void display(void) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); if(displayError) { orthographicView(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); txtInstructions.render((screenWidth - txtInstructions.getTextureWidth()) / 2.0f, (screenHeight - txtInstructions.getTextureHeight()) / 2.0f); glFlush(); return; } glPushMatrix(); // Setup the navigation glTranslated(0, 0, -zoom); glRotatef(camRotateX, 1, 0, 0); glRotatef(camRotateY, 0, 1, 0); glTranslated(0, ROOM_SIZE, 0); // Setup drawing for the scene. perspectiveView(); #if _USE_MT // If the render thread needs to wait for new spheres to be added. while(pauseSimulation) { boost::this_thread::yield(); } threadStarted(); #endif renderFrame++; renderFrameCounter++; glEnable(GL_DEPTH_TEST); glColor3f(1.0f, 1.0f, 1.0f); glUseProgram(g_program); glUniform3fv(g_programCameraPositionLocation, 1, g_cameraPosition); glUniform3fv(g_programLightDirectionLocation, 1, g_lightDirection); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereMesh.indexBufferId); // We are using instanced rendering, however we cannot draw all the spheres at once. // So we have a maximum number of objects that can be rendered at once and we'll just // render that many at a time until we have less spheres than MAX_OBJECTS_PER_RENDER // left to render. for(int objectIndex = 0; objectIndex < numSpheres; objectIndex += MAX_OBJECTS_PER_RENDER) { int numObjects = MAX_OBJECTS_PER_RENDER; // Are we going to be rendering more spheres than we should? if (numObjects + objectIndex > numSpheres) { numObjects = numSpheres - objectIndex; } Vector3 *positionIndex = spherePositions + objectIndex; glUniform4fv(g_programObjectPositionLocation, numObjects, (float *)positionIndex); // Tell the shader the size of the user sphere. // Due to the way the shader renders multiple instances, it only knows the id // of the current instance it is rendering, which does not reflect the sphere's actual // id. // So we will set that the size of the userSphere only on the first instanced render // and all later renders it will be zero. glUniform1f(g_programUserSphereLocation, (objectIndex == 0) * userSphereSize); glDrawElementsInstancedEXT(GL_TRIANGLES, sphereMesh.numIndicies, GL_UNSIGNED_INT, 0, numObjects); } glUseProgram(0); #if _USE_MT threadStopped(); #endif glPopMatrix(); // Setup drawing for the interface. orthographicView(); char buff[64]; sprintf(buff, "FPS: %d", framesPerSecond); txtRenderFrames.setText(buff); sprintf(buff, "PPS: %.1f", physicsPerSecond); txtPhysicsFrames.setText(buff); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); float yPos = -2.0f; txtInstructions.render(10, yPos += 12.0f); txtInstructions2.render(10, yPos += 12.0f); txtNumThreads.render(10, yPos += 12.0f); txtNumSpheres.render(10, yPos += 12.0f); txtRenderFrames.render(10, yPos += 12.0f); txtPhysicsFrames.render(10, yPos += 12.0f); glDisable(GL_BLEND); glFlush(); }