Vuo 2.4.4
Loading...
Searching...
No Matches
VuoShader.cc
Go to the documentation of this file.
1
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <map>
15#include <string>
16
17extern "C"
18{
19#include "VuoShader.h"
20#include "VuoGlPool.h"
21#include "VuoTime.h"
22
23#include <OpenGL/CGLMacro.h>
24
25
27#ifdef VUO_COMPILER
29 "title" : "Graphics Shader",
30 "description" : "A graphics shader program, specifying how to render a 3D object.",
31 "keywords" : [ "glsl", "fragment", "vertex" ],
32 "version" : "1.0.0",
33 "dependencies" : [
34 "VuoColor",
35 "VuoImage",
36 "VuoInteger",
37 "VuoMesh",
38 "VuoPoint2d",
39 "VuoPoint3d",
40 "VuoPoint4d",
41 "VuoReal",
42 "VuoText",
43 "VuoTime",
44 "VuoList_VuoBoolean",
45 "VuoList_VuoInteger",
46 "VuoList_VuoImage",
47 "VuoList_VuoColor",
48 "VuoList_VuoPoint2d",
49 "VuoList_VuoPoint3d",
50 "VuoList_VuoPoint4d",
51 "VuoList_VuoReal",
52 "VuoList_VuoText",
53 "VuoGlContext",
54 "VuoGlPool",
55 "OpenGL.framework"
56 ]
57 });
58#endif
60}
61
62#include "VuoShaderIssues.hh"
63
69void VuoShader_free(void *shader)
70{
71 VuoShader s = (VuoShader)shader;
72
73 // Don't delete the GL Program or Shader objects, since @ref VuoGlShader_use and @ref VuoGlProgram_use expect them to persist.
74
75 VuoRelease(s->name);
76
77 VuoRelease(s->pointProgram.vertexSource);
78 VuoRelease(s->pointProgram.geometrySource);
79 VuoRelease(s->pointProgram.fragmentSource);
80
81 VuoRelease(s->lineProgram.vertexSource);
82 VuoRelease(s->lineProgram.geometrySource);
83 VuoRelease(s->lineProgram.fragmentSource);
84
85 VuoRelease(s->triangleProgram.vertexSource);
86 VuoRelease(s->triangleProgram.geometrySource);
87 VuoRelease(s->triangleProgram.fragmentSource);
88
89 for (unsigned int u = 0; u < s->uniformsCount; ++u)
90 {
91 VuoRelease(s->uniforms[u].name);
92
93 if (strcmp(s->uniforms[u].type, "VuoImage") == 0
94 || strncmp(s->uniforms[u].type, "VuoList_", 8) == 0
95 || strcmp(s->uniforms[u].type, "mat2") == 0
96 || strcmp(s->uniforms[u].type, "mat3") == 0
97 || strcmp(s->uniforms[u].type, "mat4") == 0)
98 // It's equivalent to release any pointer in the union.
99 VuoRelease(s->uniforms[u].value.image);
100
101 VuoRelease(s->uniforms[u].type);
102 }
103
104 free(s->uniforms);
105
106 dispatch_release((dispatch_semaphore_t)s->lock);
107
108 free(s);
109}
110
120VuoShader VuoShader_make(const char *name)
121{
122 VuoShader t = (VuoShader)calloc(1, sizeof(struct _VuoShader));
124
125 t->name = VuoText_make(name);
126 VuoRetain(t->name);
127
128 t->pointProgram.expectedOutputPrimitiveCount = 1;
129 t->lineProgram.expectedOutputPrimitiveCount = 1;
130 t->triangleProgram.expectedOutputPrimitiveCount = 1;
131
132 t->objectScale = 1;
133
134 t->isTransparent = false;
135 t->useAlphaAsCoverage = false;
136
137 t->colorBuffer = NULL;
138 t->depthBuffer = NULL;
139
140 t->activationCount = 0;
141 t->lastActivationTime = 0;
142
143 t->lock = dispatch_semaphore_create(1);
144
145 return t;
146}
147
158{
159 VuoShader t = VuoShader_make(shaderFile->name().c_str());
160
162 shaderFile->expandedVertexSource().c_str(),
163 shaderFile->expandedGeometrySource().c_str(),
164 shaderFile->expandedFragmentSource().c_str());
165
167
168 return t;
169}
170
175{
176 // Keep in sync with vuo.shader.make.image.
177 VuoColor defaultHighlightColor = VuoColor_makeWithRGBA(1,1,1,1);
178 VuoReal defaultShininess = 0.9;
179
180 return VuoShader_makeLitColorShader(color, defaultHighlightColor, defaultShininess);
181}
182
187{
188 if (!shader)
190 else
191 return shader;
192}
193
198{
199 // Keep in sync with vuo.shader.make.image.
200 VuoColor defaultHighlightColor = VuoColor_makeWithRGBA(1,1,1,1);
201 VuoReal defaultShininess = 0.9;
202
203 return VuoShader_makeLitImageShader(image, 1, defaultHighlightColor, defaultShininess);
204}
205
206
210#define DEFINE_PROGRAM() \
211 VuoSubshader *program; \
212 VuoMesh_ElementAssemblyMethod epm = VuoMesh_getExpandedPrimitiveMode(inputPrimitiveMode); \
213 if (epm == VuoMesh_IndividualTriangles) \
214 program = &shader->triangleProgram; \
215 else if (epm == VuoMesh_IndividualLines) \
216 program = &shader->lineProgram; \
217 else /* if (inputPrimitiveMode == VuoMesh_Points) */ \
218 program = &shader->pointProgram;
219
308void VuoShader_addSource(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, const char *vertexShaderSource, const char *geometryShaderSource, const char *fragmentShaderSource)
309{
310 if (!shader)
311 return;
312
313 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
314
316
317 if (!VuoText_isEmpty(vertexShaderSource))
318 program->vertexSource = VuoText_make(vertexShaderSource);
319 else
320 {
321 const char *defaultVertexShaderSource = VUOSHADER_GLSL_SOURCE(120,
322 \n#include "VuoGlslProjection.glsl"
323
324 // Inputs
325 uniform mat4 modelviewMatrix;
326 attribute vec3 position;
327 attribute vec2 textureCoordinate;
328
329 // Outputs to fragment shader
330 varying vec2 fragmentTextureCoordinate;
331
332 void main()
333 {
334 fragmentTextureCoordinate = textureCoordinate;
335
336 gl_Position = VuoGlsl_projectPosition(modelviewMatrix * vec4(position, 1.));
337 }
338 );
339 const char *defaultVertexShaderWithColorSource = VUOSHADER_GLSL_SOURCE(120,
340 \n#include "VuoGlslProjection.glsl"
341
342 // Inputs
343 uniform mat4 modelviewMatrix;
344 attribute vec3 position;
345 attribute vec2 textureCoordinate;
346 attribute vec4 vertexColor;
347 uniform bool hasVertexColors;
348
349 // Outputs to fragment shader
350 varying vec2 fragmentTextureCoordinate;
351 varying vec4 fragmentVertexColor;
352
353 void main()
354 {
355 fragmentTextureCoordinate = textureCoordinate;
356 fragmentVertexColor = hasVertexColors ? vertexColor : vec4(1.);
357
358 gl_Position = VuoGlsl_projectPosition(modelviewMatrix * vec4(position, 1.));
359 }
360 );
361
362 if (strstr(fragmentShaderSource, "fragmentVertexColor"))
363 program->vertexSource = VuoText_make(defaultVertexShaderWithColorSource);
364 else
365 program->vertexSource = VuoText_make(defaultVertexShaderSource);
366 }
367 VuoRetain(program->vertexSource);
368
369 if (!VuoText_isEmpty(geometryShaderSource))
370 {
371 program->geometrySource = VuoText_make(geometryShaderSource);
372 VuoRetain(program->geometrySource);
373 }
374
375 if (!VuoText_isEmpty(fragmentShaderSource))
376 {
377 program->fragmentSource = VuoText_make(fragmentShaderSource);
378 VuoRetain(program->fragmentSource);
379 }
380
381 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
382}
383
396void VuoShader_setExpectedOutputPrimitiveCount(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, const unsigned int expectedOutputPrimitiveCount)
397{
398 if (!shader)
399 return;
400
401 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
402
404 program->expectedOutputPrimitiveCount = expectedOutputPrimitiveCount;
405
406 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
407}
408
422void VuoShader_setMayChangeOutputPrimitiveCount(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, const bool mayChangeOutputPrimitiveCount)
423{
424 if (!shader)
425 return;
426
427 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
428
430 program->mayChangeOutputPrimitiveCount = mayChangeOutputPrimitiveCount;
431
432 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
433}
434
441void VuoShader_setTransparent(VuoShader shader, const bool isTransparent)
442{
443 if (!shader)
444 return;
445
446 shader->isTransparent = isTransparent;
447}
448
458{
459 if (!shader)
460 return 0;
461
462 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
463
465 unsigned int expectedOutputPrimitiveCount = program->expectedOutputPrimitiveCount;
466
467 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
468
469 return expectedOutputPrimitiveCount;
470}
471
481{
482 if (!shader)
483 return 0;
484
485 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
486
488 unsigned int mayChangeOutputPrimitiveCount = program->mayChangeOutputPrimitiveCount;
489
490 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
491
492 return mayChangeOutputPrimitiveCount;
493}
494
501{
502 if (!shader)
503 return false;
504
505 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
506
507 if (shader->pointProgram.glFragmentShaderName
508 || shader->lineProgram.glFragmentShaderName
509 || shader->triangleProgram.glFragmentShaderName)
510 {
511 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
512 return false;
513 }
514
515 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
516 return true;
517}
518
528static void VuoShader_replaceImageMacro(VuoShader shader, string &source, map<string, GLint> &imagesToDeclare, string beforeFunction, bool isThis, string afterFunction2D, string afterFunctionRect, VuoShaderFile::Stage stage, VuoShaderIssues *outIssues)
529{
530 string::size_type beforeFunctionLength = beforeFunction.length();
531 string::size_type pos = 0;
532 while ( (pos = source.find(beforeFunction, pos)) != string::npos )
533 {
534 size_t offset = pos + beforeFunctionLength;
535
536 while (isspace(source[offset]))
537 ++offset;
538
539 if (source[offset] != '(')
540 {
542 if (outIssues)
543 outIssues->addIssue(stage, VuoShaderIssues::NoLine, "Syntax error in " + beforeFunction + ": expected '('.");
544 else
545 VUserLog("Syntax error in %s: expected '('.", beforeFunction.c_str());
546 pos += beforeFunctionLength;
547 continue;
548 }
549 ++offset;
550
551 size_t samplerStart = offset;
552 char samplerEndChar = isThis ? ')' : ',';
553 while (source[offset] != samplerEndChar)
554 ++offset;
555 size_t samplerEnd = offset;
556
557 string sampler = source.substr(samplerStart, samplerEnd - samplerStart);
558
559 if (isThis)
560 source.insert(samplerEnd, ", isf_FragNormCoord");
561 else
562 source.insert(samplerEnd,
563 ", _" + sampler + "_imgRect"
564 + ", _" + sampler + "_imgSize"
565 + ", _" + sampler + "_flip");
566
567 string replacement = afterFunction2D;
568 GLint target;
569 for (int i = 0; i < shader->uniformsCount; ++i)
570 if (strcmp(shader->uniforms[i].type, "VuoImage") == 0
571 && shader->uniforms[i].name == sampler
572 && shader->uniforms[i].value.image)
573 {
574 target = shader->uniforms[i].value.image->glTextureTarget;
575 if (shader->uniforms[i].value.image->glTextureTarget == GL_TEXTURE_RECTANGLE_EXT)
576 replacement = afterFunctionRect;
577 shader->uniforms[i].compiledTextureTarget = target;
578 break;
579 }
580
581 source.replace(pos, beforeFunctionLength, replacement);
582
583 imagesToDeclare.insert(std::make_pair(sampler, target));
584 }
585}
586
590static void VuoShader_replaceSizeMacro(VuoShader shader, string &source, string before, string after)
591{
592 string prefix(before + "(");
593 string::size_type prefixLength = prefix.length();
594 string::size_type pos = 0;
595 while ( (pos = source.find(prefix, pos)) != string::npos )
596 {
597 size_t offset = pos + prefixLength;
598 size_t samplerStart = offset;
599 while (source[offset] != ')')
600 ++offset;
601 size_t samplerEnd = offset;
602 string sampler = source.substr(samplerStart, samplerEnd - samplerStart);
603 source.replace(pos, samplerEnd - samplerStart + prefixLength + 1, "_" + sampler + "_" + after);
604 }
605}
606
611static void VuoShader_replaceImageMacros(VuoShader shader, string &source, VuoShaderFile::Stage stage, VuoShaderIssues *outIssues)
612{
613 map<string, GLint> imagesToDeclare;
614 VuoShader_replaceImageMacro(shader, source, imagesToDeclare, "IMG_PIXEL", false, "VVSAMPLER_2DBYPIXEL", "VVSAMPLER_2DRECTBYPIXEL", stage, outIssues);
615 VuoShader_replaceImageMacro(shader, source, imagesToDeclare, "IMG_NORM_PIXEL", false, "VVSAMPLER_2DBYNORM", "VVSAMPLER_2DRECTBYNORM", stage, outIssues);
616 VuoShader_replaceImageMacro(shader, source, imagesToDeclare, "IMG_THIS_PIXEL", true, "texture2D", "texture2DRect", stage, outIssues);
617 VuoShader_replaceImageMacro(shader, source, imagesToDeclare, "IMG_THIS_NORM_PIXEL", true, "texture2D", "texture2DRect", stage, outIssues);
618
619 VuoShader_replaceSizeMacro(shader, source, "IMG_SIZE", "imgSize");
620 VuoShader_replaceSizeMacro(shader, source, "LIST_LENGTH", "length");
621
622 // Fill in image declaration placeholders.
623 for (map<string, GLint>::iterator it = imagesToDeclare.begin(); it != imagesToDeclare.end(); ++it)
624 {
625 string samplerType;
626 if (it->second == GL_TEXTURE_RECTANGLE_EXT)
627 samplerType = "sampler2DRect";
628 else // if (target == GL_TEXTURE_2D)
629 samplerType = "sampler2D";
630
631 string placeholder = "//uniform VuoImage " + it->first;
632 string replacement = "uniform " + samplerType + " " + it->first;
633
634 string::size_type pos = source.find(placeholder);
635 if (pos == string::npos)
636 {
637 if (outIssues)
638 outIssues->addIssue(stage, VuoShaderIssues::NoLine, "Unknown image \"" + it->first + "\".");
639 else
640 VUserLog("Unknown image \"%s\".", it->first.c_str());
641 continue;
642 }
643 source.replace(pos, placeholder.length(), replacement);
644 }
645}
646
653static bool VuoShader_ensureUploaded(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext, VuoShaderIssues *outIssues)
654{
655 if (!shader)
656 return false;
657
659
660 // Is the shader already compiled/linked/uploaded?
661 if (program->program.programName)
662 {
663 // If the shader is already compiled/linked/uploaded,
664 // are its image targets up-to-date with the current image uniforms?
665
666 bool upToDate = true;
667 for (unsigned int i = 0; i < shader->uniformsCount; ++i)
668 if (strcmp(shader->uniforms[i].type, "VuoImage") == 0)
669 if (shader->uniforms[i].value.image
670 && shader->uniforms[i].compiledTextureTarget
671 && shader->uniforms[i].value.image->glTextureTarget != shader->uniforms[i].compiledTextureTarget)
672 {
673 upToDate = false;
674 break;
675 }
676
677 if (upToDate)
678 return true;
679 }
680
681
682 // Is there source code available?
683 // By this point, if no vertex shader was provided, the default vertex shader should already have been filled in.
684 if (!program->vertexSource)
685 return false;
686
687 // If we previously attempted to compile this subshader and it failed, don't try again.
688 if (program->compilationAttempted)
689 return false;
690 program->compilationAttempted = true;
691
692 string vertexSource = program->vertexSource;
693 VuoShader_replaceImageMacros(shader, vertexSource, VuoShaderFile::Vertex, outIssues);
694 program->glVertexShaderName = VuoGlShader_use(glContext, GL_VERTEX_SHADER, vertexSource.c_str(), static_cast<void *>(outIssues));
695 if (!program->glVertexShaderName)
696 return false;
697
698 if (!VuoText_isEmpty(program->geometrySource))
699 {
700 string geometrySource = program->geometrySource;
701 VuoShader_replaceImageMacros(shader, geometrySource, VuoShaderFile::Geometry, outIssues);
702 program->glGeometryShaderName = VuoGlShader_use(glContext, GL_GEOMETRY_SHADER_EXT, geometrySource.c_str(), static_cast<void *>(outIssues));
703 if (!program->glGeometryShaderName)
704 return false;
705 }
706
707 if (!VuoText_isEmpty(program->fragmentSource))
708 {
709 string fragmentSource = program->fragmentSource;
710 VuoShader_replaceImageMacros(shader, fragmentSource, VuoShaderFile::Fragment, outIssues);
711 program->glFragmentShaderName = VuoGlShader_use(glContext, GL_FRAGMENT_SHADER, fragmentSource.c_str(), static_cast<void *>(outIssues));
712 if (!program->glFragmentShaderName)
713 return false;
714 }
715
716 program->program = VuoGlProgram_use(glContext, shader->name, program->glVertexShaderName, program->glGeometryShaderName, program->glFragmentShaderName, inputPrimitiveMode, program->expectedOutputPrimitiveCount, static_cast<void *>(outIssues));
717
718 return program->program.programName > 0 ? true : false;
719}
720
732bool VuoShader_upload(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext, void *outIssues)
733{
734 if (!shader)
735 return false;
736
737 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
738 if (!VuoShader_ensureUploaded(shader, inputPrimitiveMode, glContext, static_cast<VuoShaderIssues *>(outIssues)))
739 {
740 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
741 return false;
742 }
743
744 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
745 return true;
746}
747
764bool VuoShader_getAttributeLocations(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext, int *positionLocation, int *normalLocation, int *textureCoordinateLocation, int *colorLocation)
765{
766 if (!shader)
767 return false;
768
769 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
770 if (!VuoShader_ensureUploaded(shader, inputPrimitiveMode, glContext, NULL))
771 {
772 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
773 return false;
774 }
775
777
778 {
779 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
780
782 if (positionLocation)
783 *positionLocation = glGetAttribLocation(program->program.programName, "position");
784 if (normalLocation)
785 *normalLocation = glGetAttribLocation(program->program.programName, "normal");
786 if (textureCoordinateLocation)
787 *textureCoordinateLocation = glGetAttribLocation(program->program.programName, "textureCoordinate");
788 if (colorLocation)
789 *colorLocation = glGetAttribLocation(program->program.programName, "vertexColor");
790 }
791
792 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
793 return true;
794}
795
804void VuoShader_initPerlinTexture(CGLContextObj cgl_ctx)
805{
806 char *pixels;
807 int i,j;
808
809 int perm[256]= {151,160,137,91,90,15,
810 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
811 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
812 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
813 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
814 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
815 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
816 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
817 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
818 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
819 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
820 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
821 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};
822
823 int grad3[16][3] = {{0,1, 1},{ 0, 1,-1},{ 0,-1,1},{ 0,-1,-1},
824 {1,0, 1},{ 1, 0,-1},{-1, 0,1},{-1, 0,-1},
825 {1,1, 0},{ 1,-1, 0},{-1, 1,0},{-1,-1, 0}, // 12 cube edges
826 {1,0,-1},{-1, 0,-1},{ 0,-1,1},{ 0, 1, 1}}; // 4 more to make 16
827
828 VuoShader_perlinTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_NoAllocation, GL_TEXTURE_2D, GL_RGBA, 256, 256, GL_BGRA, NULL);
829 glBindTexture(GL_TEXTURE_2D, VuoShader_perlinTexture);
830
831 pixels = (char*)malloc( 256*256*4 );
832 for(i = 0; i<256; i++)
833 for(j = 0; j<256; j++) {
834 int offset = (i*256+j)*4;
835 char value = perm[(j+perm[i]) & 0xFF];
836 pixels[offset+2] = grad3[value & 0x0F][0] * 64 + 64; // Gradient x
837 pixels[offset+1] = grad3[value & 0x0F][1] * 64 + 64; // Gradient y
838 pixels[offset+0] = grad3[value & 0x0F][2] * 64 + 64; // Gradient z
839 pixels[offset+3] = value; // Permuted index
840 }
841
842 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels );
843 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
844 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
845 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
846 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
847
848 free(pixels);
849}
850
858void VuoShader_initGradTexture(CGLContextObj cgl_ctx)
859{
860 char *pixels;
861 int i,j;
862
863 int perm[256]= {151,160,137,91,90,15,
864 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
865 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
866 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
867 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
868 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
869 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
870 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
871 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
872 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
873 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
874 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
875 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};
876
877 int grad4[32][4]= {{ 0, 1,1,1}, { 0, 1, 1,-1}, { 0, 1,-1,1}, { 0, 1,-1,-1}, // 32 tesseract edges
878 { 0,-1,1,1}, { 0,-1, 1,-1}, { 0,-1,-1,1}, { 0,-1,-1,-1},
879 { 1, 0,1,1}, { 1, 0, 1,-1}, { 1, 0,-1,1}, { 1, 0,-1,-1},
880 {-1, 0,1,1}, {-1, 0, 1,-1}, {-1, 0,-1,1}, {-1, 0,-1,-1},
881 { 1, 1,0,1}, { 1, 1, 0,-1}, { 1,-1, 0,1}, { 1,-1, 0,-1},
882 {-1, 1,0,1}, {-1, 1, 0,-1}, {-1,-1, 0,1}, {-1,-1, 0,-1},
883 { 1, 1,1,0}, { 1, 1,-1, 0}, { 1,-1, 1,0}, { 1,-1,-1, 0},
884 {-1, 1,1,0}, {-1, 1,-1, 0}, {-1,-1, 1,0}, {-1,-1,-1, 0}};
885
886 VuoShader_gradTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_NoAllocation, GL_TEXTURE_2D, GL_RGBA, 256, 256, GL_BGRA, NULL);
887 glBindTexture(GL_TEXTURE_2D, VuoShader_gradTexture);
888
889 pixels = (char*)malloc( 256*256*4 );
890 for(i = 0; i<256; i++)
891 for(j = 0; j<256; j++) {
892 int offset = (i*256+j)*4;
893 char value = perm[(j+perm[i]) & 0xFF];
894 pixels[offset+2] = grad4[value & 0x1F][0] * 64 + 64; // Gradient x
895 pixels[offset+1] = grad4[value & 0x1F][1] * 64 + 64; // Gradient y
896 pixels[offset+0] = grad4[value & 0x1F][2] * 64 + 64; // Gradient z
897 pixels[offset+3] = grad4[value & 0x1F][3] * 64 + 64; // Gradient w
898 }
899
900 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels );
901 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
902 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
903 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
904 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
905
906 free(pixels);
907}
908
909typedef std::map<VuoGlContext, GLuint> VuoShaderContextType;
911static dispatch_semaphore_t VuoShaderContext_semaphore;
915static void __attribute__((constructor)) VuoShaderContext_init(void)
916{
917 VuoShaderContext_semaphore = dispatch_semaphore_create(1);
918}
919
936bool VuoShader_activate(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext, VuoGlProgram *outputProgram)
937{
938 if (!shader)
939 return false;
940
941 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
942 if (!VuoShader_ensureUploaded(shader, inputPrimitiveMode, glContext, NULL))
943 {
944 VUserLog("Error: '%s' doesn't have a program for inputPrimitiveMode '%s'.", shader->name, VuoMesh_cStringForElementAssemblyMethod(inputPrimitiveMode));
945 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
946 return false;
947 }
948
950// VLog("Rendering %s with '%s'", VuoMesh_cStringForElementAssemblyMethod(epm), shader->name);
951
952 {
953 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
954
955 bool alreadyActiveOnThisContext = false;
956 dispatch_semaphore_wait(VuoShaderContext_semaphore, DISPATCH_TIME_FOREVER);
957 {
958 VuoShaderContextType::iterator i = VuoShaderContextMap.find(glContext);
959 if (i != VuoShaderContextMap.end())
960 {
961 if (i->second == program->program.programName)
962 alreadyActiveOnThisContext = true;
963 else
964 i->second = program->program.programName;
965 }
966 else
967 VuoShaderContextMap[glContext] = program->program.programName;
968 }
969 dispatch_semaphore_signal(VuoShaderContext_semaphore);
970
971 if (!alreadyActiveOnThisContext)
972 {
973 if (VuoIsDebugEnabled())
974 {
975 glValidateProgram(program->program.programName);
976
977 int infologLength = 0;
978 glGetProgramiv(program->program.programName, GL_INFO_LOG_LENGTH, &infologLength);
979 if (infologLength > 0)
980 {
981 char *infoLog = (char *)malloc(infologLength);
982 int charsWritten = 0;
983 glGetProgramInfoLog(program->program.programName, infologLength, &charsWritten, infoLog);
984 VUserLog("%s", infoLog);
985 free(infoLog);
986 }
987 }
988
989 glUseProgram(program->program.programName);
990 }
991
992 GLuint textureUnit = 0;
993 bool explicitColorBuffer = false;
994 for (unsigned int i = 0; i < shader->uniformsCount; ++i)
995 {
996 VuoShaderUniform uniform = shader->uniforms[i];
997
998
999 if (strncmp(uniform.type, "VuoList_", 8) == 0)
1000 {
1001 GLint location = VuoGlProgram_getUniformLocation(program->program, (string(uniform.name) + "[0]").c_str());
1002 if (location == -1)
1003 {
1004 VDebugLog("Warning: Shader '%s' has a value for '%s', but the linked program has no uniform by that name.", shader->name, uniform.name);
1005 continue;
1006 }
1007
1008 size_t itemCount;
1009 if (strcmp(uniform.type, "VuoList_VuoBoolean") == 0)
1010 {
1011 itemCount = VuoListGetCount_VuoBoolean(uniform.value.booleans);
1012 VuoBoolean *itemData = VuoListGetData_VuoBoolean(uniform.value.booleans);
1013 GLint *itemDataGL = (GLint *)malloc(sizeof(GLint) * itemCount);
1014 for (size_t i = 0; i < itemCount; ++i)
1015 itemDataGL[i] = itemData[i];
1016 glUniform1iv(location, itemCount, itemDataGL);
1017 }
1018 else if (strcmp(uniform.type, "VuoList_VuoInteger") == 0)
1019 {
1020 itemCount = VuoListGetCount_VuoInteger(uniform.value.integers);
1021 VuoInteger *itemData = VuoListGetData_VuoInteger(uniform.value.integers);
1022 GLint *itemDataGL = (GLint *)malloc(sizeof(GLint) * itemCount);
1023 for (size_t i = 0; i < itemCount; ++i)
1024 itemDataGL[i] = itemData[i];
1025 glUniform1iv(location, itemCount, itemDataGL);
1026 }
1027 else if (strcmp(uniform.type, "VuoList_VuoReal") == 0)
1028 {
1029 itemCount = VuoListGetCount_VuoReal(uniform.value.reals);
1030 VuoReal *itemData = VuoListGetData_VuoReal(uniform.value.reals);
1031 GLfloat *itemDataGL = (GLfloat *)malloc(sizeof(GLfloat) * itemCount);
1032 for (size_t i = 0; i < itemCount; ++i)
1033 itemDataGL[i] = itemData[i];
1034 glUniform1fv(location, itemCount, itemDataGL);
1035 }
1036 else if (strcmp(uniform.type, "VuoList_VuoPoint2d") == 0)
1037 {
1038 itemCount = VuoListGetCount_VuoPoint2d(uniform.value.point2ds);
1039 VuoPoint2d *itemData = VuoListGetData_VuoPoint2d(uniform.value.point2ds);
1040 GLfloat *itemDataGL = (GLfloat *)malloc(sizeof(GLfloat) * itemCount * 2);
1041 for (size_t i = 0; i < itemCount; ++i)
1042 {
1043 itemDataGL[i*2 + 0] = itemData[i].x;
1044 itemDataGL[i*2 + 1] = itemData[i].y;
1045 }
1046 glUniform2fv(location, itemCount, itemDataGL);
1047 }
1048 else if (strcmp(uniform.type, "VuoList_VuoPoint3d") == 0)
1049 {
1050 itemCount = VuoListGetCount_VuoPoint3d(uniform.value.point3ds);
1051 VuoPoint3d *itemData = VuoListGetData_VuoPoint3d(uniform.value.point3ds);
1052 GLfloat *itemDataGL = (GLfloat *)malloc(sizeof(GLfloat) * itemCount * 3);
1053 for (size_t i = 0; i < itemCount; ++i)
1054 {
1055 itemDataGL[i*3 + 0] = itemData[i].x;
1056 itemDataGL[i*3 + 1] = itemData[i].y;
1057 itemDataGL[i*3 + 2] = itemData[i].z;
1058 }
1059 glUniform3fv(location, itemCount, itemDataGL);
1060 }
1061 else if (strcmp(uniform.type, "VuoList_VuoPoint4d") == 0)
1062 {
1063 itemCount = VuoListGetCount_VuoPoint4d(uniform.value.point4ds);
1064 VuoPoint4d *itemData = VuoListGetData_VuoPoint4d(uniform.value.point4ds);
1065 GLfloat *itemDataGL = (GLfloat *)malloc(sizeof(GLfloat) * itemCount * 4);
1066 for (size_t i = 0; i < itemCount; ++i)
1067 {
1068 itemDataGL[i*4 + 0] = itemData[i].x;
1069 itemDataGL[i*4 + 1] = itemData[i].y;
1070 itemDataGL[i*4 + 2] = itemData[i].z;
1071 itemDataGL[i*4 + 3] = itemData[i].w;
1072 }
1073 glUniform4fv(location, itemCount, itemDataGL);
1074 }
1075 else if (strcmp(uniform.type, "VuoList_VuoColor") == 0)
1076 {
1077 itemCount = VuoListGetCount_VuoColor(uniform.value.colors);
1078 VuoColor *itemData = VuoListGetData_VuoColor(uniform.value.colors);
1079 GLfloat *itemDataGL = (GLfloat *)malloc(sizeof(GLfloat) * itemCount * 4);
1080 for (size_t i = 0; i < itemCount; ++i)
1081 {
1082 itemDataGL[i*4 + 0] = itemData[i].r;
1083 itemDataGL[i*4 + 1] = itemData[i].g;
1084 itemDataGL[i*4 + 2] = itemData[i].b;
1085 itemDataGL[i*4 + 3] = itemData[i].a;
1086 }
1087 glUniform4fv(location, itemCount, itemDataGL);
1088 }
1089 else
1090 VDebugLog("Warning: Shader '%s' has unknown type '%s' for uniform '%s'.", shader->name, uniform.type, uniform.name);
1091
1092 GLint listLengthUniform = VuoGlProgram_getUniformLocation(program->program, (string("_") + uniform.name + "_length").c_str());
1093 if (listLengthUniform != -1)
1094 glUniform1i(listLengthUniform, itemCount);
1095
1096 continue;
1097 }
1098
1099
1100 // Populate the ISF image-related uniforms, even if the image itself isn't used.
1101 if (strcmp(uniform.type, "VuoImage") == 0 && uniform.value.image)
1102 {
1103 VuoImage image = uniform.value.image;
1104
1106 GLint imgRectUniform = VuoGlProgram_getUniformLocation(program->program, (string("_") + uniform.name + "_imgRect").c_str());
1107 if (imgRectUniform != -1)
1108 {
1109 if (image->glTextureTarget == GL_TEXTURE_2D)
1110 glUniform4f(imgRectUniform, 0, 0, 1, 1);
1111 else
1112 glUniform4f(imgRectUniform, 0, 0, image->pixelsWide, image->pixelsHigh);
1113 }
1114
1115 GLint imgSizeUniform = VuoGlProgram_getUniformLocation(program->program, (string("_") + uniform.name + "_imgSize").c_str());
1116 if (imgSizeUniform != -1)
1117 glUniform2f(imgSizeUniform, image->pixelsWide, image->pixelsHigh);
1118
1120 GLint flipUniform = VuoGlProgram_getUniformLocation(program->program, (string("_") + uniform.name + "_flip").c_str());
1121 if (flipUniform != -1)
1122 glUniform1i(flipUniform, 0);
1123 }
1124
1125 GLint location = VuoGlProgram_getUniformLocation(program->program, uniform.name);
1126 if (location == -1)
1127 {
1128 VDebugLog("Warning: Shader '%s' has a value for '%s', but the linked program has no uniform by that name.", shader->name, uniform.name);
1129 continue;
1130 }
1131
1132 if (strcmp(uniform.type, "VuoImage") == 0)
1133 {
1134 VuoImage image = uniform.value.image;
1135
1136 glActiveTexture(GL_TEXTURE0 + textureUnit);
1137 if (image)
1138 glBindTexture(image->glTextureTarget, image->glTextureName);
1139 else
1140 {
1141 // When passing a null image to a shader,
1142 // allocate a texture unit for it anyway and unbind all textures from it,
1143 // so it samples the void instead of sampling
1144 // whatever happens to be hanging out on on the texture unit associated with the sampler.
1145 // https://b33p.net/kosada/node/8976
1146 glBindTexture(GL_TEXTURE_2D, 0);
1147 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1148 }
1149 glUniform1i(location, textureUnit);
1150 ++textureUnit;
1151
1152 if (strcmp(uniform.name, "colorBuffer") == 0)
1153 explicitColorBuffer = true;
1154 }
1155 else if (strcmp(uniform.type, "VuoBoolean") == 0)
1156 glUniform1i(location, uniform.value.boolean);
1157 else if (strcmp(uniform.type, "VuoInteger") == 0)
1158 glUniform1i(location, uniform.value.integer);
1159 else if (strcmp(uniform.type, "VuoReal") == 0)
1160 glUniform1f(location, uniform.value.real);
1161 else if (strcmp(uniform.type, "VuoPoint2d") == 0)
1162 glUniform2f(location, uniform.value.point2d.x, uniform.value.point2d.y);
1163 else if (strcmp(uniform.type, "VuoPoint3d") == 0)
1164 glUniform3f(location, uniform.value.point3d.x, uniform.value.point3d.y, uniform.value.point3d.z);
1165 else if (strcmp(uniform.type, "VuoPoint4d") == 0)
1166 glUniform4f(location, uniform.value.point4d.x, uniform.value.point4d.y, uniform.value.point4d.z, uniform.value.point4d.w);
1167 else if (strcmp(uniform.type, "VuoColor") == 0)
1168 glUniform4f(location, uniform.value.color.r, uniform.value.color.g, uniform.value.color.b, uniform.value.color.a);
1169 else if (strcmp(uniform.type, "mat2") == 0)
1170 glUniformMatrix2fv(location, 1, GL_FALSE, uniform.value.mat2);
1171 else if (strcmp(uniform.type, "mat3") == 0)
1172 glUniformMatrix3fv(location, 1, GL_FALSE, uniform.value.mat3);
1173 else if (strcmp(uniform.type, "mat4") == 0)
1174 glUniformMatrix4fv(location, 1, GL_FALSE, uniform.value.mat4);
1175 else
1176 VUserLog("Error: Unknown type %s for '%s'", uniform.type, uniform.name);
1177 }
1178
1179
1180 GLint perlinTextureUniform = VuoGlProgram_getUniformLocation(program->program, "perlinTexture");
1181 if (perlinTextureUniform != -1)
1182 {
1183 glActiveTexture(GL_TEXTURE0 + textureUnit);
1184
1185 static dispatch_once_t initPerlinTexture = 0;
1186 dispatch_once(&initPerlinTexture, ^{
1188 });
1189
1190 glBindTexture(GL_TEXTURE_2D, VuoShader_perlinTexture);
1191 glUniform1i(perlinTextureUniform, textureUnit);
1192 ++textureUnit;
1193 }
1194
1195 GLint gradTextureUniform = VuoGlProgram_getUniformLocation(program->program, "gradTexture");
1196 if (gradTextureUniform != -1)
1197 {
1198 glActiveTexture(GL_TEXTURE0 + textureUnit);
1199
1200 static dispatch_once_t initGradTexture = 0;
1201 dispatch_once(&initGradTexture, ^{
1203 });
1204
1205 glBindTexture(GL_TEXTURE_2D, VuoShader_gradTexture);
1206 glUniform1i(gradTextureUniform, textureUnit);
1207 ++textureUnit;
1208 }
1209
1210
1211 GLint colorBufferUniform = VuoGlProgram_getUniformLocation(program->program, "colorBuffer");
1212 GLint depthBufferUniform = VuoGlProgram_getUniformLocation(program->program, "depthBuffer");
1213
1214 GLint width, height;
1215 if ((!explicitColorBuffer && colorBufferUniform != -1) || depthBufferUniform != -1)
1216 {
1217 GLint viewport[4];
1218 glGetIntegerv(GL_VIEWPORT, viewport);
1219 width = viewport[2];
1220 height = viewport[3];
1221 }
1222
1223 if (!explicitColorBuffer && colorBufferUniform != -1)
1224 {
1225 // Capture the context's current color image and feed it to the shader.
1226 glActiveTexture(GL_TEXTURE0 + textureUnit);
1227
1228 GLuint colorBufferTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_RGBA, width, height, GL_BGRA, NULL);
1229 glBindTexture(GL_TEXTURE_2D, colorBufferTexture);
1230
1231 GLint multisampling, multisampledFramebuffer;
1232 glGetIntegerv(GL_SAMPLE_BUFFERS, &multisampling);
1233 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &multisampledFramebuffer);
1234 if (multisampling && multisampledFramebuffer)
1235 {
1236 GLuint resolvedFramebuffer;
1237 glGenFramebuffers(1, &resolvedFramebuffer);
1238 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolvedFramebuffer);
1239
1240 {
1241 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTexture, 0);
1242
1243 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, multisampledFramebuffer);
1244 glReadBuffer(GL_COLOR_ATTACHMENT0);
1245 glDrawBuffer(GL_COLOR_ATTACHMENT0);
1246 glBlitFramebuffer(0, 0, width, height,
1247 0, 0, width, height,
1248 GL_COLOR_BUFFER_BIT,
1249 GL_NEAREST);
1250
1251 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
1252 }
1253
1254 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, multisampledFramebuffer);
1255 glDeleteFramebuffers(1, &resolvedFramebuffer);
1256 }
1257 else
1258 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
1259
1260 shader->colorBuffer = VuoImage_make(colorBufferTexture, GL_RGBA, width, height);
1261 VuoRetain(shader->colorBuffer);
1262
1263 glUniform1i(colorBufferUniform, textureUnit);
1264 ++textureUnit;
1265 }
1266
1267 if (depthBufferUniform != -1)
1268 {
1269 // Capture the context's current depth image and feed it to the shader.
1270 glActiveTexture(GL_TEXTURE0 + textureUnit);
1271
1272 GLuint depthBufferTexture = VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_DEPTH_COMPONENT16, width, height, GL_DEPTH_COMPONENT, NULL);
1273 glBindTexture(GL_TEXTURE_2D, depthBufferTexture);
1274
1276 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 0, 0, width, height, 0);
1277
1278 shader->depthBuffer = VuoImage_make(depthBufferTexture, GL_DEPTH_COMPONENT16, width, height);
1279 VuoRetain(shader->depthBuffer);
1280
1281 glUniform1i(depthBufferUniform, textureUnit);
1282 ++textureUnit;
1283 }
1284
1285 // ISF
1286 {
1287 // RENDERSIZE is provided by a #define in VuoShaderFile::insertPreamble.
1288 // TIME is provided by an input port.
1289
1290 double now = VuoLogGetElapsedTime();
1291 GLint timedeltaUniform = VuoGlProgram_getUniformLocation(program->program, "TIMEDELTA");
1292 if (timedeltaUniform != -1)
1293 glUniform1f(timedeltaUniform, now - shader->lastActivationTime);
1294 shader->lastActivationTime = now;
1295
1296 GLint dateUniform = VuoGlProgram_getUniformLocation(program->program, "DATE");
1297 if (dateUniform != -1)
1298 {
1299 VuoInteger year;
1300 VuoInteger month;
1301 VuoInteger dayOfMonth;
1302 VuoInteger hour;
1303 VuoInteger minute;
1304 VuoReal second;
1305 if (VuoTime_getComponents(VuoTime_getCurrent(), &year, NULL, &month, &dayOfMonth, NULL, NULL, &hour, &minute, &second))
1306 glUniform4f(dateUniform, (float)year, (float)month, (float)dayOfMonth, (float)(second + (minute + (hour * 60)) * 60));
1307 }
1308
1309 GLint frameindexUniform = VuoGlProgram_getUniformLocation(program->program, "FRAMEINDEX");
1310 if (frameindexUniform != -1)
1311 glUniform1i(frameindexUniform, shader->activationCount);
1312 ++shader->activationCount;
1313 }
1314 }
1315
1316 // dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock); --- hold the lock while the shader is active
1317 *outputProgram = program->program;
1318 return true;
1319}
1320
1333void VuoShader_deactivate(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext)
1334{
1335 if (!shader)
1336 return;
1337
1338// dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER); --- the lock is held while the shader is active
1339 if (!VuoShader_ensureUploaded(shader, inputPrimitiveMode, glContext, NULL))
1340 {
1341// dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
1342 return;
1343 }
1344
1346
1347 {
1348 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
1349
1350 GLuint textureUnit = 0;
1351 for (unsigned int i = 0; i < shader->uniformsCount; ++i)
1352 {
1353 GLint location = VuoGlProgram_getUniformLocation(program->program, shader->uniforms[i].name);
1354 if (location == -1)
1355 continue;
1356
1357 if (strcmp(shader->uniforms[i].type, "VuoImage") == 0)
1358 {
1359 VuoImage image = shader->uniforms[i].value.image;
1360 if (!image)
1361 continue;
1362
1363 glActiveTexture(GL_TEXTURE0 + textureUnit);
1364 glBindTexture(image->glTextureTarget, 0);
1365 ++textureUnit;
1366 }
1367 }
1368
1369 if (VuoGlProgram_getUniformLocation(program->program, "perlinTexture") != -1)
1370 {
1371 glActiveTexture(GL_TEXTURE0 + textureUnit);
1372 glBindTexture(GL_TEXTURE_2D, 0);
1373 ++textureUnit;
1374 }
1375
1376 if (VuoGlProgram_getUniformLocation(program->program, "gradTexture") != -1)
1377 {
1378 glActiveTexture(GL_TEXTURE0 + textureUnit);
1379 glBindTexture(GL_TEXTURE_2D, 0);
1380 ++textureUnit;
1381 }
1382
1383 if (shader->colorBuffer)
1384 {
1385 glActiveTexture(GL_TEXTURE0 + textureUnit);
1386 glBindTexture(GL_TEXTURE_2D, 0);
1387 ++textureUnit;
1388 VuoRelease(shader->colorBuffer);
1389 shader->colorBuffer = NULL;
1390 }
1391
1392 if (shader->depthBuffer)
1393 {
1394 glActiveTexture(GL_TEXTURE0 + textureUnit);
1395 glBindTexture(GL_TEXTURE_2D, 0);
1396 ++textureUnit;
1397 VuoRelease(shader->depthBuffer);
1398 shader->depthBuffer = NULL;
1399 }
1400
1401 // Instead of deactivating the shader, keep it active in hope that we can reuse it during this context's next draw call.
1402// glUseProgram(0);
1403 }
1404
1405 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
1406 return;
1407}
1408
1415{
1416 dispatch_semaphore_wait(VuoShaderContext_semaphore, DISPATCH_TIME_FOREVER);
1417 VuoShaderContextType::iterator i = VuoShaderContextMap.find(glContext);
1418 if (i != VuoShaderContextMap.end())
1419 {
1420 i->second = 0;
1421 CGLContextObj cgl_ctx = (CGLContextObj)glContext;
1422 glUseProgram(0);
1423 }
1424 dispatch_semaphore_signal(VuoShaderContext_semaphore);
1425}
1426
1433{
1434 if (!js)
1435 return NULL;
1436
1437 json_object *o = NULL;
1438
1439 if (json_object_object_get_ex(js, "pointer", &o))
1440 {
1441 VuoShader shader = (VuoShader)json_object_get_int64(o);
1442 json_object_set_userdata(js, nullptr, [](json_object *js, void *shader) { VuoRelease(shader); });
1443 return shader;
1444 }
1445
1447}
1448
1456json_object * VuoShader_getJson(const VuoShader value)
1457{
1458 if (!value)
1459 return NULL;
1460
1461 VuoRetain(value);
1462
1463 json_object *js = json_object_new_object();
1464 json_object_object_add(js, "pointer", json_object_new_int64((int64_t)value));
1465 return js;
1466}
1467
1474{
1475 return VuoShader_getJson(value);
1476}
1477
1484{
1485 if (!value)
1486 return strdup("No shader");
1487
1488 return strdup(value->name);
1489}
1490
1503VuoPoint2d VuoShader_samplerCoordinatesFromVuoCoordinates(VuoPoint2d vuoCoordinates, VuoImage image)
1504{
1505 VuoPoint2d samplerCoordinates;
1506 samplerCoordinates.x = VuoShader_samplerSizeFromVuoSize(vuoCoordinates.x) + 0.5;
1507 samplerCoordinates.y = VuoShader_samplerSizeFromVuoSize(vuoCoordinates.y)/((double)image->pixelsHigh/image->pixelsWide) + 0.5;
1508 return samplerCoordinates;
1509}
1510
1517{
1518 return vuoSize/2.;
1519}
1520
1532{
1533 c.x *= imageWidth;
1534 c.y *= imageHeight;
1535 return c;
1536}
1537
1554{
1555 if (!shader)
1556 return true;
1557
1558 if (shader->isTransparent || shader->useAlphaAsCoverage)
1559 {
1560// VLog("Shader %p ('%s') isTransparent=%d useAlphaAsCoverage=%d", shader, shader->name, shader->isTransparent, shader->useAlphaAsCoverage);
1561 return false;
1562 }
1563
1564 bool opaque = true;
1565
1566 dispatch_semaphore_wait((dispatch_semaphore_t)shader->lock, DISPATCH_TIME_FOREVER);
1567
1568 for (int i = 0; i < shader->uniformsCount; ++i)
1569 {
1570 if (strcmp(shader->uniforms[i].type, "VuoColor") == 0
1571 && !VuoColor_isOpaque(shader->uniforms[i].value.color))
1572 {
1573// VLog("Shader %p ('%s') has a transparent color: %s", shader, shader->name, VuoColor_getShortSummary(shader->uniforms[i].value.color));
1574 opaque = false;
1575 goto done;
1576 }
1577
1578 if (strcmp(shader->uniforms[i].type, "VuoList_VuoColor") == 0
1579 && !VuoColor_areAllOpaque(shader->uniforms[i].value.colors))
1580 {
1581// VLog("Shader %p ('%s') has a transparent color", shader, shader->name);
1582 opaque = false;
1583 goto done;
1584 }
1585
1586 if (strcmp(shader->uniforms[i].type, "VuoReal") == 0
1587 && strcmp(shader->uniforms[i].name, "alpha") == 0
1588 && shader->uniforms[i].value.real < 1)
1589 {
1590// VLog("Shader %p ('%s') has 'alpha' value %g", shader, shader->name, shader->uniforms[i].value.real);
1591 opaque = false;
1592 goto done;
1593 }
1594
1595 if (strcmp(shader->uniforms[i].type, "VuoImage") == 0
1596 && shader->uniforms[i].value.image
1597 && VuoGlTexture_formatHasAlphaChannel(shader->uniforms[i].value.image->glInternalFormat))
1598 {
1599// VLog("Shader %p ('%s') has an image with an alpha channel: %s", shader, shader->name, VuoImage_getSummary(shader->uniforms[i].value.image));
1600 opaque = false;
1601 goto done;
1602 }
1603 }
1604
1605done:
1606 dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
1607
1608 return opaque;
1609}
1610
1617{
1618 if (!shader)
1619 return false;
1620
1621 if (shader == VuoShader_makeDefaultShader())
1622 return false;
1623
1624 return true;
1625}
1626
1627
1628#include "VuoShaderShaders.h"
1629#include "VuoShaderUniforms.h"