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