13#include <CoreServices/CoreServices.h>
14#include <OpenGL/CGLMacro.h>
16#define glGenVertexArrays glGenVertexArraysAPPLE
17#define glBindVertexArray glBindVertexArrayAPPLE
18#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
27 "title" :
"VuoSceneObjectRenderer",
46 GLint textureCoordinate;
49 unsigned int expectedOutputPrimitiveCount;
50 bool mayChangeOutputPrimitiveCount;
61 GLuint shamFramebuffer;
83 VUserLog(
"Error '%s' is not a transform feedback shader.", shader->name);
93 bool havePoints =
VuoShader_getAttributeLocations(shader,
VuoMesh_Points, cgl_ctx, &sceneObjectRenderer->pointAttributes.position, &sceneObjectRenderer->pointAttributes.normal, &sceneObjectRenderer->pointAttributes.textureCoordinate, &sceneObjectRenderer->pointAttributes.color );
94 bool haveLines =
VuoShader_getAttributeLocations(shader,
VuoMesh_IndividualLines, cgl_ctx, &sceneObjectRenderer->lineAttributes.position, &sceneObjectRenderer->lineAttributes.normal, &sceneObjectRenderer->lineAttributes.textureCoordinate, &sceneObjectRenderer->lineAttributes.color );
95 bool haveTriangles =
VuoShader_getAttributeLocations(shader,
VuoMesh_IndividualTriangles, cgl_ctx, &sceneObjectRenderer->triangleAttributes.position, &sceneObjectRenderer->triangleAttributes.normal, &sceneObjectRenderer->triangleAttributes.textureCoordinate, &sceneObjectRenderer->triangleAttributes.color);
96 if (!havePoints || !haveLines || !haveTriangles)
98 VUserLog(
"Error: '%s' is missing programs for: %s %s %s", shader->name, havePoints?
"" :
"points", haveLines?
"" :
"lines", haveTriangles?
"" :
"triangles");
99 free(sceneObjectRenderer);
100 sceneObjectRenderer = NULL;
113 sceneObjectRenderer->shader = shader;
119 sceneObjectRenderer->shamTexture =
VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_RGBA, 1, 1, GL_BGRA, NULL);
121 glGenFramebuffers(1, &sceneObjectRenderer->shamFramebuffer);
122 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
123 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sceneObjectRenderer->shamTexture, 0);
124 glBindFramebuffer(GL_FRAMEBUFFER, 0);
126 glGenQueries(1, &sceneObjectRenderer->query);
143 GLuint outputPrimitiveGlMode;
145 int primitiveVertexMultiplier;
148 outputPrimitiveGlMode = GL_TRIANGLES;
149 attributes = sceneObjectRenderer->triangleAttributes;
150 primitiveVertexMultiplier = 3;
154 outputPrimitiveGlMode = GL_LINES;
155 attributes = sceneObjectRenderer->lineAttributes;
156 primitiveVertexMultiplier = 2;
160 outputPrimitiveGlMode = GL_POINTS;
161 attributes = sceneObjectRenderer->pointAttributes;
162 primitiveVertexMultiplier = 1;
165 unsigned int vertexCount, combinedBuffer, elementCount, elementBuffer;
166 void *normalOffset, *textureCoordinateOffset, *colorOffset;
167 VuoMesh_getGPUBuffers(mesh, &vertexCount, &combinedBuffer, &normalOffset, &textureCoordinateOffset, &colorOffset, &elementCount, &elementBuffer);
171 glBindBuffer(GL_ARRAY_BUFFER, combinedBuffer);
176 VUserLog(
"Shader activation failed.");
182 if (modelviewMatrixUniform != -1)
183 glUniformMatrix4fv(modelviewMatrixUniform, 1, GL_FALSE, modelviewMatrix);
187 if (modelviewMatrixInverseUniform != -1)
189 float modelviewMatrixInverse[16];
191 glUniformMatrix4fv(modelviewMatrixInverseUniform, 1, GL_FALSE, modelviewMatrixInverse);
195 int stride =
sizeof(float) * 3;
196 glEnableVertexAttribArray(attributes.position);
197 glVertexAttribPointer(attributes.position, 3 , GL_FLOAT, GL_FALSE, stride, (
void*)0);
198 bool hasNormals = normalOffset && attributes.normal >= 0;
201 glEnableVertexAttribArray(attributes.normal);
202 glVertexAttribPointer(attributes.normal, 3 , GL_FLOAT, GL_FALSE, stride, normalOffset);
204 bool hasTextureCoordinates = textureCoordinateOffset && attributes.textureCoordinate >= 0;
205 if (hasTextureCoordinates)
207 glEnableVertexAttribArray(attributes.textureCoordinate);
208 glVertexAttribPointer(attributes.textureCoordinate, 2 , GL_FLOAT, GL_FALSE,
sizeof(
float) * 2, textureCoordinateOffset);
210 bool hasColors = colorOffset && attributes.color >= 0;
213 glEnableVertexAttribArray(attributes.color);
214 glVertexAttribPointer(attributes.color, 4 , GL_FLOAT, GL_FALSE,
sizeof(
float) * 4, colorOffset);
220 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
226 unsigned long combinedOutputBufferSize =
sizeof(float) * (3 + 3 + 2 + 4) * outputVertexCount;
227 GLuint combinedOutputBuffer =
VuoGlPool_use(cgl_ctx, VuoGlPool_ArrayBuffer, combinedOutputBufferSize);
229 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, combinedOutputBuffer);
234 int size =
sizeof(float) * 3 * outputVertexCount;
235 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0, combinedOutputBuffer, 0, size);
237 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 1, combinedOutputBuffer, offset, size);
239 size =
sizeof(float) * 2 * outputVertexCount;
240 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 2, combinedOutputBuffer, offset, size);
242 size =
sizeof(float) * 4 * outputVertexCount;
243 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 3, combinedOutputBuffer, offset, size);
249 if (attributes.mayChangeOutputPrimitiveCount)
250 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT, sceneObjectRenderer->query);
251 glBeginTransformFeedbackEXT(outputPrimitiveGlMode);
254 GLuint timeElapsedQuery;
255 glGenQueries(1, &timeElapsedQuery);
256 glBeginQuery(GL_TIME_ELAPSED_EXT, timeElapsedQuery);
261 glDrawElements(mode, completeInputElementCount, GL_UNSIGNED_INT, (
void*)0);
262 else if (vertexCount)
263 glDrawArrays(mode, 0, completeInputElementCount);
267 glEndQuery(GL_TIME_ELAPSED_EXT);
269 glGetQueryObjectuiv(timeElapsedQuery, GL_QUERY_RESULT, &nanoseconds);
270 seconds = ((double)nanoseconds) / NSEC_PER_SEC;
271 glDeleteQueries(1, &timeElapsedQuery);
273 double objectPercent = seconds / (1./60.) * 100.;
274 VLog(
"%6.2f %% of 60 Hz frame %s (%s)", objectPercent, sceneObject->name, sceneObjectRenderer->shader->name);
278 glEndTransformFeedbackEXT();
279 if (attributes.mayChangeOutputPrimitiveCount)
280 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT);
282 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0);
285 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
288 glDisableVertexAttribArray(attributes.color);
289 if (hasTextureCoordinates)
290 glDisableVertexAttribArray(attributes.textureCoordinate);
292 glDisableVertexAttribArray(attributes.normal);
293 glDisableVertexAttribArray(attributes.position);
298 GLuint actualVertexCount = 0;
299 if (attributes.mayChangeOutputPrimitiveCount)
301 glGetQueryObjectuiv(sceneObjectRenderer->query, GL_QUERY_RESULT, &actualVertexCount);
302 actualVertexCount *= primitiveVertexMultiplier;
305 actualVertexCount = outputVertexCount;
310 VLog(
"inputElements=%lu actualVertexCount=%d normals=%d textureCoordinates=%d colors=%d", completeInputElementCount, actualVertexCount, hasNormals, hasTextureCoordinates, hasColors);
312 GLfloat feedback[actualVertexCount * (3 + 3 + 2 + 4)];
313 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, combinedOutputBuffer);
314 glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0,
sizeof(feedback), feedback);
315 for (
int i = 0; i < actualVertexCount; ++i)
316 fprintf(stderr,
"\t%3d = pos %5.2f %5.2f %5.2f normal %5.2f %5.2f %5.2f tc %5.2f %5.2f color %5.2f %5.2f %5.2f %5.2f\n", i,
317 feedback[i * 3], feedback[i * 3 + 1], feedback[i * 3 + 2],
318 feedback[(outputVertexCount + i) * 3], feedback[(outputVertexCount + i) * 3 + 1], feedback[(outputVertexCount + i) * 3 + 2],
319 feedback[outputVertexCount * (3 + 3) + i * 2], feedback[outputVertexCount * (3 + 3) + i * 2 + 1],
320 feedback[outputVertexCount * (3 + 3 + 2) + i * 4], feedback[outputVertexCount * (3 + 3 + 2) + i * 4 + 1], feedback[outputVertexCount * (3 + 3 + 2) + i * 4 + 2], feedback[outputVertexCount * (3 + 3 + 2) + i * 4 + 3]);
321 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0);
337 actualVertexCount, combinedOutputBuffer, combinedOutputBufferSize,
338 (
void *)(
sizeof(
float) * (3 ) * outputVertexCount),
339 hasTextureCoordinates ? (
void *)(
sizeof(
float) * (3 + 3 ) * outputVertexCount) :
nullptr,
340 hasColors ? (
void *)(
sizeof(
float) * (3 + 3 + 2) * outputVertexCount) :
nullptr,
342 outputPrimitiveMode);
350#define ELEM(i) (elementCount ? elements[i] : i)
359 for (
int i = 0; i < verticesPerPrimitive * floatsPerVertex; ++i)
360 destination[i] = defaultValues[i % floatsPerVertex];
370 unsigned int *e = elements + start;
371 for (
int i = 0; i < verticesPerPrimitive; ++i)
372 for (
int j = 0; j < floatsPerVertex; ++j)
373 destination[i * floatsPerVertex + j] = source[*(e + i) * floatsPerVertex + j];
377 for (
int i = 0; i < verticesPerPrimitive; ++i)
378 for (
int j = 0; j < floatsPerVertex; ++j)
379 destination[i * floatsPerVertex + j] = source[(start + i) * floatsPerVertex + j];
385 if ((start / 3) % 2 == 0)
387 for (
int i = 0; i < verticesPerPrimitive; ++i)
388 for (
int j = 0; j < floatsPerVertex; ++j)
389 destination[i * floatsPerVertex + j] = source[
ELEM(start/3 + i) * floatsPerVertex + j];
393 for (
int j = 0; j < floatsPerVertex; ++j)
395 destination[0 * floatsPerVertex + j] = source[
ELEM(start/3 + 1) * floatsPerVertex + j];
396 destination[1 * floatsPerVertex + j] = source[
ELEM(start/3 ) * floatsPerVertex + j];
397 destination[2 * floatsPerVertex + j] = source[
ELEM(start/3 + 2) * floatsPerVertex + j];
404 for (
int j = 0; j < floatsPerVertex; ++j)
406 destination[0 * floatsPerVertex + j] = source[
ELEM(0 ) * floatsPerVertex + j];
407 destination[1 * floatsPerVertex + j] = source[
ELEM(start/3 + 1) * floatsPerVertex + j];
408 destination[2 * floatsPerVertex + j] = source[
ELEM(start/3 + 2) * floatsPerVertex + j];
414 for (
int j = 0; j < floatsPerVertex; ++j)
416 destination[0 * floatsPerVertex + j] = source[
ELEM(start/2 ) * floatsPerVertex + j];
417 destination[1 * floatsPerVertex + j] = source[
ELEM(start/2 + 1) * floatsPerVertex + j];
432 float *inputPositions, *inputNormals, *inputTextureCoordinates, *inputColors;
433 unsigned int elementCount, *elements;
434 VuoMesh_getCPUBuffers(mesh,
nullptr, &inputPositions, &inputNormals, &inputTextureCoordinates, &inputColors, &elementCount, &elements);
436 float modelMatrixInverse[16];
451 unsigned int allocatedVertices = inputCount;
452 float *newPositions, *newNormals, *newTextureCoordinates, *newColors;
454 unsigned int newVertexCount = 0;
456 int verticesPerPrimitive;
461 verticesPerPrimitive = 3;
464 verticesPerPrimitive = 2;
466 verticesPerPrimitive = 1;
468 float defaultPosition[3] = {0,0,0};
469 float defaultNormal[3] = {0,0,1};
470 float defaultColor[4] = {1,1,1,1};
472 for (
unsigned int e = 0; e < inputCount; e += verticesPerPrimitive)
476 allocatedVertices *= 2;
477 newPositions = (
float *)realloc(newPositions,
sizeof(
float) * 3 * allocatedVertices);
478 newNormals = (
float *)realloc(newNormals,
sizeof(
float) * 3 * allocatedVertices);
479 newTextureCoordinates = (
float *)realloc(newTextureCoordinates,
sizeof(
float) * 2 * allocatedVertices);
480 newColors = (
float *)realloc(newColors,
sizeof(
float) * 4 * allocatedVertices);
483 float *positions = newPositions + newVertexCount * 3;
484 float *normals = newNormals + newVertexCount * 3;
485 float *textureCoordinates = newTextureCoordinates + newVertexCount * 2;
486 float *colors = newColors + newVertexCount * 4;
489 VuoSceneObjectRenderer_copyElement(mesh, e, inputTextureCoordinates, elementCount, elements, elementAssemblyMethod, verticesPerPrimitive, 2, textureCoordinates, defaultPosition);
492 int vertexCount = verticesPerPrimitive;
501 cpuGeometryOperator(modelviewMatrix, modelMatrixInverse, &vertexCount, positions, normals, textureCoordinates, colors);
516 if (vertexCount % verticesPerPrimitive)
518 VUserLog(
"Error: When %d vertices are input to cpuGeometryOperator, it must output a multiple of %d vertices.", verticesPerPrimitive, verticesPerPrimitive);
522 newVertexCount += vertexCount;
530 bool originalMeshHasTextureCoordinates = inputTextureCoordinates;
531 VuoMesh newMesh =
VuoMesh_makeFromCPUBuffers(newVertexCount, newPositions, newNormals, originalMeshHasTextureCoordinates ? newTextureCoordinates :
nullptr, newColors,
533 elementAssemblyMethod);
534 if (!originalMeshHasTextureCoordinates)
535 free(newTextureCoordinates);
552 return Block_copy(^(
float *modelMatrix,
float *modelMatrixInverse,
int *vertexCount,
float *positions,
float *normals,
float *textureCoordinates,
float *colors) {
553 VuoPoint3d positionInScene[3];
554 VuoPoint3d deformedPositionInScene[3];
555 VuoPoint3d normalInScene[3];
556 VuoPoint2d textureCoordinate[3];
557 for (
int i = 0; i < *vertexCount; ++i)
575 VuoPoint3d deformedPosition = deform(positionInScene[i],
577 textureCoordinate[i]);
578 deformedPositionInScene[i] = deformedPosition;
589 VuoPoint3d tangentInScene[3], bitangentInScene[3];
590 if (*vertexCount == 3)
596 VuoPoint3d tan1[3], tan2[3];
597 bzero(tan1,
sizeof(VuoPoint3d) * 3);
598 bzero(tan2,
sizeof(VuoPoint3d) * 3);
600 VuoPoint3d v1 = positionInScene[0];
601 VuoPoint3d v2 = positionInScene[1];
602 VuoPoint3d v3 = positionInScene[2];
604 VuoPoint2d w1 = textureCoordinate[0];
605 VuoPoint2d w2 = textureCoordinate[1];
606 VuoPoint2d w3 = textureCoordinate[2];
608 float x1 = v2.x - v1.x;
609 float x2 = v3.x - v1.x;
610 float y1 = v2.y - v1.y;
611 float y2 = v3.y - v1.y;
612 float z1 = v2.z - v1.z;
613 float z2 = v3.z - v1.z;
615 float s1 = w2.x - w1.x;
616 float s2 = w3.x - w1.x;
617 float t1 = w2.y - w1.y;
618 float t2 = w3.y - w1.y;
620 float r = 1.0F / (s1 * t2 - s2 * t1);
621 VuoPoint3d sdir = (VuoPoint3d){
622 (t2 * x1 - t1 * x2) * r,
623 (t2 * y1 - t1 * y2) * r,
624 (t2 * z1 - t1 * z2) * r};
625 VuoPoint3d tdir = (VuoPoint3d){
626 (s1 * x2 - s2 * x1) * r,
627 (s1 * y2 - s2 * y1) * r,
628 (s1 * z2 - s2 * z1) * r};
638 for (
int i = 0; i < *vertexCount; ++i)
640 VuoPoint3d n = normalInScene[i];
641 VuoPoint3d t = tan1[i];
642 VuoPoint3d t2 = tan2[i];
650 for (
int i = 0; i < *vertexCount; ++i)
652 tangentInScene[i] = (VuoPoint3d){1,0,0};
653 bitangentInScene[i] = (VuoPoint3d){0,1,0};
659 for (
int i = 0; i < *vertexCount; ++i)
661 const float scale = .01;
662 VuoPoint3d deformedAlongTangent = deform(positionInScene[i] + tangentInScene[i] * scale,
664 textureCoordinate[i] + (VuoPoint2d){scale, 0});
665 VuoPoint3d deformedAlongBitangent = deform(positionInScene[i] + bitangentInScene[i] * scale,
667 textureCoordinate[i] + (VuoPoint2d){0, scale});
669 VuoPoint3d deformedPosition = deformedPositionInScene[i];
672 VuoPoint3d deformedTangent = deformedAlongTangent - deformedPosition;
673 VuoPoint3d deformedBitangent = deformedAlongBitangent - deformedPosition;
691 static bool gpuTransformFeedback;
692 static dispatch_once_t once = 0;
693 dispatch_once(&once, ^{
695 Boolean overridden =
false;
696 gpuTransformFeedback = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"gpuTransformFeedback"), CFSTR(
"org.vuo.Editor"), &overridden);
703 __block
const char *renderer;
705 renderer = (
const char *)glGetString(GL_RENDERER);
708 if (strncmp(renderer,
"Intel", 5) == 0
709 || strncmp(renderer,
"AMD ", 4) == 0
710 || strncmp(renderer,
"NVIDIA GeForce 9400M", 4) == 0
711 || strncmp(renderer,
"Apple ", 6) == 0
712 || strncmp(renderer,
"ATI ", 4) == 0)
713 gpuTransformFeedback =
false;
716 gpuTransformFeedback =
true;
719 VUserLog(
"gpuTransformFeedback = %d", gpuTransformFeedback);
722 return gpuTransformFeedback;
752 glEnable(GL_RASTERIZER_DISCARD_EXT);
754 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
760 glBindBuffer(GL_ARRAY_BUFFER, 0);
761 glBindFramebuffer(GL_FRAMEBUFFER, 0);
763 glDisable(GL_RASTERIZER_DISCARD_EXT);
767 glFlushRenderAPPLE();
770 return sceneObjectCopy;
781 return sceneObjectCopy;
798 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
799 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
800 VuoGlTexture_release(VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_RGBA, 1, 1, sceneObjectRenderer->shamTexture);
802 glDeleteFramebuffers(1, &sceneObjectRenderer->shamFramebuffer);
806 glDeleteQueries(1, &sceneObjectRenderer->query);
809 free(sceneObjectRenderer);