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",
48 GLint textureCoordinate;
50 unsigned int expectedOutputPrimitiveCount;
51 bool mayChangeOutputPrimitiveCount;
62 GLuint shamFramebuffer;
84 VUserLog(
"Error '%s' is not a transform feedback shader.", shader->
name);
94 bool havePoints =
VuoShader_getAttributeLocations(shader,
VuoMesh_Points, cgl_ctx, &sceneObjectRenderer->pointAttributes.position, &sceneObjectRenderer->pointAttributes.normal, &sceneObjectRenderer->pointAttributes.tangent, &sceneObjectRenderer->pointAttributes.bitangent, &sceneObjectRenderer->pointAttributes.textureCoordinate );
95 bool haveLines =
VuoShader_getAttributeLocations(shader,
VuoMesh_IndividualLines, cgl_ctx, &sceneObjectRenderer->lineAttributes.position, &sceneObjectRenderer->lineAttributes.normal, &sceneObjectRenderer->lineAttributes.tangent, &sceneObjectRenderer->lineAttributes.bitangent, &sceneObjectRenderer->lineAttributes.textureCoordinate );
96 bool haveTriangles =
VuoShader_getAttributeLocations(shader,
VuoMesh_IndividualTriangles, cgl_ctx, &sceneObjectRenderer->triangleAttributes.position, &sceneObjectRenderer->triangleAttributes.normal, &sceneObjectRenderer->triangleAttributes.tangent, &sceneObjectRenderer->triangleAttributes.bitangent, &sceneObjectRenderer->triangleAttributes.textureCoordinate);
97 if (!havePoints || !haveLines || !haveTriangles)
99 VUserLog(
"Error: '%s' is missing programs for: %s %s %s", shader->
name, havePoints?
"" :
"points", haveLines?
"" :
"lines", haveTriangles?
"" :
"triangles");
100 free(sceneObjectRenderer);
101 sceneObjectRenderer = NULL;
114 sceneObjectRenderer->shader = shader;
120 sceneObjectRenderer->shamTexture =
VuoGlTexturePool_use(cgl_ctx, VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_RGBA, 1, 1, GL_BGRA, NULL);
122 glGenFramebuffers(1, &sceneObjectRenderer->shamFramebuffer);
123 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
124 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sceneObjectRenderer->shamTexture, 0);
125 glBindFramebuffer(GL_FRAMEBUFFER, 0);
127 glGenQueries(1, &sceneObjectRenderer->query);
139 if (!sceneObject->mesh)
146 for (
unsigned int i = 0; i < sceneObject->mesh->
submeshCount; ++i)
152 GLuint outputPrimitiveGlMode;
154 int primitiveVertexMultiplier;
157 outputPrimitiveGlMode = GL_TRIANGLES;
158 attributes = sceneObjectRenderer->triangleAttributes;
159 primitiveVertexMultiplier = 3;
163 outputPrimitiveGlMode = GL_LINES;
164 attributes = sceneObjectRenderer->lineAttributes;
165 primitiveVertexMultiplier = 2;
169 outputPrimitiveGlMode = GL_POINTS;
170 attributes = sceneObjectRenderer->pointAttributes;
171 primitiveVertexMultiplier = 1;
176 glBindBuffer(GL_ARRAY_BUFFER, submesh.
glUpload.combinedBuffer);
181 VUserLog(
"Shader activation failed.");
187 if (modelviewMatrixUniform != -1)
188 glUniformMatrix4fv(modelviewMatrixUniform, 1, GL_FALSE, modelviewMatrix);
192 if (modelviewMatrixInverseUniform != -1)
194 float modelviewMatrixInverse[16];
196 glUniformMatrix4fv(modelviewMatrixInverseUniform, 1, GL_FALSE, modelviewMatrixInverse);
201 glEnableVertexAttribArray(attributes.position);
202 glVertexAttribPointer(attributes.position, 4 , GL_FLOAT, GL_FALSE, stride, (
void*)0);
203 if (submesh.
glUpload.normalOffset && attributes.normal >= 0)
205 glEnableVertexAttribArray(attributes.normal);
206 glVertexAttribPointer(attributes.normal, 4 , GL_FLOAT, GL_FALSE, stride, submesh.
glUpload.normalOffset);
208 bool hasTangents = submesh.
glUpload.tangentOffset && attributes.tangent >= 0;
211 glEnableVertexAttribArray(attributes.tangent);
212 glVertexAttribPointer(attributes.tangent, 4 , GL_FLOAT, GL_FALSE, stride, submesh.
glUpload.tangentOffset);
214 bool hasBitangents = submesh.
glUpload.bitangentOffset && attributes.bitangent >= 0;
217 glEnableVertexAttribArray(attributes.bitangent);
218 glVertexAttribPointer(attributes.bitangent, 4 , GL_FLOAT, GL_FALSE, stride, submesh.
glUpload.bitangentOffset);
220 bool hasTextureCoordinates = submesh.
glUpload.textureCoordinateOffset && attributes.textureCoordinate >= 0;
221 if (hasTextureCoordinates)
223 glEnableVertexAttribArray(attributes.textureCoordinate);
224 glVertexAttribPointer(attributes.textureCoordinate, 4 , GL_FLOAT, GL_FALSE, stride, submesh.
glUpload.textureCoordinateOffset);
230 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submesh.
glUpload.elementBuffer);
236 unsigned long singleOutputBufferSize =
sizeof(VuoPoint4d)*outputVertexCount;
237 unsigned long combinedOutputBufferSize = singleOutputBufferSize*5;
238 GLuint combinedOutputBuffer =
VuoGlPool_use(cgl_ctx, VuoGlPool_ArrayBuffer, combinedOutputBufferSize);
240 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, combinedOutputBuffer);
242 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0, combinedOutputBuffer);
247 if (attributes.mayChangeOutputPrimitiveCount)
248 glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT, sceneObjectRenderer->query);
249 glBeginTransformFeedbackEXT(outputPrimitiveGlMode);
252 GLuint timeElapsedQuery;
253 glGenQueries(1, &timeElapsedQuery);
254 glBeginQuery(GL_TIME_ELAPSED_EXT, timeElapsedQuery);
259 glDrawElements(mode, completeInputElementCount, GL_UNSIGNED_INT, (
void*)0);
261 glDrawArrays(mode, 0, completeInputElementCount);
265 glEndQuery(GL_TIME_ELAPSED_EXT);
267 glGetQueryObjectuiv(timeElapsedQuery, GL_QUERY_RESULT, &nanoseconds);
268 seconds = ((double)nanoseconds) / NSEC_PER_SEC;
269 glDeleteQueries(1, &timeElapsedQuery);
271 double objectPercent = seconds / (1./60.) * 100.;
272 VLog(
"%6.2f %% of 60 Hz frame %s (%s)", objectPercent, sceneObject->name, sceneObjectRenderer->shader->
name);
276 glEndTransformFeedbackEXT();
277 if (attributes.mayChangeOutputPrimitiveCount)
278 glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT);
280 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0);
283 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
285 if (hasTextureCoordinates)
286 glDisableVertexAttribArray(attributes.textureCoordinate);
288 glDisableVertexAttribArray(attributes.bitangent);
290 glDisableVertexAttribArray(attributes.tangent);
291 if (submesh.
glUpload.normalOffset && attributes.normal >= 0)
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;
311 GLfloat feedback[actualVertexCount*4*5];
312 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, combinedOutputBuffer);
313 glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0,
sizeof(feedback), feedback);
314 for (
int buffer = 0; buffer < 5; ++buffer)
317 fprintf(stderr,
"positions:\n");
318 else if (buffer == 1)
322 fprintf(stderr,
"normals:\n");
324 else if (buffer == 2)
326 if (!submesh.
glUpload.tangentOffset)
328 fprintf(stderr,
"tangents:\n");
330 else if (buffer == 3)
332 if (!submesh.
glUpload.bitangentOffset)
334 fprintf(stderr,
"bitangents:\n");
336 else if (buffer == 4)
338 if (!submesh.
glUpload.textureCoordinateOffset)
340 fprintf(stderr,
"texture coordinates:\n");
343 for (
int vertex = 0; vertex < actualVertexCount; vertex++)
345 for (
int coordinate = 0; coordinate < 4; ++coordinate)
346 fprintf(stderr,
"\t%f", feedback[vertex*4*5 + buffer*4 + coordinate]);
347 if (buffer >= 1 && buffer <= 3)
348 fprintf(stderr,
" (length %f)",
VuoPoint3d_magnitude((VuoPoint3d){feedback[vertex*4*5 + buffer*4], feedback[vertex*4*5 + buffer*4 + 1], feedback[vertex*4*5 + buffer*4 + 2]}));
349 fprintf(stderr,
"\n");
352 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER_EXT, 0);
359 unsigned long combinedOutputBufferStride =
sizeof(VuoPoint4d) * 5;
362 actualVertexCount, combinedOutputBuffer, combinedOutputBufferSize, combinedOutputBufferStride,
363 submesh.
glUpload.normalOffset ? (
void*)(
sizeof(VuoPoint4d)*1) : NULL,
364 submesh.
glUpload.tangentOffset ? (
void*)(
sizeof(VuoPoint4d)*2) : NULL,
365 submesh.
glUpload.bitangentOffset ? (
void*)(
sizeof(VuoPoint4d)*3) : NULL,
366 submesh.
glUpload.textureCoordinateOffset ? (
void*)(
sizeof(VuoPoint4d)*4) : NULL,
368 outputPrimitiveMode);
375 sceneObject->mesh = newMesh;
379 #define ELEM(i) (submesh.elementCount ? submesh.elements[i] : i)
388 for (
int i = 0; i < count; ++i)
389 destination[i] = (VuoPoint4d){0,0,1,1};
397 unsigned int *e = submesh.
elements + start;
398 destination[0] = source[*(e )];
399 destination[1] = source[*(e + 1)];
400 destination[2] = source[*(e + 2)];
404 VuoPoint4d *s = source + start;
405 destination[0] = *(s );
406 destination[1] = *(s + 1);
407 destination[2] = *(s + 2);
414 unsigned int *e = submesh.
elements + start;
415 destination[0] = source[*(e )];
416 destination[1] = source[*(e + 1)];
420 VuoPoint4d *s = source + start;
421 destination[0] = *(s );
422 destination[1] = *(s + 1);
428 destination[0] = source[submesh.
elements[start]];
430 destination[0] = source[start];
435 if ((start / 3) % 2 == 0)
437 destination[0] = source[
ELEM(start/3 )];
438 destination[1] = source[
ELEM(start/3 + 1)];
439 destination[2] = source[
ELEM(start/3 + 2)];
443 destination[0] = source[
ELEM(start/3 + 1)];
444 destination[1] = source[
ELEM(start/3 )];
445 destination[2] = source[
ELEM(start/3 + 2)];
451 destination[0] = source[
ELEM(0 )];
452 destination[1] = source[
ELEM(start/3 + 1)];
453 destination[2] = source[
ELEM(start/3 + 2)];
458 destination[0] = source[
ELEM(start/2 )];
459 destination[1] = source[
ELEM(start/2 + 1)];
469 if (!sceneObject->mesh)
476 float modelMatrixInverse[16];
479 for (
unsigned int i = 0; i < sceneObject->mesh->
submeshCount; ++i)
486 unsigned int allocatedVertices = inputCount;
487 VuoPoint4d *newPositions = (VuoPoint4d *)malloc(
sizeof(VuoPoint4d) * allocatedVertices);
488 VuoPoint4d *newNormals = (VuoPoint4d *)malloc(
sizeof(VuoPoint4d) * allocatedVertices);
489 VuoPoint4d *newTangents = (VuoPoint4d *)malloc(
sizeof(VuoPoint4d) * allocatedVertices);
490 VuoPoint4d *newBitangents = (VuoPoint4d *)malloc(
sizeof(VuoPoint4d) * allocatedVertices);
491 VuoPoint4d *newTextureCoordinates = (VuoPoint4d *)malloc(
sizeof(VuoPoint4d) * allocatedVertices);
492 unsigned int newVertexCount = 0;
494 int verticesPerPrimitive;
498 verticesPerPrimitive = 3;
501 verticesPerPrimitive = 2;
503 verticesPerPrimitive = 1;
505 for (
unsigned int e = 0; e < inputCount; e += verticesPerPrimitive)
509 allocatedVertices *= 2;
510 newPositions = (VuoPoint4d *)realloc(newPositions,
sizeof(VuoPoint4d) * allocatedVertices);
511 newNormals = (VuoPoint4d *)realloc(newNormals,
sizeof(VuoPoint4d) * allocatedVertices);
512 newTangents = (VuoPoint4d *)realloc(newTangents,
sizeof(VuoPoint4d) * allocatedVertices);
513 newBitangents = (VuoPoint4d *)realloc(newBitangents,
sizeof(VuoPoint4d) * allocatedVertices);
514 newTextureCoordinates = (VuoPoint4d *)realloc(newTextureCoordinates,
sizeof(VuoPoint4d) * allocatedVertices);
517 VuoPoint4d *positions = newPositions + newVertexCount;
518 VuoPoint4d *normals = newNormals + newVertexCount;
519 VuoPoint4d *tangents = newTangents + newVertexCount;
520 VuoPoint4d *bitangents = newBitangents + newVertexCount;
521 VuoPoint4d *textureCoordinates = newTextureCoordinates + newVertexCount;
528 int vertexCount = verticesPerPrimitive;
530 cpuGeometryOperator(modelviewMatrix, modelMatrixInverse, &vertexCount, positions, normals, tangents, bitangents, textureCoordinates);
538 if (vertexCount % verticesPerPrimitive)
540 VUserLog(
"Error: When %d vertices are input to cpuGeometryOperator, it must output a multiple of %d vertices.", verticesPerPrimitive, verticesPerPrimitive);
544 newVertexCount += vertexCount;
548 VuoSubmesh newSubmesh =
VuoSubmesh_makeFromBuffers(newVertexCount, newPositions, newNormals, newTangents, newBitangents, originalMeshHasTextureCoordinates ? newTextureCoordinates : NULL,
559 sceneObject->mesh = newMesh;
572 return Block_copy(^(
float *modelMatrix,
float *modelMatrixInverse,
int *vertexCount, VuoPoint4d *positions, VuoPoint4d *normals, VuoPoint4d *tangents, VuoPoint4d *bitangents, VuoPoint4d *textureCoordinates) {
573 for (
int i = 0; i < *vertexCount; ++i)
584 VuoPoint3d deformedPosition = deform(positionInScene,
586 (VuoPoint2d){textureCoordinates[i].x, textureCoordinates[i].y});
600 VuoPoint3d deformedAlongTangent = deform((VuoPoint3d){positionInScene.x + tangentInScene.x / 100.f,
601 positionInScene.y + tangentInScene.y / 100.f,
602 positionInScene.z + tangentInScene.z / 100.f},
604 (VuoPoint2d){textureCoordinates[i].x + .01f,
605 textureCoordinates[i].y});
606 VuoPoint3d deformedAlongBitangent = deform((VuoPoint3d){positionInScene.x + bitangentInScene.x / 100.f,
607 positionInScene.y + bitangentInScene.y / 100.f,
608 positionInScene.z + bitangentInScene.z / 100.f},
610 (VuoPoint2d){textureCoordinates[i].x,
611 textureCoordinates[i].y + .01f});
618 tangents[i] = (VuoPoint4d){tangent.x, tangent.y, tangent.z, 1};
619 bitangents[i] = (VuoPoint4d){bitangent.x, bitangent.y, bitangent.z, 1};
620 normals[i] = (VuoPoint4d){normal.x, normal.y, normal.z, 1};
632 static bool gpuTransformFeedback;
633 static dispatch_once_t once = 0;
634 dispatch_once(&once, ^{
636 Boolean overridden =
false;
637 gpuTransformFeedback = (int)CFPreferencesGetAppIntegerValue(CFSTR(
"gpuTransformFeedback"), CFSTR(
"org.vuo.Editor"), &overridden);
644 __block
const char *renderer;
646 renderer = (
const char *)glGetString(GL_RENDERER);
649 if (strncmp(renderer,
"Intel", 5) == 0
650 || strncmp(renderer,
"AMD ", 4) == 0
651 || strncmp(renderer,
"NVIDIA GeForce 9400M", 4) == 0
652 || strncmp(renderer,
"ATI ", 4) == 0)
653 gpuTransformFeedback =
false;
656 gpuTransformFeedback =
true;
659 VDebugLog(
"gpuTransformFeedback = %d", gpuTransformFeedback);
662 return gpuTransformFeedback;
692 glEnable(GL_RASTERIZER_DISCARD_EXT);
694 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
700 glBindBuffer(GL_ARRAY_BUFFER, 0);
701 glBindFramebuffer(GL_FRAMEBUFFER, 0);
703 glDisable(GL_RASTERIZER_DISCARD_EXT);
707 glFlushRenderAPPLE();
710 return sceneObjectCopy;
721 return sceneObjectCopy;
738 glBindFramebuffer(GL_FRAMEBUFFER, sceneObjectRenderer->shamFramebuffer);
739 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
740 VuoGlTexture_release(VuoGlTexturePool_Allocate, GL_TEXTURE_2D, GL_RGBA, 1, 1, sceneObjectRenderer->shamTexture);
742 glDeleteFramebuffers(1, &sceneObjectRenderer->shamFramebuffer);
746 glDeleteQueries(1, &sceneObjectRenderer->query);
749 free(sceneObjectRenderer);