// occquery.cpp : Defines the entry point for the console application. // #include #include #include "common.h" #include "glInterface.h" #include "RenderTraverser.h" #include "SceneEntity.h" #include "Vector3.h" #include "Matrix4x4.h" #include "BinaryLoader.h" #include "Bvh.h" #include "Camera.h" #include "Geometry.h" #include "BvhLoader.h" #include "FrustumCullingTraverser.h" #include "StopAndWaitTraverser.h" #include "CHCTraverser.h" #include "CHCPlusPlusTraverser.h" #include "Visualization.h" #include "RenderState.h" using namespace std; using namespace CHCDemoEngine; /// the renderable scene geometry SceneEntityContainer sceneEntities; // traverses and renders the hierarchy RenderTraverser *traverser = NULL; /// the hierarchy Bvh *bvh = NULL; /// the scene camera Camera *camera = NULL; /// the visualization Visualization *visualization = NULL; /// the current render state RenderState state; /// the rendering algorithm int renderMode = RenderTraverser::CULL_FRUSTUM; // eye near plane distance float nearDist = 0.1f; /// the pixel threshold where a node is still considered invisible int threshold; int assumedVisibleFrames = 10; int maxBatchSize = 50; const float keyForwardMotion = 1.0f; const float keyRotation = 0.2f; int winWidth = 1024; int winHeight = 768; float winAspectRatio = 1.0f; double accumulatedTime = 1000; float fps = 1e3f; int renderedObjects = 0; int renderedNodes = 0; int renderedTriangles = 0; int issuedQueries = 0; int traversedNodes = 0; int frustumCulledNodes = 0; int queryCulledNodes = 0; int stateChanges = 0; bool showHelp = false; bool showStatistics = true; bool showBoundingVolumes = false; bool visMode = false; //mouse navigation state int xEyeBegin, yEyeBegin, yMotionBegin, verticalMotionBegin, horizontalMotionBegin = 0; bool useOptimization = false; bool useTightBounds = true; bool useRenderQueue = false; bool useMultiQueries = true; float rotation = 0; Matrix4x4 visView = IdentityMatrix(); void InitExtensions(); void DisplayVisualization(); void InitGLstate(); void CleanUp(); void SetupEyeView(); void UpdateEyeMtx(); void SetupLighting(); void DisplayStats(); void Output(int x, int y, const char *string); void DrawHelpMessage(); void begin2D(); void end2D(); void keyboard(unsigned char c, int x, int y); void drawStatistics(); void display(void); void special(int c, int x, int y); void reshape(int w, int h); void mouse(int button, int state, int x, int y); void leftMotion(int x, int y); void rightMotion(int x, int y); void middleMotion(int x, int y); void drawEyeView(); void setupVisView(); void CalcDecimalPoint(std::string &str, int d); void ResetTraverser(); int main(int argc, char* argv[]) { int returnCode = 0; #ifdef _CRT_SET //Now just call this function at the start of your program and if you're //compiling in debug mode (F5), any leaks will be displayed in the Output //window when the program shuts down. If you're not in debug mode this will //be ignored. Use it as you will! //note: from GDNet Direct [3.8.04 - 3.14.04] void detectMemoryLeaks() { _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); _CrtSetReportMode(_CRT_ASSERT,_CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ASSERT,_CRTDBG_FILE_STDERR); #endif camera = new Camera(winWidth, winHeight, 60); camera->SetNear(nearDist); glutInitWindowSize(winWidth, winHeight); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutCreateWindow("Coherent Hierarchical Culling"); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutIdleFunc(display); InitExtensions(); InitGLstate(); leftMotion(0, 0); middleMotion(0, 0); BinaryLoader loader; //const string filename("data/city/model/city.dem"); const string filename = string(model_path + "city.dem"); if (loader.Load(filename, sceneEntities)) cout << "scene " << filename << " loaded" << endl; else { cerr << "loading scene " << filename << " failed" << endl; exit(0); } const string bvh_filename = string(model_path + "city.bvh"); BvhLoader bvhLoader; bvh = bvhLoader.Load(bvh_filename, sceneEntities); //bvh = bvhLoader.Load("data/city/model/city.bvh", sceneEntities); if (!bvh) { cerr << "loading bvh " << bvh_filename << " failed" << endl; exit(0); } bvh->SetCamera(camera); ResetTraverser(); camera->SetDirection(Vector3(0.961829f, 0.273652f, 0.0f)); camera->SetPosition(Vector3(483.398f, 242.364f, 186.078f)); visualization = new Visualization(bvh, camera, NULL, &state); glutMainLoop(); // clean up CleanUp(); return 0; } void InitGLstate(void) { glClearColor(0.5f, 0.5f, 0.8f, 0.0f); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT,1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); SetupLighting(); glColor3f(1.0f, 1.0f, 1.0f); glShadeModel(GL_SMOOTH); glMaterialf(GL_FRONT, GL_SHININESS, 64); glEnable(GL_NORMALIZE); //glEnable(GL_ALPHA_TEST); glDisable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.1f); glFrontFace(GL_CCW); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); //glDisable(GL_CULL_FACE); GLfloat ambientColor[] = {0.5, 0.5, 0.5, 1.0}; GLfloat diffuseColor[] = {1.0, 0.0, 0.0, 1.0}; GLfloat specularColor[] = {0.0, 0.0, 0.0, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor); glMaterialfv(GL_FRONT, GL_SPECULAR, specularColor); } void DrawHelpMessage(void) { const char *message[] = { "Help information", "", "'F1' - shows/dismisses this message", "", "'MOUSE-LEFT' - turn left/right, move forward/backward", "'MOUSE-RIGHT' - turn left/right, move forward/backward", "'MOUSE-MIDDLE' - move up/down, left/right", "'CURSOR UP' - move forward", "'CURSOR BACK' - move backward", "'CURSOR RIGHT' - turn right", "'CURSOR LEFT' - turn left", "", "'SPACE' - cycles through occlusion culling algorithms", "'-' - decreases max batch size", "'+' - increases max batch size", "'6' - decrease assumed visible frames", "'7' - increase assumed visible frames", "'8' - upward motion", "'9' - downward motion", "", "'R' - use render queue", "", "'S' - shows/hides statistics", "'V' - shows/hides bounding volumes", "", "'1' - shows/hides bird eye view", 0, }; int x = 40, y = 60; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0.0f, 1.0f , 0.0f, 0.2f); // 20% green. // Drawn clockwise because the flipped Y axis flips CCW and CW. glRecti(winWidth - 30, 30, 30, winHeight - 30); glDisable(GL_BLEND); glColor3f(1.0f, 1.0f, 1.0f); for(int i = 0; message[i] != 0; i++) { if(message[i][0] == '\0') { y += 15; } else { Output(x, y, message[i]); y += 20; } } } void ResetTraverser() { DEL_PTR(traverser); bvh->ResetNodeClassifications(); switch (renderMode) { case RenderTraverser::CULL_FRUSTUM: traverser = new FrustumCullingTraverser(); break; case RenderTraverser::STOP_AND_WAIT: traverser = new StopAndWaitTraverser(); break; case RenderTraverser::CHC: traverser = new CHCTraverser(); break; case RenderTraverser::CHCPLUSPLUS: traverser = new CHCPlusPlusTraverser(); break; default: traverser = new FrustumCullingTraverser(); } traverser->SetCamera(camera); traverser->SetHierarchy(bvh); traverser->SetRenderState(&state); traverser->SetUseOptimization(useOptimization); traverser->SetUseRenderQueue(useRenderQueue); traverser->SetVisibilityThreshold(threshold); traverser->SetAssumedVisibleFrames(assumedVisibleFrames); traverser->SetMaxBatchSize(maxBatchSize); traverser->SetUseMultiQueries(useMultiQueries); traverser->SetUseTightBounds(useTightBounds); } void SetupLighting() { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); //glDisable(GL_LIGHT1); //glDisable(GL_LIGHTING); //GLfloat ambient[] = {0.5, 0.5, 0.5, 1.0}; GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0}; GLfloat diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat lmodel_ambient[] = {0.5f, 0.5f, 0.5f, 1.0f}; //GLfloat lmodel_ambient[] = {0.2f, 0.2f, 0.2f, 1.0f}; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); GLfloat position[] = {1.0, 1.0, 1.0, 0.0}; glLightfv(GL_LIGHT0, GL_POSITION, position); //////////// //-- second light GLfloat ambient1[] = {0.5, 0.5, 0.5, 1.0}; //GLfloat diffuse1[] = {1.0, 1.0, 1.0, 1.0}; GLfloat diffuse1[] = {0.5, 0.5, 0.5, 1.0}; GLfloat specular1[] = {0.5, 0.5, 0.5, 1.0}; glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1); glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1); glLightfv(GL_LIGHT1, GL_SPECULAR, specular1); GLfloat position1[] = {0.0, 1.0, 0.0, 1.0}; glLightfv(GL_LIGHT1, GL_POSITION, position1); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); //glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); //glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SEPARATE_SPECULAR_COLOR_EXT); glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SINGLE_COLOR_EXT); } void SetupEyeView(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, 1.0f / winAspectRatio, nearDist, 2.0f * Magnitude(bvh->GetBox().Diagonal())); glMatrixMode(GL_MODELVIEW); camera->SetupCameraView(); GLfloat position[] = {0.8f, 1.0f, 1.5f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {bvh->GetBox().Center().x, bvh->GetBox().Max().y, bvh->GetBox().Center().z, 1.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // bring eye modelview matrix up-to-date SetupEyeView(); // actually render the scene geometry using one of the specified algorithms traverser->RenderScene(); if (visMode) DisplayVisualization(); DisplayStats(); glutSwapBuffers(); } #pragma warning( disable : 4100 ) void keyboard(const unsigned char c, const int x, const int y) { // used to avoid vertical motion with the keys Vector3 hvec = Vector3(camera->GetDirection()[0], camera->GetDirection()[1], 0.0f); Vector3 uvec = Vector3(0, 0, 1); switch(c) { case 27: exit(0); break; case 32: //space renderMode = (renderMode + 1) % RenderTraverser::NUM_RENDERMODES; ResetTraverser(); break; case 'h': case 'H': showHelp = !showHelp; break; case 'v': case 'V': showBoundingVolumes = !showBoundingVolumes; //HierarchyNode::SetRenderBoundingVolume(showBoundingVolumes); break; case 'O': case 'o': showStatistics = !showStatistics; break; case '+': maxBatchSize += 10; traverser->SetMaxBatchSize(maxBatchSize); break; case '-': maxBatchSize -= 10; if (maxBatchSize < 0) maxBatchSize = 1; traverser->SetMaxBatchSize(maxBatchSize); break; case '6': assumedVisibleFrames -= 1; if (assumedVisibleFrames < 1) assumedVisibleFrames = 1; traverser->SetAssumedVisibleFrames(assumedVisibleFrames); break; case '7': assumedVisibleFrames += 1; traverser->SetAssumedVisibleFrames(assumedVisibleFrames); break; case 'M': case 'm': useMultiQueries = !useMultiQueries; traverser->SetUseMultiQueries(useMultiQueries); break; case '1': visMode = !visMode; break; case '8': { Vector3 pos = camera->GetPosition(); pos += uvec * keyForwardMotion; camera->SetPosition(pos); break; } case '9': { Vector3 pos = camera->GetPosition(); pos -= uvec * keyForwardMotion; camera->SetPosition(pos); break; } case 'g': case 'G': useOptimization = !useOptimization; traverser->SetUseOptimization(useOptimization); break; case 'a': case 'A': { Vector3 viewDir = camera->GetDirection(); // rotate view vector Matrix4x4 rot = RotationZMatrix(keyRotation); viewDir = rot * viewDir; camera->SetDirection(viewDir); } break; case 'd': case 'D': { Vector3 viewDir = camera->GetDirection(); // rotate view vector Matrix4x4 rot = RotationZMatrix(-keyRotation); viewDir = rot * viewDir; camera->SetDirection(viewDir); } break; case 'w': case 'W': { Vector3 pos = camera->GetPosition(); pos += hvec * keyForwardMotion; camera->SetPosition(pos); } break; case 'x': case 'X': { Vector3 pos = camera->GetPosition(); pos -= hvec * keyForwardMotion; camera->SetPosition(pos); } break; case 'r': case 'R': { useRenderQueue = !useRenderQueue; traverser->SetUseRenderQueue(useRenderQueue); } case 'b': case 'B': { useTightBounds = !useTightBounds; traverser->SetUseTightBounds(useTightBounds); } default: return; } glutPostRedisplay(); } void special(int c, int x, int y) { // used to avoid vertical motion with the keys Vector3 hvec = Vector3(camera->GetDirection()[0], camera->GetDirection()[1], 0.0f); switch(c) { case GLUT_KEY_F1: showHelp = !showHelp; break; case GLUT_KEY_LEFT: { Vector3 viewDir = camera->GetDirection(); // rotate view vector Matrix4x4 rot = RotationZMatrix(keyRotation); viewDir = rot * viewDir; camera->SetDirection(viewDir); } break; case GLUT_KEY_RIGHT: { Vector3 viewDir = camera->GetDirection(); // rotate view vector Matrix4x4 rot = RotationZMatrix(-keyRotation); viewDir = rot * viewDir; camera->SetDirection(viewDir); } break; case GLUT_KEY_UP: { Vector3 pos = camera->GetPosition(); pos += hvec * 0.6f; camera->SetPosition(pos); } break; case GLUT_KEY_DOWN: { Vector3 pos = camera->GetPosition(); pos -= hvec * 0.6f; camera->SetPosition(pos); } break; default: return; } glutPostRedisplay(); } #pragma warning( default : 4100 ) void reshape(const int w, const int h) { winAspectRatio = 1.0f; glViewport(0, 0, w, h); winWidth = w; winHeight = h; if (w) winAspectRatio = (float) h / (float) w; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, 1.0f / winAspectRatio, nearDist, 2.0f * Magnitude(bvh->GetBox().Diagonal())); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) { xEyeBegin = x; yMotionBegin = y; glutMotionFunc(leftMotion); } else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) { yEyeBegin = y; yMotionBegin = y; glutMotionFunc(rightMotion); } else if ((button == GLUT_MIDDLE_BUTTON) && (state == GLUT_DOWN)) { horizontalMotionBegin = x; verticalMotionBegin = y; glutMotionFunc(middleMotion); } glutPostRedisplay(); } /** rotation for left/right mouse drag motion for up/down mouse drag */ void leftMotion(int x, int y) { static float eyeXAngle = 0.0f; Vector3 viewDir = camera->GetDirection(); Vector3 pos = camera->GetPosition(); // don't move in the vertical direction Vector3 horView(viewDir[0], viewDir[1], 0); eyeXAngle = 0.2f * M_PI * (xEyeBegin - x) / 180.0; rotation += eyeXAngle; // rotate view vector Matrix4x4 rot = RotationZMatrix(eyeXAngle); viewDir = rot * viewDir; pos += horView * (yMotionBegin - y) * 0.2f; camera->SetDirection(viewDir); camera->SetPosition(pos); xEyeBegin = x; yMotionBegin = y; glutPostRedisplay(); } /** rotation for left / right mouse drag motion for up / down mouse drag */ void rightMotion(int x, int y) { static float eyeYAngle = 0.0f; Vector3 viewDir = camera->GetDirection(); Vector3 right = camera->GetRightVector(); eyeYAngle = -0.2f * M_PI * (yEyeBegin - y) / 180.0; // rotate view vector Matrix4x4 rot = RotationAxisMatrix(right, eyeYAngle); viewDir = rot * viewDir; camera->SetDirection(viewDir); yEyeBegin = y; glutPostRedisplay(); } // strafe void middleMotion(int x, int y) { Vector3 viewDir = camera->GetDirection(); Vector3 pos = camera->GetPosition(); // the 90 degree rotated view vector // y zero so we don't move in the vertical Vector3 rVec(viewDir[0], viewDir[1], 0); Matrix4x4 rot = RotationZMatrix(M_PI * 0.5f); rVec = rot * rVec; pos -= rVec * (x - horizontalMotionBegin) * 0.1f; pos[2] += (verticalMotionBegin - y) * 0.1f; camera->SetPosition(pos); horizontalMotionBegin = x; verticalMotionBegin = y; glutPostRedisplay(); } void InitExtensions(void) { GLenum err = glewInit(); if (GLEW_OK != err) { // problem: glewInit failed, something is seriously wrong fprintf(stderr,"Error: %s\n", glewGetErrorString(err)); exit(1); } if (!GLEW_ARB_occlusion_query) { printf("I require the GL_ARB_occlusion_query to work.\n"); exit(1); } } void begin2D(void) { glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0, winWidth, winHeight, 0); } void end2D(void) { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); } void Output(int x, int y, const char *string) { if (string != 0) { size_t len, i; glRasterPos2f(x, y); len = strlen(string); for (i = 0; i < len; ++ i) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, string[i]); } } } // displays the visualisation of culling algorithm void DisplayVisualization() { setupVisView(); visualization->SetFrameId(traverser->GetCurrentFrameId()); begin2D(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(0.0,0.0,0.0,0.5); glRecti(winWidth, 0, winWidth - winWidth / 4, winHeight / 3); glDisable(GL_BLEND); end2D(); glViewport(winWidth - winWidth / 4, winHeight - winHeight / 3, winWidth, winHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //gluPerspective(60.0f, 1.0f / winAspectRatio, nearDist, 2.0f * Magnitude(bvh->GetBox().Diagonal())); AxisAlignedBox3 box = bvh->GetBox(); const float offs = 2000; glOrtho(box.Min().y - offs, box.Max().y + offs, box.Min().y - offs, box.Max().y + offs, 0.1, 20.0f * Magnitude(bvh->GetBox().Diagonal())); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMultMatrixf((float *)visView.x); //SetupLighting(); GLfloat position[] = {0.8f, 1.0f, 1.5f, 0.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); GLfloat position1[] = {bvh->GetBox().Center().x, bvh->GetBox().Max().y, bvh->GetBox().Center().z, 1.0f}; glLightfv(GL_LIGHT1, GL_POSITION, position1); glClear(GL_DEPTH_BUFFER_BIT); //////////// //-- visualization of the occlusion culling visualization->Render(); glPopMatrix(); glViewport(0, 0, winWidth, winHeight); } /** Sets up view matrix for bird eye view */ void setupVisView() { Vector3 pos(-bvh->GetBox().Center()); pos.z = -15.0f * bvh->GetBox().Size().z; pos.y += 1400; pos.x -= 1170; Vector3 dir(0, 0, 1); Vector3 up(0, 1, 0); Vector3 left = Normalize(CrossProd(dir, up)); up = Normalize(CrossProd(left, dir)); visView = Matrix4x4(up, left, dir); pos = visView * pos; visView.x[3][0] = pos.x; visView.x[3][1] = pos.y; visView.x[3][2] = pos.z; //cout << visView<< endl; } // cleanup routine after the main loop void CleanUp() { CLEAR_CONTAINER(sceneEntities); DEL_PTR(traverser); DEL_PTR(bvh); DEL_PTR(visualization); DEL_PTR(camera); } // this function inserts a dezimal point after each 1000 void CalcDecimalPoint(string &str, int d) { vector numbers; char hstr[100]; while (d != 0) { numbers.push_back(d % 1000); d /= 1000; } // first element without leading zeros if (numbers.size() > 0) { sprintf_s(hstr, "%d", numbers.back()); str.append(hstr); } for (int i = (int)numbers.size() - 2; i >= 0; i--) { sprintf_s(hstr, ",%03d", numbers[i]); str.append(hstr); } } void DisplayStats() { char *msg[] = {"Frustum Culling", "Stop and Wait", "CHC", "CHC ++"}; char msg2[400]; char msg3[200]; char msg4[200]; char msg5[200]; char msg6[200]; static double renderTime = traverser->GetStats().mRenderTime; const float expFactor = 0.3f; renderTime = traverser->GetStats().mRenderTime * expFactor + (1.0f - expFactor) * renderTime; accumulatedTime += renderTime; if (accumulatedTime > 500) // update every fraction of a second { accumulatedTime = 0; if (renderTime) fps = 1e3f / (float)renderTime; renderedObjects = traverser->GetStats().mNumRenderedGeometry; renderedNodes = traverser->GetStats().mNumRenderedNodes; renderedTriangles = traverser->GetStats().mNumRenderedTriangles; traversedNodes = traverser->GetStats().mNumTraversedNodes; frustumCulledNodes = traverser->GetStats().mNumFrustumCulledNodes; queryCulledNodes = traverser->GetStats().mNumQueryCulledNodes; issuedQueries = traverser->GetStats().mNumIssuedQueries; stateChanges = traverser->GetStats().mNumStateChanges; } sprintf_s(msg2, "assumed visible frames: %4d, max batch size: %4d, using render queue: %d", assumedVisibleFrames, maxBatchSize, useRenderQueue); string str; string str2; CalcDecimalPoint(str, renderedTriangles); CalcDecimalPoint(str2, bvh->GetBvhStats().mTriangles); sprintf_s(msg3, "rendered nodes: %6d (of %6d), rendered triangles: %s (of %s)", renderedNodes, bvh->GetNumVirtualNodes(), str.c_str(), str2.c_str()); sprintf_s(msg4, "traversed: %5d, frustum culled: %5d, query culled: %5d", traversedNodes, frustumCulledNodes, queryCulledNodes); sprintf_s(msg5, "issued queries: %5d, state changes: %5d", issuedQueries, stateChanges); sprintf_s(msg6, "fps: %6.1f", fps); //cout << "previously visible node queries: " << traverser->GetStats().mNumPreviouslyVisibleNodeQueries << endl; begin2D(); if(showHelp) { DrawHelpMessage(); } else { glColor3f(1.0f, 1.0f, 1.0f); Output(850, 30, msg[renderMode]); if (showStatistics) { Output(20, 30, msg2); Output(20, 60, msg3); Output(20, 90, msg4); Output(20, 120, msg5); Output(20, 150, msg6); } } end2D(); }