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