Vuo  2.3.2
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 
20 extern "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 
72 void 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 
123 VuoShader 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 
311 void 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 
318  DEFINE_PROGRAM();
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 
399 void 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 
406  DEFINE_PROGRAM();
407  program->expectedOutputPrimitiveCount = expectedOutputPrimitiveCount;
408 
409  dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
410 }
411 
425 void 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 
432  DEFINE_PROGRAM();
433  program->mayChangeOutputPrimitiveCount = mayChangeOutputPrimitiveCount;
434 
435  dispatch_semaphore_signal((dispatch_semaphore_t)shader->lock);
436 }
437 
444 void 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 
467  DEFINE_PROGRAM();
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 
490  DEFINE_PROGRAM();
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 
531 static 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 
593 static 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 
614 static 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 
656 static bool VuoShader_ensureUploaded(VuoShader shader, const VuoMesh_ElementAssemblyMethod inputPrimitiveMode, VuoGlContext glContext, VuoShaderIssues *outIssues)
657 {
658  if (!shader)
659  return false;
660 
661  DEFINE_PROGRAM();
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 
735 bool 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 
767 bool 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 
779  DEFINE_PROGRAM();
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 
799 static GLuint VuoShader_perlinTexture;
807 void 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 
854 static GLuint VuoShader_gradTexture;
861 void 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 
912 typedef std::map<VuoGlContext, GLuint> VuoShaderContextType;
914 static dispatch_semaphore_t VuoShaderContext_semaphore;
918 static void __attribute__((constructor)) VuoShaderContext_init(void)
919 {
920  VuoShaderContext_semaphore = dispatch_semaphore_create(1);
921 }
922 
939 bool 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 
952  DEFINE_PROGRAM();
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, ^{
1190  VuoShader_initPerlinTexture(cgl_ctx);
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, ^{
1205  VuoShader_initGradTexture(cgl_ctx);
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 
1336 void 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 
1348  DEFINE_PROGRAM();
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 
1445  return VuoShader_makeDefaultShader();
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 
1480 char * VuoShader_getSummary(const VuoShader value)
1481 {
1482  if (!value)
1483  return strdup("No shader");
1484 
1485  return strdup(value->name);
1486 }
1487 
1500 VuoPoint2d 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 
1602 done:
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"