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

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