source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/chcdemo.cpp @ 3010

Revision 3010, 50.7 KB checked in by mattausch, 16 years ago (diff)
Line 
1// chcdemo.cpp : Defines the entry point for the console application.
2//
3#include "glInterface.h"
4#include <math.h>
5#include <time.h>
6#include "common.h"
7#include "RenderTraverser.h"
8#include "SceneEntity.h"
9#include "Vector3.h"
10#include "Matrix4x4.h"
11#include "ResourceManager.h"
12#include "Bvh.h"
13#include "Camera.h"
14#include "Geometry.h"
15#include "BvhLoader.h"
16#include "FrustumCullingTraverser.h"
17#include "StopAndWaitTraverser.h"
18#include "CHCTraverser.h"
19#include "CHCPlusPlusTraverser.h"
20#include "Visualization.h"
21#include "RenderState.h"
22#include "Timer/PerfTimer.h"
23#include "SceneQuery.h"
24#include "RenderQueue.h"
25#include "Material.h"
26#include <Cg/cg.h>
27#include <Cg/cgGL.h>
28#include "glfont2.h"
29#include "PerformanceGraph.h"
30#include "Environment.h"
31#include "Halton.h"
32#include "Transform3.h"
33#include "SampleGenerator.h"
34#include "FrameBufferObject.h"
35#include "DeferredRenderer.h"
36#include "ShadowMapping.h"
37#include "Light.h"
38#include "SceneEntityConverter.h"
39#include "ObjConverter.h"
40#include "SkyPreetham.h"
41#include "Texture.h"
42#include "EntityMerger.h"
43
44
45
46using namespace std;
47using namespace CHCDemoEngine;
48
49
50static Environment env;
51
52#define MAX_DEPTH_CONST 10.0f
53
54// fbo
55FrameBufferObject *fbo = NULL;
56
57GLuint fontTex;
58
59/// the renderable scene geometry
60SceneEntityContainer sceneEntities;
61// traverses and renders the hierarchy
62RenderTraverser *traverser = NULL;
63/// the hierarchy
64Bvh *bvh = NULL;
65/// handles scene loading
66ResourceManager *loader = NULL;
67/// the scene camera
68Camera *camera = NULL;
69/// the scene camera
70Camera *visCamera = NULL;
71/// the visualization
72Visualization *visualization = NULL;
73/// the current render state
74RenderState state;
75/// the rendering algorithm
76int renderMode = RenderTraverser::CHCPLUSPLUS;
77// eye near plane distance
78float nearDist = 0.2f;
79float farDist = 1e6f;
80/// the field of view
81float fov = 50.0f;
82/// the pixel threshold where a node is still considered invisible
83int threshold;
84
85int assumedVisibleFrames = 10;
86int maxBatchSize = 50;
87
88int trianglesPerVirtualLeaf = INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES;
89
90SceneQuery *sceneQuery = NULL;
91RenderQueue *renderQueue = NULL;
92
93// traverses and renders the hierarchy
94RenderTraverser *shadowTraverser = NULL;
95
96SkyPreetham *preetham = NULL;
97
98/// the used render type for this render pass
99enum RenderMethod
100{
101        RENDER_FIXED,
102        RENDER_DEPTH_PASS,
103        RENDER_DEFERRED,
104        RENDER_DEPTH_PASS_DEFERRED,
105        RENDER_NUM_RENDER_TYPES
106};
107
108/// one of four possible render methods
109int renderMethod = RENDER_FIXED;
110
111
112/// these values get scaled with the frame rate
113static float keyForwardMotion = 30.0f;
114static float keyRotation = 1.5f;
115
116/// elapsed time in milliseconds
117double elapsedTime = 1000.0f;
118double algTime = 1000.0f;
119
120static int winWidth = 1024;
121static int winHeight = 768;
122
123int shadowSize = 2048;
124
125static float winAspectRatio = 1.0f;
126
127double accumulatedTime = 1000;
128float fps = 1e3f;
129
130glfont::GLFont myfont;
131
132// rendertexture
133static int texWidth = 1024;
134static int texHeight = 768;
135
136int renderedObjects = 0;
137int renderedNodes = 0;
138int renderedTriangles = 0;
139
140int issuedQueries = 0;
141int traversedNodes = 0;
142int frustumCulledNodes = 0;
143int queryCulledNodes = 0;
144int stateChanges = 0;
145int numBatches = 0;
146
147
148// mouse navigation state
149int xEyeBegin = 0;
150int yEyeBegin = 0;
151int yMotionBegin = 0;
152int verticalMotionBegin = 0;
153int horizontalMotionBegin = 0;
154
155
156bool leftKeyPressed = false;
157bool rightKeyPressed = false;
158bool upKeyPressed = false;
159bool downKeyPressed = false;
160bool descendKeyPressed = false;
161bool ascendKeyPressed = false;
162
163bool showHelp = false;
164bool showStatistics = false;
165bool showOptions = true;
166bool showBoundingVolumes = false;
167bool visMode = false;
168
169bool useOptimization = false;
170bool useTightBounds = true;
171bool useRenderQueue = true;
172bool useMultiQueries = true;
173bool flyMode = true;
174
175bool useGlobIllum = false;
176bool useTemporalCoherence = true;
177bool showAlgorithmTime = false;
178
179bool useFullScreen = false;
180bool useLODs = true;
181bool moveLight = false;
182
183bool useAdvancedShading = false;
184bool showShadowMap = false;
185bool renderLightView = false;
186
187bool altKeyPressed = false;
188
189bool useHDR = true;
190
191static float ssaoTempCohFactor = 255.0;
192
193
194PerfTimer frameTimer, algTimer;
195
196static int sCurrentMrtSet = 0;
197
198PerformanceGraph *perfGraph = NULL;
199
200
201//DeferredRenderer::SAMPLING_METHOD samplingMethod = DeferredRenderer::SAMPLING_POISSON;
202DeferredRenderer::SAMPLING_METHOD samplingMethod = DeferredRenderer::SAMPLING_QUADRATIC;
203
204ShadowMap *shadowMap = NULL;
205DirectionalLight *light = NULL;
206DeferredRenderer *ssaoShader = NULL;
207
208SceneEntity *cube = NULL;
209SceneEntity *aeroplane = NULL;
210SceneEntity *skyDome = NULL;
211
212
213
214// function forward declarations
215void InitExtensions();
216void DisplayVisualization();
217void InitGLstate();
218void InitRenderTexture();
219void InitCg();
220void CleanUp();
221void SetupEyeView();
222void UpdateEyeMtx();
223void SetupLighting();
224void DisplayStats();
225void Output(int x, int y, const char *string);
226void DrawHelpMessage();
227void RenderSky();
228void RenderVisibleObjects();
229
230void Begin2D();
231void End2D();
232void KeyBoard(unsigned char c, int x, int y);
233void DrawStatistics();
234void Display();
235void Special(int c, int x, int y);
236void KeyUp(unsigned char c, int x, int y);
237void SpecialKeyUp(int c, int x, int y);
238void Reshape(int w, int h);
239void Mouse(int button, int state, int x, int y);
240void LeftMotion(int x, int y);
241void RightMotion(int x, int y);
242void MiddleMotion(int x, int y);
243void CalcDecimalPoint(string &str, int d);
244
245RenderTraverser *CreateTraverser(Camera *cam);
246
247void KeyHorizontalMotion(float shift);
248void KeyVerticalMotion(float shift);
249
250void PlaceViewer(const Vector3 &oldPos);
251
252inline float KeyRotationAngle() { return keyRotation * elapsedTime * 1e-3f; }
253inline float KeyShift() { return keyForwardMotion * elapsedTime * 1e-3f; }
254
255void InitFBO();
256
257void RightMotionLight(int x, int y);
258
259void RenderShadowMap(float newfar);
260
261
262
263/////////
264//-- cg stuff
265
266static CGcontext sCgContext = NULL;
267static CGprogram sCgMrtVertexProgram = NULL;
268
269static CGparameter sMaxDepthParam;
270static CGparameter sMaxDepthParamTex;
271static CGparameter sEyePosParamTex;
272static CGparameter sEyePosParam;
273
274static CGparameter sTLParam;
275static CGparameter sTRParam;
276static CGparameter sBRParam;
277static CGparameter sBLParam;
278
279static CGparameter sTLParamTex;
280static CGparameter sTRParamTex;
281static CGparameter sBRParamTex;
282static CGparameter sBLParamTex;
283
284static Matrix4x4 viewProjMat = IdentityMatrix();
285static Matrix4x4 oldViewProjMat = IdentityMatrix();
286
287
288
289static void cgErrorCallback()
290{
291        CGerror lastError = cgGetError();
292
293        if(lastError)
294        {
295                printf("%s\n\n", cgGetErrorString(lastError));
296                printf("%s\n", cgGetLastListing(sCgContext));
297               
298                printf("Cg error, exiting...\n");
299
300                exit(0);
301        }
302}
303
304
305static void PrintGLerror(char *msg)
306{
307        GLenum errCode;
308        const GLubyte *errStr;
309       
310        if ((errCode = glGetError()) != GL_NO_ERROR)
311        {
312                errStr = gluErrorString(errCode);
313                fprintf(stderr,"OpenGL ERROR: %s: %s\n", errStr, msg);
314        }
315}
316
317
318int main(int argc, char* argv[])
319{
320        int returnCode = 0;
321
322        Vector3 camPos(.0f, .0f, .0f);
323        Vector3 camDir(.0f, 1.0f, .0f);
324        Vector3 lightDir(-0.8f, 1.0f, -0.7f);
325
326        cout << "=== reading environment file ===" << endl << endl;
327
328        string envFileName = "default.env";
329        if (!env.Read(envFileName))
330        {
331                cerr << "loading environment " << envFileName << " failed!" << endl;
332        }
333        else
334        {
335                env.GetIntParam(string("assumedVisibleFrames"), assumedVisibleFrames);
336                env.GetIntParam(string("maxBatchSize"), maxBatchSize);
337                env.GetIntParam(string("trianglesPerVirtualLeaf"), trianglesPerVirtualLeaf);
338
339                env.GetFloatParam(string("keyForwardMotion"), keyForwardMotion);
340                env.GetFloatParam(string("keyRotation"), keyRotation);
341
342                env.GetIntParam(string("winWidth"), winWidth);
343                env.GetIntParam(string("winHeight"), winHeight);
344
345                env.GetBoolParam(string("useFullScreen"), useFullScreen);
346                env.GetFloatParam(string("tempCohFactor"), ssaoTempCohFactor);
347                env.GetVectorParam(string("camPosition"), camPos);
348                env.GetVectorParam(string("camDirection"), camDir);
349                env.GetVectorParam(string("lightDirection"), lightDir);
350
351                env.GetBoolParam(string("useLODs"), useLODs);
352                env.GetIntParam(string("shadowSize"), shadowSize);
353
354                env.GetBoolParam(string("useHDR"), useHDR);
355
356                //env.GetStringParam(string("modelPath"), model_path);
357                //env.GetIntParam(string("numSssaoSamples"), numSsaoSamples);
358
359
360                cout << "assumedVisibleFrames: " << assumedVisibleFrames << endl;
361                cout << "maxBatchSize: " << maxBatchSize << endl;
362                cout << "trianglesPerVirtualLeaf: " << trianglesPerVirtualLeaf << endl;
363
364                cout << "keyForwardMotion: " << keyForwardMotion << endl;
365                cout << "keyRotation: " << keyRotation << endl;
366                cout << "winWidth: " << winWidth << endl;
367                cout << "winHeight: " << winHeight << endl;
368                cout << "useFullScreen: " << useFullScreen << endl;
369                cout << "useLODs: " << useLODs << endl;
370                cout << "camPosition: " << camPos << endl;
371                cout << "temporal coherence: " << ssaoTempCohFactor << endl;
372                cout << "shadow size: " << shadowSize << endl;
373
374                //cout << "model path: " << model_path << endl;
375
376                cout << "**** end parameters ****" << endl << endl;
377        }
378
379        ///////////////////////////
380
381        camera = new Camera(winWidth, winHeight, fov);
382        camera->SetNear(nearDist);
383        camera->SetFar(1000);
384
385        camera->SetDirection(camDir);
386        camera->SetPosition(camPos);
387
388        visCamera = new Camera(winWidth, winHeight, fov);
389        visCamera->SetNear(0.0f);
390        visCamera->Yaw(.5 * M_PI);
391
392        // create a new light
393        light = new DirectionalLight(lightDir, RgbaColor(1, 1, 1, 1), RgbaColor(1, 1, 1, 1));
394
395
396        renderQueue = new RenderQueue(&state, camera);
397
398        glutInitWindowSize(winWidth, winHeight);
399        glutInit(&argc, argv);
400        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_MULTISAMPLE);
401        //glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
402        //glutInitDisplayString("samples=2");
403
404        SceneEntity::SetUseLODs(useLODs);
405
406
407        if (!useFullScreen)
408        {
409                glutCreateWindow("FriendlyCulling");
410        }
411        else
412        {
413                glutGameModeString( "1024x768:32@75" );
414                glutEnterGameMode();
415        }
416
417        glutDisplayFunc(Display);
418        glutKeyboardFunc(KeyBoard);
419        glutSpecialFunc(Special);
420        glutReshapeFunc(Reshape);
421        glutMouseFunc(Mouse);
422        glutIdleFunc(Display);
423        glutKeyboardUpFunc(KeyUp);
424        glutSpecialUpFunc(SpecialKeyUp);
425        glutIgnoreKeyRepeat(true);
426
427        // initialise gl graphics
428        InitExtensions();
429        InitGLstate();
430
431
432        glEnable(GL_MULTISAMPLE_ARB);
433        glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
434
435        LeftMotion(0, 0);
436        MiddleMotion(0, 0);
437
438        perfGraph = new PerformanceGraph(1000);
439
440        loader = new ResourceManager();
441
442        //const string filename("data/city/model/city.dem");
443        const string filename = string(model_path + "city.dem");
444
445        if (loader->Load(filename, sceneEntities))
446                cout << "scene " << filename << " loaded" << endl;
447        else
448        {
449                cerr << "loading scene " << filename << " failed" << endl;
450                CleanUp();
451                exit(0);
452        }
453
454        const string bvh_filename = string(model_path + "city.bvh");
455        BvhLoader bvhLoader;
456        bvh = bvhLoader.Load(bvh_filename, sceneEntities);
457
458        if (!bvh)
459        {
460                cerr << "loading bvh " << bvh_filename << " failed" << endl;
461                CleanUp();
462                exit(0);
463        }
464       
465#if 0
466
467        int merged = 0;
468
469        SceneEntity *oldEnt = NULL;
470
471        cout << "merging entities .. " << endl;
472        SceneEntityContainer::const_iterator sit, sit_end = sceneEntities.end();
473
474        for (sit = sceneEntities.begin(); sit < sit_end; ++ sit)
475        {
476                SceneEntity *newEnt = (*sit);
477
478                if (!newEnt->GetTransform()->IsIdentity())
479                {
480                        sceneEntities2.push_back(newEnt);
481                        continue;
482                }
483
484                if (oldEnt)
485                {
486                        EntityMerger merger(newEnt, oldEnt);
487                        SceneEntity *ent = merger.Merge();
488
489                        sceneEntities2.push_back(ent);
490
491                        oldEnt = NULL;
492
493                        ++ merged;
494                }
495                else
496                {
497                        oldEnt = newEnt;
498                }
499        }
500
501        if (oldEnt && oldEnt->GetTransform()->IsIdentity())
502                sceneEntities2.push_back(oldEnt);
503
504        cout << "merged " << merged << " of " << (int)sceneEntities.size() << " entities " << endl;
505#endif
506
507        // set far plane based on scene extent
508        farDist = 10.0f * Magnitude(bvh->GetBox().Diagonal());
509        bvh->SetVirtualLeaves(trianglesPerVirtualLeaf);
510
511        camera->SetFar(Magnitude(bvh->GetBox().Diagonal()));
512       
513        InitCg();
514
515        DeferredRenderer::Init(sCgContext);
516        SkyPreetham::Init(sCgContext);
517
518        Vector3 cubeCenter(470.398f, 240.364f, 182.5f);
519       
520        Matrix4x4 transl = TranslationMatrix(cubeCenter);
521       
522
523        SceneEntityContainer dummy;
524       
525        string skyDomeStr(model_path + "sky.dem");
526
527        if (loader->Load(skyDomeStr, dummy))
528                cout << "successfully loaded " << dummy.size() << " scene entities" << endl;
529        else
530        {
531                cerr << "loading file " << skyDomeStr << " failed" << endl;
532
533                CleanUp();
534                exit(0);
535        }
536
537        skyDome = dummy[0];
538
539
540        const float turbitiy = 5.0f;
541        preetham = new SkyPreetham(turbitiy, skyDome);
542
543        // initialize the render traverser
544        traverser = CreateTraverser(camera);
545
546        visualization = new Visualization(bvh, camera, NULL, &state);
547       
548        state.SetRenderPassType(RenderState::FIXED);
549        sceneQuery = new SceneQuery(bvh->GetBox(), traverser);
550
551        // frame time is restarted every frame
552        frameTimer.Start();
553
554        // the rendering loop
555        glutMainLoop();
556
557        // clean up
558        CleanUp();
559
560        return 0;
561}
562
563
564void InitCg(void)
565{
566        // Setup Cg
567        cgSetErrorCallback(cgErrorCallback);
568
569        // Create cgContext.
570        sCgContext = cgCreateContext();
571
572        // get the best profile for this hardware
573        RenderState::sCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
574        cgGLSetOptimalOptions(RenderState::sCgFragmentProfile);
575
576        RenderState::sCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
577        cgGLSetOptimalOptions(RenderState::sCgVertexProfile);
578
579        sCgMrtVertexProgram =
580                cgCreateProgramFromFile(sCgContext,
581                                                                CG_SOURCE,
582                                                                "src/shaders/mrt.cg",
583                                                                RenderState::sCgVertexProfile,
584                                                                "vtx",
585                                                                NULL);
586
587        if (sCgMrtVertexProgram != NULL)
588        {
589                cgGLLoadProgram(sCgMrtVertexProgram);
590
591                //sInvViewProjParam = cgGetNamedParameter(sCgMrtVertexProgram, "InvViewProj");
592                Transform3::sModelMatrixParam = cgGetNamedParameter(sCgMrtVertexProgram, "ModelView");
593        }
594
595        RenderState::sCgMrtFragmentTexProgram =
596                cgCreateProgramFromFile(sCgContext,
597                                                                CG_SOURCE,
598                                                                "src/shaders/mrt.cg",
599                                                                RenderState::sCgFragmentProfile,
600                                                                "fragtex",
601                                                                NULL);
602
603        if (RenderState::sCgMrtFragmentTexProgram != NULL)
604        {
605                cgGLLoadProgram(RenderState::sCgMrtFragmentTexProgram);
606
607                sMaxDepthParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "maxDepth");
608                sEyePosParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "eyePos");
609                RenderState::sTexParam = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "tex");
610       
611                cgGLSetParameter1f(sMaxDepthParamTex, MAX_DEPTH_CONST / farDist);
612
613                sTLParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "tl");
614                sTRParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "tr");
615                sBRParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "br");
616                sBLParamTex = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "bl");
617        }
618        else
619                cerr << "fragment tex program failed to load" << endl;
620
621        RenderState::sCgMrtFragmentProgram =
622                cgCreateProgramFromFile(sCgContext,
623                                                                CG_SOURCE,
624                                                                "src/shaders/mrt.cg",
625                                                                RenderState::sCgFragmentProfile,
626                                                                "frag",
627                                                                NULL);
628
629        if (RenderState::sCgMrtFragmentProgram != NULL)
630        {
631                cgGLLoadProgram(RenderState::sCgMrtFragmentProgram);
632
633                sMaxDepthParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "maxDepth");
634                sEyePosParam = cgGetNamedParameter(RenderState::sCgMrtFragmentTexProgram, "eyePos");
635               
636                cgGLSetParameter1f(sMaxDepthParam, MAX_DEPTH_CONST / farDist);
637
638                sTLParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "tl");
639                sTRParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "tr");
640                sBRParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "br");
641                sBLParam = cgGetNamedParameter(RenderState::sCgMrtFragmentProgram, "bl");
642        }
643        else
644                cerr << "fragment program failed to load" << endl;
645       
646
647        PrintGLerror("init");
648
649        cout << "cg initialization successful" << endl;
650}
651
652
653void InitFBO()
654{
655        PrintGLerror("fbo start");
656
657        // this fbo basicly stores the scene information we get from standard rendering of a frame
658        // we store colors, normals, positions (for the ssao)
659        fbo = new FrameBufferObject(texWidth, texHeight, FrameBufferObject::DEPTH_32);
660        //fbo = new FrameBufferObject(texWidth, texHeight, FrameBufferObject::DEPTH_24);
661
662        // the diffuse color buffer
663        fbo->AddColorBuffer(ColorBufferObject::RGBA_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST, ColorBufferObject::FILTER_NEAREST);
664        // the normals buffer
665        fbo->AddColorBuffer(ColorBufferObject::RGBA_FLOAT_16, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST);
666        // the positions buffer
667        //fbo->AddColorBuffer(ColorBufferObject::RGBA_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST);
668        fbo->AddColorBuffer(ColorBufferObject::RGB_UBYTE, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST);
669        // another color buffer
670        fbo->AddColorBuffer(ColorBufferObject::RGBA_FLOAT_32, ColorBufferObject::WRAP_CLAMP_TO_EDGE, ColorBufferObject::FILTER_NEAREST, ColorBufferObject::FILTER_NEAREST);
671
672        PrintGLerror("fbo");
673}
674
675
676bool InitFont(void)
677{
678        glEnable(GL_TEXTURE_2D);
679
680        glGenTextures(1, &fontTex);
681        glBindTexture(GL_TEXTURE_2D, fontTex);
682        if (!myfont.Create("data/fonts/verdana.glf", fontTex))
683                return false;
684
685        glDisable(GL_TEXTURE_2D);
686       
687        return true;
688}
689
690
691void InitGLstate()
692{
693        glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
694       
695        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
696        glPixelStorei(GL_PACK_ALIGNMENT,1);
697       
698        glDepthFunc(GL_LESS);
699        glEnable(GL_DEPTH_TEST);
700
701        glColor3f(1.0f, 1.0f, 1.0f);
702        glShadeModel(GL_SMOOTH);
703       
704        glMaterialf(GL_FRONT, GL_SHININESS, 64);
705        glEnable(GL_NORMALIZE);
706               
707        glDisable(GL_ALPHA_TEST);
708        glAlphaFunc(GL_GEQUAL, 0.5f);
709
710        glFrontFace(GL_CCW);
711        glCullFace(GL_BACK);
712        glEnable(GL_CULL_FACE);
713
714        glDisable(GL_TEXTURE_2D);
715
716        GLfloat ambientColor[] = {0.2, 0.2, 0.2, 1.0};
717        GLfloat diffuseColor[] = {1.0, 0.0, 0.0, 1.0};
718        GLfloat specularColor[] = {0.0, 0.0, 0.0, 1.0};
719
720        glMaterialfv(GL_FRONT, GL_AMBIENT, ambientColor);
721        glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseColor);
722        glMaterialfv(GL_FRONT, GL_SPECULAR, specularColor);
723
724        glDepthFunc(GL_LESS);
725
726        if (!InitFont())
727                cerr << "font creation failed" << endl;
728        else
729                cout << "successfully created font" << endl;
730
731
732        //////////////////////////////
733
734        //GLfloat lmodel_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
735        GLfloat lmodel_ambient[] = {0.7f, 0.7f, 0.8f, 1.0f};
736
737        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
738        //glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
739        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
740        glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, GL_SINGLE_COLOR_EXT);
741}
742
743
744void DrawHelpMessage()
745{
746        const char *message[] =
747        {
748                "Help information",
749                "",
750                "'F1'           - shows/dismisses this message",
751                "'F2'           - shows/hides bird eye view",
752                "'F3'           - shows/hides bounds (boxes or tight bounds)",
753                "'F4',          - shows/hides parameters",
754                "'F5'           - shows/hides statistics",
755                "'F6',          - toggles between fly/walkmode",
756                "'F7',          - cycles throw render modes",
757                "'F8',          - enables/disables ambient occlusion (only deferred)",
758                "'F9',          - shows pure algorithm render time (using glFinish)",
759                "'SPACE'        - cycles through occlusion culling algorithms",
760                "",
761                "'MOUSE LEFT'        - turn left/right, move forward/backward",
762                "'MOUSE RIGHT'       - turn left/right, move forward/backward",
763                "'MOUSE MIDDLE'      - move up/down, left/right",
764                "'CURSOR UP/DOWN'    - move forward/backward",
765                "'CURSOR LEFT/RIGHT' - turn left/right",
766                "",
767                "'-'/'+'        - decreases/increases max batch size",
768                "'1'/'2'        - downward/upward motion",
769                "'3'/'4'        - decreases/increases triangles per virtual bvh leaf (sets bvh depth)",
770                "'5'/'6'        - decreases/increases assumed visible frames",
771                "",
772                "'R'            - use render queue",
773                "'B'            - use tight bounds",
774                "'M'            - use multiqueries",
775                "'O'            - use CHC optimization (geometry queries for leaves)",
776                0,
777        };
778       
779       
780        glColor4f(0.0f, 1.0f , 0.0f, 0.2f); // 20% green.
781
782        glRecti(30, 30, winWidth - 30, winHeight - 30);
783
784        glEnd();
785
786        glColor3f(1.0f, 1.0f, 1.0f);
787       
788        glEnable(GL_TEXTURE_2D);
789        myfont.Begin();
790
791        int x = 40, y = 30;
792
793        for(int i = 0; message[i] != 0; ++ i)
794        {
795                if(message[i][0] == '\0')
796                {
797                        y += 15;
798                }
799                else
800                {
801                        myfont.DrawString(message[i], x, winHeight - y);
802                        y += 25;
803                }
804        }
805        glDisable(GL_TEXTURE_2D);
806}
807
808
809RenderTraverser *CreateTraverser(Camera *cam)
810{
811        RenderTraverser *tr;
812       
813        bvh->ResetNodeClassifications();
814
815        switch (renderMode)
816        {
817        case RenderTraverser::CULL_FRUSTUM:
818                tr = new FrustumCullingTraverser();
819                break;
820        case RenderTraverser::STOP_AND_WAIT:
821                tr = new StopAndWaitTraverser();
822                break;
823        case RenderTraverser::CHC:
824                tr = new CHCTraverser();
825                break;
826        case RenderTraverser::CHCPLUSPLUS:
827                tr = new CHCPlusPlusTraverser();
828                break;
829       
830        default:
831                tr = new FrustumCullingTraverser();
832        }
833
834        tr->SetCamera(cam);
835        tr->SetHierarchy(bvh);
836        tr->SetRenderQueue(renderQueue);
837        tr->SetRenderState(&state);
838        tr->SetUseOptimization(useOptimization);
839        tr->SetUseRenderQueue(useRenderQueue);
840        tr->SetVisibilityThreshold(threshold);
841        tr->SetAssumedVisibleFrames(assumedVisibleFrames);
842        tr->SetMaxBatchSize(maxBatchSize);
843        tr->SetUseMultiQueries(useMultiQueries);
844        tr->SetUseTightBounds(useTightBounds);
845        tr->SetUseDepthPass((renderMethod == RENDER_DEPTH_PASS) || (renderMethod == RENDER_DEPTH_PASS_DEFERRED));
846        tr->SetRenderQueue(renderQueue);
847
848        return tr;
849}
850
851
852void SetupLighting()
853{
854        glEnable(GL_LIGHT0);
855        glDisable(GL_LIGHT1);
856       
857        Vector3 lightDir = -light->GetDirection();
858
859
860        ///////////
861        //-- first light: sunlight
862
863        GLfloat ambient[] = {0.25f, 0.25f, 0.3f, 1.0f};
864        GLfloat diffuse[] = {1.0f, 0.95f, 0.85f, 1.0f};
865        GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
866       
867
868        const bool useToneMapping = ((renderMethod == RENDER_DEPTH_PASS_DEFERRED) || (renderMethod == RENDER_DEFERRED)) && useHDR;
869
870        Vector3 sunAmbient;
871        Vector3 sunDiffuse;
872
873        preetham->ComputeSunColor(lightDir, sunAmbient, sunDiffuse, !useToneMapping);
874
875        ambient[0] = sunAmbient.x;
876        ambient[1] = sunAmbient.y;
877        ambient[2] = sunAmbient.z;
878
879        // no tone mapping => scale
880        if (!useToneMapping)
881        {
882                const float maxComponent = sunDiffuse.MaxComponent();
883                sunDiffuse /= maxComponent;
884        }
885
886        diffuse[0] = sunDiffuse.x;
887        diffuse[1] = sunDiffuse.y;
888        diffuse[2] = sunDiffuse.z;
889
890        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
891        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
892        glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
893
894        GLfloat position[] = {lightDir.x, lightDir.y, lightDir.z, 0.0f};
895        glLightfv(GL_LIGHT0, GL_POSITION, position);
896}
897
898
899void SetupEyeView()
900{
901        // store matrix of last frame
902        oldViewProjMat = viewProjMat;
903
904        glMatrixMode(GL_PROJECTION);
905        glLoadIdentity();
906        gluPerspective(fov, winAspectRatio, nearDist, farDist);
907
908        glMatrixMode(GL_MODELVIEW);
909       
910        // set up the camera view
911        camera->SetupCameraView();
912
913               
914        /////////////////
915
916        Matrix4x4 matViewing, matProjection;
917
918        camera->GetModelViewMatrix(matViewing);
919        camera->GetProjectionMatrix(matProjection);
920
921        // store matrix for later use
922        viewProjMat = matViewing * matProjection;
923       
924        if ((renderMethod == RENDER_DEFERRED) || (renderMethod == RENDER_DEPTH_PASS_DEFERRED))
925        {
926                cgGLSetMatrixParameterfc(Transform3::sModelMatrixParam, (const float *)IdentityMatrix().x);
927        }
928}
929
930
931void KeyHorizontalMotion(float shift)
932{
933        Vector3 hvec = -camera->GetDirection();
934        hvec.z = 0;
935
936        Vector3 pos = camera->GetPosition();
937        pos += hvec * shift;
938       
939        camera->SetPosition(pos);
940}
941
942
943void KeyVerticalMotion(float shift)
944{
945        Vector3 uvec = Vector3(0, 0, shift);
946
947        Vector3 pos = camera->GetPosition();
948        pos += uvec;
949       
950        camera->SetPosition(pos);
951}
952
953
954static void ComputeViewVectors(Vector3 &tl, Vector3 &tr, Vector3 &bl, Vector3 &br)
955{
956        Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr;
957
958        camera->ComputePoints(ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr);
959
960        bl = Normalize(nbl - fbl);
961        br = Normalize(nbr - fbr);
962        tl = Normalize(ntl - ftl);
963        tr = Normalize(ntr - ftr);
964}
965
966
967void InitDeferredRendering()
968{
969        if (!fbo) InitFBO();
970        fbo->Bind();
971
972        // multisampling does not work with deferred shading
973        glDisable(GL_MULTISAMPLE_ARB);
974
975        state.SetRenderPassType(RenderState::DEFERRED);
976
977        cgGLEnableProfile(RenderState::sCgVertexProfile);
978        cgGLBindProgram(sCgMrtVertexProgram);
979
980        cgGLEnableProfile(RenderState::sCgFragmentProfile);
981        cgGLBindProgram(RenderState::sCgMrtFragmentProgram);
982
983        const Vector3 pos = camera->GetPosition();
984
985        cgGLSetParameter3f(sEyePosParam, pos.x, pos.y, pos.z);
986        cgGLSetParameter3f(sEyePosParamTex, pos.x, pos.y, pos.z);
987
988        Vector3 tl, tr, bl, br;
989        ComputeViewVectors(tl, tr, bl, br);
990
991        cgGLSetParameter3f(sBLParam, bl.x, bl.y, bl.z);
992        cgGLSetParameter3f(sBRParam, br.x, br.y, br.z);
993        cgGLSetParameter3f(sTLParam, tl.x, tl.y, tl.z);
994        cgGLSetParameter3f(sTRParam, tr.x, tr.y, tr.z);
995
996        cgGLSetParameter3f(sBLParamTex, bl.x, bl.y, bl.z);
997        cgGLSetParameter3f(sBRParamTex, br.x, br.y, br.z);
998        cgGLSetParameter3f(sTLParamTex, tl.x, tl.y, tl.z);
999        cgGLSetParameter3f(sTRParamTex, tr.x, tr.y, tr.z);
1000
1001        // draw to 3 color buffers
1002        // a color, normal, and positions buffer
1003        if (sCurrentMrtSet == 0)
1004        {
1005                DeferredRenderer::colorBufferIdx = 0;
1006                glDrawBuffers(2, mrt);
1007        }
1008        else
1009        {
1010                DeferredRenderer::colorBufferIdx = 3;
1011                glDrawBuffers(2, mrt2);
1012        }
1013
1014        sCurrentMrtSet = 1 - sCurrentMrtSet;
1015}
1016
1017
1018// the main rendering loop
1019void Display()
1020{       
1021        Vector3 oldPos = camera->GetPosition();
1022
1023        if (leftKeyPressed)
1024                camera->Pitch(KeyRotationAngle());
1025        if (rightKeyPressed)
1026                camera->Pitch(-KeyRotationAngle());
1027        if (upKeyPressed)
1028                KeyHorizontalMotion(-KeyShift());
1029        if (downKeyPressed)
1030                KeyHorizontalMotion(KeyShift());
1031        if (ascendKeyPressed)
1032                KeyVerticalMotion(KeyShift());
1033        if (descendKeyPressed)
1034                KeyVerticalMotion(-KeyShift());
1035
1036        // place view on ground
1037        if (!flyMode) PlaceViewer(oldPos);
1038
1039        if (showAlgorithmTime)
1040        {
1041                glFinish();
1042                algTimer.Start();
1043        }
1044       
1045
1046
1047        if ((!shadowMap || !shadowTraverser) && (showShadowMap || renderLightView))
1048        {
1049                if (!shadowMap)
1050                        shadowMap = new ShadowMap(light, shadowSize, bvh->GetBox(), camera);
1051
1052                if (!shadowTraverser)
1053                        shadowTraverser = CreateTraverser(shadowMap->GetShadowCamera());
1054
1055        }
1056
1057       
1058        // bring eye modelview matrix up-to-date
1059        SetupEyeView();
1060
1061        // hack
1062        int oldRenderMethod = renderMethod;
1063
1064        if (renderLightView)
1065                renderMethod = RenderState::FIXED;
1066
1067        glEnableClientState(GL_VERTEX_ARRAY);
1068
1069
1070        // render with the specified method (forward rendering, forward + depth, deferred)
1071        switch (renderMethod)
1072        {
1073        case RENDER_FIXED:
1074       
1075                glEnable(GL_MULTISAMPLE_ARB);
1076               
1077                state.SetRenderPassType(RenderState::FIXED);
1078                glEnable(GL_LIGHTING);
1079
1080                cgGLDisableProfile(RenderState::sCgFragmentProfile);
1081                cgGLDisableProfile(RenderState::sCgVertexProfile);
1082
1083                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1084
1085                glEnableClientState(GL_NORMAL_ARRAY);
1086
1087                break;
1088
1089        case RENDER_DEPTH_PASS_DEFERRED:
1090
1091                glDisable(GL_MULTISAMPLE_ARB);
1092                state.SetUseAlphaToCoverage(false);
1093
1094                state.SetRenderPassType(RenderState::DEPTH_PASS);
1095
1096                if (!fbo) InitFBO(); fbo->Bind();
1097
1098                glDrawBuffers(1, mrt);
1099
1100                cgGLDisableProfile(RenderState::sCgFragmentProfile);
1101                cgGLDisableProfile(RenderState::sCgVertexProfile);
1102
1103                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1104
1105                // the scene is rendered withouth any shading   
1106                glShadeModel(GL_FLAT);
1107                glDisable(GL_LIGHTING);
1108                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1109
1110
1111                break;
1112
1113        case RENDER_DEPTH_PASS:
1114
1115                glEnable(GL_MULTISAMPLE_ARB);
1116
1117                cgGLDisableProfile(RenderState::sCgFragmentProfile);
1118                cgGLDisableProfile(RenderState::sCgVertexProfile);
1119
1120                state.SetRenderPassType(RenderState::DEPTH_PASS);
1121
1122                // the scene is rendered withouth any shading   
1123                glShadeModel(GL_FLAT);
1124                glDisable(GL_LIGHTING);
1125       
1126                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1127                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1128
1129
1130                break;
1131       
1132        case RenderState::DEFERRED:
1133
1134                if (showShadowMap && !renderLightView)
1135                        RenderShadowMap(camera->GetFar());
1136
1137                //glPushAttrib(GL_VIEWPORT_BIT);
1138                glViewport(0, 0, texWidth, texHeight);
1139
1140                InitDeferredRendering();
1141               
1142                glEnableClientState(GL_NORMAL_ARRAY);
1143                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1144
1145                break;
1146        }
1147
1148        glDepthFunc(GL_LESS);
1149
1150        glDisable(GL_TEXTURE_2D);
1151        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1152               
1153
1154        // reset lod levels for current frame
1155        LODLevel::InitFrame(camera->GetPosition());
1156
1157        // set up lights
1158        SetupLighting();
1159
1160
1161        if (renderLightView)
1162        {
1163                // change CHC++ set of state variables (must be done for each change of camera because
1164                // otherwise the temporal coherency is broken
1165                BvhNode::SetCurrentState(1);
1166                shadowMap->RenderShadowView(shadowTraverser, viewProjMat);
1167                BvhNode::SetCurrentState(0);
1168        }
1169        else
1170        {
1171                // actually render the scene geometry using the specified algorithm
1172                traverser->RenderScene();
1173                //renderQueue->Apply();
1174        }
1175
1176
1177        /////////
1178        //-- do the rest of the rendering
1179       
1180        // reset depth pass and render visible objects
1181        if ((renderMethod == RENDER_DEPTH_PASS) ||
1182                (renderMethod == RENDER_DEPTH_PASS_DEFERRED))
1183        {
1184                RenderVisibleObjects();
1185        }
1186       
1187
1188        ///////////////
1189        //-- render sky
1190
1191        // q: should we render sky after deferred shading?
1192        // this would conveniently solves some issues (e.g, skys without shadows)
1193
1194        RenderSky();
1195
1196
1197        if ((renderMethod == RENDER_DEFERRED) ||
1198                (renderMethod == RENDER_DEPTH_PASS_DEFERRED))
1199        {
1200                FrameBufferObject::Release();
1201
1202                cgGLDisableProfile(RenderState::sCgVertexProfile);
1203                cgGLDisableProfile(RenderState::sCgFragmentProfile);
1204
1205                if (!ssaoShader) ssaoShader =
1206                        new DeferredRenderer(texWidth, texHeight, camera, farDist / MAX_DEPTH_CONST);
1207               
1208                DeferredRenderer::SHADING_METHOD shadingMethod;
1209
1210                if (useAdvancedShading)
1211                {
1212                        if (useGlobIllum)
1213                                shadingMethod = DeferredRenderer::GI;
1214                        else
1215                                shadingMethod = DeferredRenderer::SSAO;
1216                }
1217                else
1218                        shadingMethod = DeferredRenderer::DEFAULT;
1219
1220
1221                ssaoShader->SetShadingMethod(shadingMethod);
1222                ssaoShader->SetSamplingMethod(samplingMethod);
1223                ssaoShader->SetUseTemporalCoherence(useTemporalCoherence);
1224
1225                ShadowMap *sm = showShadowMap ? shadowMap : NULL;
1226                ssaoShader->Render(fbo, oldViewProjMat, viewProjMat, ssaoTempCohFactor, light, useHDR, sm);
1227        }
1228
1229
1230        state.SetRenderPassType(RenderState::FIXED);
1231        state.Reset();
1232
1233
1234        glDisableClientState(GL_VERTEX_ARRAY);
1235        glDisableClientState(GL_NORMAL_ARRAY);
1236       
1237        renderMethod = oldRenderMethod;
1238
1239
1240        ///////////
1241
1242
1243        if (showAlgorithmTime)
1244        {
1245                glFinish();
1246
1247                algTime = algTimer.Elapsedms();
1248                perfGraph->AddData(algTime);
1249
1250                perfGraph->Draw();
1251        }
1252        else
1253        {
1254                if (visMode) DisplayVisualization();
1255        }
1256
1257        glFlush();
1258
1259        const bool restart = true;
1260        elapsedTime = frameTimer.Elapsedms(restart);
1261
1262        DisplayStats();
1263
1264        glutSwapBuffers();
1265}
1266
1267
1268#pragma warning( disable : 4100 )
1269void KeyBoard(unsigned char c, int x, int y)
1270{
1271        switch(c)
1272        {
1273        case 27:
1274                CleanUp();
1275                exit(0);
1276                break;
1277        case 32: // space
1278                renderMode = (renderMode + 1) % RenderTraverser::NUM_TRAVERSAL_TYPES;
1279
1280                DEL_PTR(traverser);
1281                traverser = CreateTraverser(camera);
1282
1283                if (shadowTraverser)
1284                {
1285                        // shadow traverser has to be recomputed
1286                        DEL_PTR(shadowTraverser);
1287                        shadowTraverser = CreateTraverser(shadowMap->GetShadowCamera());
1288                }
1289
1290                break;
1291        case '+':
1292                if (maxBatchSize < 10)
1293                        maxBatchSize = 10;
1294                else
1295                        maxBatchSize += 10;
1296
1297                traverser->SetMaxBatchSize(maxBatchSize);
1298                break;
1299        case '-':
1300                maxBatchSize -= 10;
1301                if (maxBatchSize < 0) maxBatchSize = 1;
1302                traverser->SetMaxBatchSize(maxBatchSize);               
1303                break;
1304        case 'M':
1305        case 'm':
1306                useMultiQueries = !useMultiQueries;
1307                traverser->SetUseMultiQueries(useMultiQueries);
1308                break;
1309        case '1':
1310                descendKeyPressed = true;
1311                break;
1312        case '2':
1313                ascendKeyPressed = true;
1314                break;
1315        case '3':
1316                if (trianglesPerVirtualLeaf >= 100)
1317                        trianglesPerVirtualLeaf -= 100;
1318                bvh->SetVirtualLeaves(trianglesPerVirtualLeaf);
1319                break;
1320        case '4':
1321                trianglesPerVirtualLeaf += 100;
1322                bvh->SetVirtualLeaves(trianglesPerVirtualLeaf);
1323                break;
1324        case '5':
1325                assumedVisibleFrames -= 1;
1326                if (assumedVisibleFrames < 1) assumedVisibleFrames = 1;
1327                traverser->SetAssumedVisibleFrames(assumedVisibleFrames);
1328                break;
1329        case '6':
1330                assumedVisibleFrames += 1;
1331                traverser->SetAssumedVisibleFrames(assumedVisibleFrames);               
1332                break;
1333        case '7':
1334                ssaoTempCohFactor *= 0.5f;
1335                break;
1336        case '8':
1337                ssaoTempCohFactor *= 2.0f;
1338                //if (ssaoTempCohFactor > 1.0f) ssaoExpFactor = 1.0f;
1339                break;
1340        case '9':
1341                useLODs = !useLODs;
1342                SceneEntity::SetUseLODs(useLODs);
1343                break;
1344        case 'P':
1345        case 'p':
1346                samplingMethod = DeferredRenderer::SAMPLING_METHOD((samplingMethod + 1) % 3);
1347                cout << "ssao sampling method: " << samplingMethod << endl;
1348                break;
1349        case 'Y':
1350        case 'y':
1351                showShadowMap = !showShadowMap;
1352                break;
1353        case 'g':
1354        case 'G':
1355                useGlobIllum = !useGlobIllum;
1356                break;
1357        case 't':
1358        case 'T':
1359                useTemporalCoherence = !useTemporalCoherence;
1360                break;
1361        case 'o':
1362        case 'O':
1363                useOptimization = !useOptimization;
1364                traverser->SetUseOptimization(useOptimization);
1365                break;
1366        case 'a':
1367        case 'A':
1368                leftKeyPressed = true;
1369                break;
1370        case 'd':
1371        case 'D':
1372                rightKeyPressed = true;
1373                break;
1374        case 'w':
1375        case 'W':
1376                upKeyPressed = true;
1377                break;
1378        case 's':
1379        case 'S':
1380                downKeyPressed = true;
1381                break;
1382        case 'r':
1383        case 'R':
1384                useRenderQueue = !useRenderQueue;
1385                traverser->SetUseRenderQueue(useRenderQueue);
1386               
1387                break;
1388        case 'b':
1389        case 'B':
1390                useTightBounds = !useTightBounds;
1391                traverser->SetUseTightBounds(useTightBounds);
1392                break;
1393        case 'l':
1394        case 'L':
1395                renderLightView = !renderLightView;
1396                break;
1397        case 'h':
1398        case 'H':
1399                useHDR = !useHDR;
1400                break;
1401        default:
1402                return;
1403        }
1404
1405        glutPostRedisplay();
1406}
1407
1408
1409void SpecialKeyUp(int c, int x, int y)
1410{
1411        switch (c)
1412        {
1413        case GLUT_KEY_LEFT:
1414                leftKeyPressed = false;
1415                break;
1416        case GLUT_KEY_RIGHT:
1417                rightKeyPressed = false;
1418                break;
1419        case GLUT_KEY_UP:
1420                upKeyPressed = false;
1421                break;
1422        case GLUT_KEY_DOWN:
1423                downKeyPressed = false;
1424                break;
1425        case GLUT_ACTIVE_ALT:
1426                altKeyPressed = false;
1427                break;
1428        default:
1429                return;
1430        }
1431}
1432
1433
1434void KeyUp(unsigned char c, int x, int y)
1435{
1436        switch (c)
1437        {
1438
1439        case 'A':
1440        case 'a':
1441                leftKeyPressed = false;
1442                break;
1443        case 'D':
1444        case 'd':
1445                rightKeyPressed = false;
1446                break;
1447        case 'W':
1448        case 'w':
1449                upKeyPressed = false;
1450                break;
1451        case 'S':
1452        case 's':
1453                downKeyPressed = false;
1454                break;
1455        case '1':
1456                descendKeyPressed = false;
1457                break;
1458        case '2':
1459                ascendKeyPressed = false;
1460                break;
1461       
1462        default:
1463                return;
1464        }
1465        //glutPostRedisplay();
1466}
1467
1468
1469void Special(int c, int x, int y)
1470{
1471        switch(c)
1472        {
1473        case GLUT_KEY_F1:
1474                showHelp = !showHelp;
1475                break;
1476        case GLUT_KEY_F2:
1477                visMode = !visMode;
1478                break;
1479        case GLUT_KEY_F3:
1480                showBoundingVolumes = !showBoundingVolumes;
1481                traverser->SetShowBounds(showBoundingVolumes);
1482                break;
1483        case GLUT_KEY_F4:
1484                showOptions = !showOptions;
1485                break;
1486        case GLUT_KEY_F5:
1487                showStatistics = !showStatistics;
1488                break;
1489        case GLUT_KEY_F6:
1490                flyMode = !flyMode;
1491                break;
1492        case GLUT_KEY_F7:
1493
1494                renderMethod = (renderMethod + 1) % 4;
1495
1496                traverser->SetUseDepthPass(
1497                        (renderMethod == RENDER_DEPTH_PASS) ||
1498                        (renderMethod == RENDER_DEPTH_PASS_DEFERRED)
1499                        );
1500               
1501                break;
1502        case GLUT_KEY_F8:
1503                useAdvancedShading = !useAdvancedShading;
1504
1505                break;
1506        case GLUT_KEY_F9:
1507                showAlgorithmTime = !showAlgorithmTime;
1508                break;
1509        case GLUT_KEY_F10:
1510                moveLight = !moveLight;
1511                break;
1512        case GLUT_KEY_LEFT:
1513                {
1514                        leftKeyPressed = true;
1515                        camera->Pitch(KeyRotationAngle());
1516                }
1517                break;
1518        case GLUT_KEY_RIGHT:
1519                {
1520                        rightKeyPressed = true;
1521                        camera->Pitch(-KeyRotationAngle());
1522                }
1523                break;
1524        case GLUT_KEY_UP:
1525                {
1526                        upKeyPressed = true;
1527                        KeyHorizontalMotion(KeyShift());
1528                }
1529                break;
1530        case GLUT_KEY_DOWN:
1531                {
1532                        downKeyPressed = true;
1533                        KeyHorizontalMotion(-KeyShift());
1534                }
1535                break;
1536        default:
1537                return;
1538
1539        }
1540
1541        glutPostRedisplay();
1542}
1543
1544#pragma warning( default : 4100 )
1545
1546
1547void Reshape(int w, int h)
1548{
1549        winAspectRatio = 1.0f;
1550
1551        glViewport(0, 0, w, h);
1552       
1553        winWidth = w;
1554        winHeight = h;
1555
1556        if (w) winAspectRatio = (float) w / (float) h;
1557
1558        glMatrixMode(GL_PROJECTION);
1559        glLoadIdentity();
1560
1561        gluPerspective(fov, winAspectRatio, nearDist, farDist);
1562
1563        glMatrixMode(GL_MODELVIEW);
1564
1565        glutPostRedisplay();
1566}
1567
1568
1569void Mouse(int button, int state, int x, int y)
1570{
1571        if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN))
1572        {
1573                xEyeBegin = x;
1574                yMotionBegin = y;
1575
1576                glutMotionFunc(LeftMotion);
1577        }
1578        else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN))
1579        {
1580                xEyeBegin = x;
1581                yEyeBegin = y;
1582                yMotionBegin = y;
1583
1584                if (!moveLight)
1585                        glutMotionFunc(RightMotion);
1586                else
1587                        glutMotionFunc(RightMotionLight);
1588        }
1589        else if ((button == GLUT_MIDDLE_BUTTON) && (state == GLUT_DOWN))
1590        {
1591                horizontalMotionBegin = x;
1592                verticalMotionBegin = y;
1593                glutMotionFunc(MiddleMotion);
1594        }
1595
1596        glutPostRedisplay();
1597}
1598
1599
1600/**     rotation for left/right mouse drag
1601        motion for up/down mouse drag
1602*/
1603void LeftMotion(int x, int y)
1604{
1605        Vector3 viewDir = camera->GetDirection();
1606        Vector3 pos = camera->GetPosition();
1607
1608        // don't move in the vertical direction
1609        Vector3 horView(viewDir[0], viewDir[1], 0);
1610       
1611        float eyeXAngle = 0.2f *  M_PI * (xEyeBegin - x) / 180.0;
1612
1613        camera->Pitch(eyeXAngle);
1614
1615        pos += horView * (yMotionBegin - y) * 0.2f;
1616       
1617        camera->SetPosition(pos);
1618       
1619        xEyeBegin = x;
1620        yMotionBegin = y;
1621
1622        glutPostRedisplay();
1623}
1624
1625
1626void RightMotionLight(int x, int y)
1627{
1628        float theta = 0.2f * M_PI * (xEyeBegin - x) / 180.0f;
1629        float phi = 0.2f * M_PI * (yMotionBegin - y) / 180.0f;
1630       
1631        Vector3 lightDir = light->GetDirection();
1632
1633        Matrix4x4 roty = RotationYMatrix(theta);
1634        Matrix4x4 rotx = RotationXMatrix(phi);
1635
1636        lightDir = roty * lightDir;
1637        lightDir = rotx * lightDir;
1638
1639        // normalize to avoid accumulating errors
1640        lightDir.Normalize();
1641
1642        light->SetDirection(lightDir);
1643
1644        xEyeBegin = x;
1645        yMotionBegin = y;
1646
1647        glutPostRedisplay();
1648}
1649
1650
1651/**     rotation for left / right mouse drag
1652        motion for up / down mouse drag
1653*/
1654void RightMotion(int x, int y)
1655{
1656        float eyeXAngle = 0.2f *  M_PI * (xEyeBegin - x) / 180.0;
1657        float eyeYAngle = -0.2f *  M_PI * (yEyeBegin - y) / 180.0;
1658
1659        camera->Yaw(eyeYAngle);
1660        camera->Pitch(eyeXAngle);
1661
1662        xEyeBegin = x;
1663        yEyeBegin = y;
1664
1665        glutPostRedisplay();
1666}
1667
1668
1669// strafe
1670void MiddleMotion(int x, int y)
1671{
1672        Vector3 viewDir = camera->GetDirection();
1673        Vector3 pos = camera->GetPosition();
1674
1675        // the 90 degree rotated view vector
1676        // y zero so we don't move in the vertical
1677        Vector3 rVec(viewDir[0], viewDir[1], 0);
1678       
1679        Matrix4x4 rot = RotationZMatrix(M_PI * 0.5f);
1680        rVec = rot * rVec;
1681       
1682        pos -= rVec * (x - horizontalMotionBegin) * 0.1f;
1683        pos[2] += (verticalMotionBegin - y) * 0.1f;
1684
1685        camera->SetPosition(pos);
1686
1687        horizontalMotionBegin = x;
1688        verticalMotionBegin = y;
1689
1690        glutPostRedisplay();
1691}
1692
1693
1694void InitExtensions(void)
1695{
1696        GLenum err = glewInit();
1697
1698        if (GLEW_OK != err)
1699        {
1700                // problem: glewInit failed, something is seriously wrong
1701                fprintf(stderr,"Error: %s\n", glewGetErrorString(err));
1702                exit(1);
1703        }
1704        if  (!GLEW_ARB_occlusion_query)
1705        {
1706                printf("I require the GL_ARB_occlusion_query to work.\n");
1707                exit(1);
1708        }
1709}
1710
1711
1712void Begin2D()
1713{
1714        glDisable(GL_LIGHTING);
1715        glDisable(GL_DEPTH_TEST);
1716
1717        glMatrixMode(GL_PROJECTION);
1718        glPushMatrix();
1719        glLoadIdentity();
1720
1721        gluOrtho2D(0, winWidth, 0, winHeight);
1722
1723        glMatrixMode(GL_MODELVIEW);
1724        glPushMatrix();
1725        glLoadIdentity();
1726}
1727
1728
1729void End2D()
1730{
1731        glMatrixMode(GL_PROJECTION);
1732        glPopMatrix();
1733
1734        glMatrixMode(GL_MODELVIEW);
1735        glPopMatrix();
1736
1737        glEnable(GL_LIGHTING);
1738        glEnable(GL_DEPTH_TEST);
1739}
1740
1741
1742// displays the visualisation of culling algorithm
1743void DisplayVisualization()
1744{
1745        visualization->SetFrameId(traverser->GetCurrentFrameId());
1746       
1747        Begin2D();
1748        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1749        glEnable(GL_BLEND);
1750        glColor4f(0.0f ,0.0f, 0.0f, 0.5f);
1751
1752        glRecti(winWidth - winWidth / 3, winHeight - winHeight / 3, winWidth, winHeight);
1753        glDisable(GL_BLEND);
1754        End2D();
1755       
1756       
1757        AxisAlignedBox3 box = bvh->GetBox();
1758
1759        const float offs = box.Size().x * 0.3f;
1760       
1761        Vector3 vizpos = Vector3(box.Min().x, box.Min().y  - box.Size().y * 0.35f, box.Min().z + box.Size().z * 50);
1762       
1763        visCamera->SetPosition(vizpos);
1764        visCamera->ResetPitchAndYaw();
1765       
1766        glPushAttrib(GL_VIEWPORT_BIT);
1767        glViewport(winWidth - winWidth / 3, winHeight - winHeight / 3, winWidth / 3, winHeight / 3);
1768
1769        glMatrixMode(GL_PROJECTION);
1770        glPushMatrix();
1771
1772        glLoadIdentity();
1773       
1774        glOrtho(-offs, offs, -offs, offs, 0.0f, box.Size().z * 100.0f);
1775
1776        glMatrixMode(GL_MODELVIEW);
1777        glPushMatrix();
1778
1779        visCamera->SetupCameraView();
1780
1781        Matrix4x4 rotZ = RotationZMatrix(-camera->GetPitch());
1782        glMultMatrixf((float *)rotZ.x);
1783
1784        // inverse translation in order to fix current position
1785        Vector3 pos = camera->GetPosition();
1786        glTranslatef(-pos.x, -pos.y, -pos.z);
1787
1788
1789        GLfloat position[] = {0.8f, 1.0f, 1.5f, 0.0f};
1790        glLightfv(GL_LIGHT0, GL_POSITION, position);
1791
1792        GLfloat position1[] = {bvh->GetBox().Center().x, bvh->GetBox().Max().y, bvh->GetBox().Center().z, 1.0f};
1793        glLightfv(GL_LIGHT1, GL_POSITION, position1);
1794
1795        glClear(GL_DEPTH_BUFFER_BIT);
1796
1797
1798        ////////////
1799        //-- visualization of the occlusion culling
1800
1801        visualization->Render();
1802
1803       
1804        // reset previous settings
1805        glPopAttrib();
1806
1807        glMatrixMode(GL_PROJECTION);
1808        glPopMatrix();
1809        glMatrixMode(GL_MODELVIEW);
1810        glPopMatrix();
1811}
1812
1813
1814// cleanup routine after the main loop
1815void CleanUp()
1816{
1817        DEL_PTR(traverser);
1818        DEL_PTR(sceneQuery);
1819        DEL_PTR(bvh);
1820        DEL_PTR(visualization);
1821        DEL_PTR(camera);
1822        DEL_PTR(loader);
1823        DEL_PTR(renderQueue);
1824        DEL_PTR(perfGraph);
1825
1826        DEL_PTR(fbo);
1827        DEL_PTR(ssaoShader);
1828
1829        if (sCgMrtVertexProgram)
1830                cgDestroyProgram(sCgMrtVertexProgram);
1831        if (RenderState::sCgMrtFragmentProgram)
1832                cgDestroyProgram(RenderState::sCgMrtFragmentProgram);
1833        if (RenderState::sCgMrtFragmentTexProgram)
1834                cgDestroyProgram(RenderState::sCgMrtFragmentTexProgram);
1835       
1836        if (sCgContext)
1837                cgDestroyContext(sCgContext);
1838}
1839
1840
1841// this function inserts a dezimal point after each 1000
1842void CalcDecimalPoint(string &str, int d, int len)
1843{
1844        static vector<int> numbers;
1845        numbers.clear();
1846
1847        static string shortStr;
1848        shortStr.clear();
1849
1850        static char hstr[100];
1851
1852        while (d != 0)
1853        {
1854                numbers.push_back(d % 1000);
1855                d /= 1000;
1856        }
1857
1858        // first element without leading zeros
1859        if (numbers.size() > 0)
1860        {
1861                sprintf(hstr, "%d", numbers.back());
1862                shortStr.append(hstr);
1863        }
1864       
1865        for (int i = (int)numbers.size() - 2; i >= 0; i--)
1866        {
1867                sprintf(hstr, ",%03d", numbers[i]);
1868                shortStr.append(hstr);
1869        }
1870
1871        int dif = len - (int)shortStr.size();
1872
1873        for (int i = 0; i < dif; ++ i)
1874        {
1875                str += " ";
1876        }
1877
1878        str.append(shortStr);
1879}
1880
1881
1882void DisplayStats()
1883{
1884        static char msg[9][300];
1885
1886        static double frameTime = elapsedTime;
1887        static double renderTime = algTime;
1888
1889        const float expFactor = 0.1f;
1890
1891        // if some strange render time spike happened in this frame => don't count
1892        if (elapsedTime < 500) frameTime = elapsedTime * expFactor + (1.0f - expFactor) * elapsedTime;
1893       
1894        static float rTime = 1000.0f;
1895
1896        if (showAlgorithmTime)
1897        {
1898                if (algTime < 500) renderTime = algTime * expFactor + (1.0f - expFactor) * renderTime;
1899        }
1900
1901        accumulatedTime += elapsedTime;
1902
1903        if (accumulatedTime > 500) // update every fraction of a second
1904        {       
1905                accumulatedTime = 0;
1906
1907                if (frameTime) fps = 1e3f / (float)frameTime;
1908
1909                rTime = renderTime;
1910
1911                if (renderLightView && shadowTraverser)
1912                {
1913                        renderedTriangles = shadowTraverser->GetStats().mNumRenderedTriangles;
1914                        renderedObjects = shadowTraverser->GetStats().mNumRenderedGeometry;
1915                        renderedNodes = shadowTraverser->GetStats().mNumRenderedNodes;
1916                }
1917                else if (showShadowMap && shadowTraverser)
1918                {
1919                        renderedNodes = traverser->GetStats().mNumRenderedNodes + shadowTraverser->GetStats().mNumRenderedNodes;
1920                        renderedObjects = traverser->GetStats().mNumRenderedGeometry + shadowTraverser->GetStats().mNumRenderedGeometry;
1921                        renderedTriangles = traverser->GetStats().mNumRenderedTriangles + shadowTraverser->GetStats().mNumRenderedTriangles;
1922                }
1923                else
1924                {
1925                        renderedTriangles = traverser->GetStats().mNumRenderedTriangles;
1926                        renderedObjects = traverser->GetStats().mNumRenderedGeometry;
1927                        renderedNodes = traverser->GetStats().mNumRenderedNodes;
1928                }
1929
1930                traversedNodes = traverser->GetStats().mNumTraversedNodes;
1931                frustumCulledNodes = traverser->GetStats().mNumFrustumCulledNodes;
1932                queryCulledNodes = traverser->GetStats().mNumQueryCulledNodes;
1933                issuedQueries = traverser->GetStats().mNumIssuedQueries;
1934                stateChanges = traverser->GetStats().mNumStateChanges;
1935                numBatches = traverser->GetStats().mNumBatches;
1936        }
1937
1938
1939        Begin2D();
1940
1941        glEnable(GL_BLEND);
1942        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1943
1944        if (showHelp)
1945        {       
1946                DrawHelpMessage();
1947        }
1948        else
1949        {
1950                if (showOptions)
1951                {
1952                        glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
1953                        glRecti(5, winHeight - 95, winWidth * 2 / 3 - 5, winHeight - 5);
1954                }
1955
1956                if (showStatistics)
1957                {
1958                        glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
1959                        glRecti(5, winHeight - 165, winWidth * 2 / 3 - 5, winHeight - 100);
1960                }
1961
1962                glEnable(GL_TEXTURE_2D);
1963
1964                myfont.Begin();
1965
1966                if (showOptions)
1967                {
1968                        glColor3f(0.0f, 1.0f, 0.0f);
1969
1970                        int i = 0;
1971
1972                        static char *renderMethodStr[] = {"forward", "depth pass + forward", "deferred shading", "depth pass + deferred"};
1973       
1974                        sprintf(msg[i ++], "multiqueries: %d, tight bounds: %d, render queue: %d",
1975                                                        useMultiQueries, useTightBounds, useRenderQueue);
1976
1977                        sprintf(msg[i ++], "render technique: %s, SSAO: %d", renderMethodStr[renderMethod], useAdvancedShading);
1978
1979                        sprintf(msg[i ++], "triangles per virtual leaf: %5d", trianglesPerVirtualLeaf);
1980
1981                        sprintf(msg[i ++], "assumed visible frames: %4d, max batch size: %4d",
1982                                assumedVisibleFrames, maxBatchSize);
1983
1984                        for (int j = 0; j < 4; ++ j)
1985                                myfont.DrawString(msg[j], 10.0f, winHeight - 5 - j * 20);
1986                }
1987
1988                if (showStatistics)
1989                {
1990                        glColor3f(1.0f, 1.0f, 0.0f);
1991
1992                        string objStr, totalObjStr;
1993                        string triStr, totalTriStr;
1994
1995                        int len = 10;
1996                        CalcDecimalPoint(objStr, renderedObjects, len);
1997                        CalcDecimalPoint(totalObjStr, (int)loader->GetNumEntities(), len);
1998
1999                        CalcDecimalPoint(triStr, renderedTriangles, len);
2000                        CalcDecimalPoint(totalTriStr, bvh->GetBvhStats().mTriangles, len);
2001
2002                        int i = 4;
2003
2004                        if (0)
2005                        {
2006                                sprintf(msg[i ++], "rendered: %s of %s objects, %s of %s triangles",
2007                                        objStr.c_str(), totalObjStr.c_str(), triStr.c_str(), totalTriStr.c_str());
2008                        }
2009                        else
2010                        {
2011                                sprintf(msg[i ++], "rendered: %6d of %6d nodes, %s of %s triangles",
2012                                        renderedNodes, bvh->GetNumVirtualNodes(), triStr.c_str(), totalTriStr.c_str());
2013                        }
2014
2015                        sprintf(msg[i ++], "traversed: %5d, frustum culled: %5d, query culled: %5d",
2016                                traversedNodes, frustumCulledNodes, queryCulledNodes);
2017
2018                        sprintf(msg[i ++], "issued queries: %5d, state changes: %5d, render batches: %5d",
2019                                issuedQueries, stateChanges, numBatches);
2020
2021                        for (int j = 4; j < 7; ++ j)
2022                                myfont.DrawString(msg[j], 10.0f, winHeight - (j + 1) * 20);
2023                }
2024
2025                glColor3f(1.0f, 1.0f, 1.0f);
2026                static char *alg_str[] = {"Frustum Cull", "Stop and Wait", "CHC", "CHC ++"};
2027               
2028                if (!showAlgorithmTime)
2029                                sprintf(msg[7], "%s:  %6.1f fps", alg_str[renderMode], fps);
2030                else
2031                        sprintf(msg[7], "%s:  %6.1f ms", alg_str[renderMode], rTime);
2032               
2033                myfont.DrawString(msg[7], 1.3f, 690.0f, 760.0f);//, top_color, bottom_color);
2034               
2035                //sprintf(msg[8], "algorithm time: %6.1f ms", rTime);
2036                //myfont.DrawString(msg[8], 720.0f, 730.0f);           
2037        }
2038
2039        glDisable(GL_BLEND);
2040        glDisable(GL_TEXTURE_2D);
2041
2042        End2D();
2043}       
2044
2045
2046void RenderSky()
2047{
2048        cgGLEnableProfile(RenderState::sCgVertexProfile);
2049
2050        if ((renderMethod == RENDER_DEFERRED) || (renderMethod == RENDER_DEPTH_PASS_DEFERRED))
2051                state.SetRenderPassType(RenderState::DEFERRED);
2052
2053        const bool useToneMapping = ((renderMethod == RENDER_DEPTH_PASS_DEFERRED) || (renderMethod == RENDER_DEFERRED)) && useHDR;
2054
2055        preetham->RenderSkyDome(-light->GetDirection(), camera, &state, !useToneMapping);
2056
2057        cgGLDisableProfile(RenderState::sCgVertexProfile);
2058        cgGLDisableProfile(RenderState::sCgFragmentProfile);
2059}
2060
2061
2062// render visible object from depth pass
2063void RenderVisibleObjects()
2064{
2065        if (renderMethod == RENDER_DEPTH_PASS_DEFERRED)
2066        {
2067                if (showShadowMap && !renderLightView)
2068                {
2069                        float minVisibleDist = min(camera->GetFar(), traverser->GetMaxVisibleDistance());
2070                        RenderShadowMap(minVisibleDist);
2071                }
2072
2073                glDisable(GL_LIGHTING);
2074                glViewport(0, 0, texWidth, texHeight);
2075
2076                InitDeferredRendering();
2077        }
2078        else
2079        {
2080                glEnable(GL_LIGHTING);
2081                state.SetRenderPassType(RenderState::FIXED);
2082        }
2083
2084        glShadeModel(GL_SMOOTH);
2085        glEnableClientState(GL_NORMAL_ARRAY);
2086
2087        // draw all objects that have exactly the same depth as the current sample
2088        glDepthFunc(GL_LEQUAL);
2089        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2090
2091        glClear(GL_COLOR_BUFFER_BIT);
2092
2093        state.SetUseAlphaToCoverage(true);
2094        state.Reset();
2095
2096        //cout << "visible: " << (int)traverser->GetVisibleObjects().size() << endl;
2097
2098        SceneEntityContainer::const_iterator sit,
2099                sit_end = traverser->GetVisibleObjects().end();
2100
2101        for (sit = traverser->GetVisibleObjects().begin(); sit != sit_end; ++ sit)
2102        {
2103                renderQueue->Enqueue(*sit);
2104        }
2105
2106        renderQueue->Apply();
2107
2108        glDepthFunc(GL_LESS);
2109        state.Reset();
2110
2111        PrintGLerror("visibleobjects");
2112}
2113
2114
2115void PlaceViewer(const Vector3 &oldPos)
2116{
2117        Vector3 playerPos = camera->GetPosition();
2118        bool validIntersect = sceneQuery->CalcIntersection(playerPos);
2119
2120        if (validIntersect)
2121                // && ((playerPos.z - oldPos.z) < bvh->GetBox().Size(2) * 1e-1f))
2122        {
2123                camera->SetPosition(playerPos);
2124        }
2125}
2126
2127
2128void RenderShadowMap(float newfar)
2129{
2130        cgGLDisableProfile(RenderState::sCgFragmentProfile);
2131        cgGLDisableProfile(RenderState::sCgVertexProfile);
2132
2133        glDisableClientState(GL_NORMAL_ARRAY);
2134
2135        state.SetRenderPassType(RenderState::DEPTH_PASS);
2136        state.LockCullFaceEnabled(true);
2137        state.SetUseAlphaToCoverage(false);
2138
2139        // change CHC++ set of state variables
2140        // this must be done for each change of camera because
2141        // otherwise the temporal coherency is broken
2142        BvhNode::SetCurrentState(1);
2143
2144        // hack: temporarily change camera far plane
2145        camera->SetFar(newfar);
2146        glDisable(GL_CULL_FACE);
2147       
2148        // the scene is rendered withouth any shading   
2149        shadowMap->ComputeShadowMap(shadowTraverser, viewProjMat);
2150
2151        glEnable(GL_CULL_FACE);
2152        camera->SetFar(farDist);
2153
2154        state.SetUseAlphaToCoverage(true);
2155        state.LockCullFaceEnabled(false);
2156
2157        glEnableClientState(GL_NORMAL_ARRAY);
2158
2159        // change back state
2160        BvhNode::SetCurrentState(0);
2161}
Note: See TracBrowser for help on using the repository browser.