source: GTP/trunk/App/Demos/Vis/HillyTerrain/OGRE/TerrainFrameListener.cpp @ 2555

Revision 2555, 57.3 KB checked in by mattausch, 17 years ago (diff)

added partial implementation of chc++. problem: bounding box rendering in Ogre is VERY slow

Line 
1#include <OgreNoMemoryMacros.h>
2#include <CEGUI/CEGUI.h>
3#include <../CEGUIRenderer/include/OgreCEGUIRenderer.h>
4#include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h>
5#include <../CEGUIRenderer/include/OgreCEGUITexture.h>
6#include <OgreMemoryMacros.h>
7#include "TerrainFrameListener.h"
8#include "OgrePlatformQueryManager.h"
9#include "VisibilityInfo.h"
10#include "OgreOcclusionQueriesQueryManager.h"
11#include "TestCullingTerrainApplication.h"
12#include <string>
13
14
15//-- captions for overlays
16String TerrainFrameListener::msAlgorithmCaptions[] =
17{
18        "Coherent Hierarchical Culling",
19        "Coherent Hierarchical Culling++",
20        "Stop and Wait Culling",
21        "View Frustum Culling",
22        "Standard Rendering"
23};
24
25//-- captions for overlays
26String TerrainFrameListener::msApprevAlgorithmCaptions[] =
27{
28        "CHC",
29        "VFC",
30        "CHC++",
31        "SWC",
32        "DEF",
33        "INT"
34};
35
36
37String TerrainFrameListener::msQueryTypeCaptions[] =
38{
39        "from camera",
40        "from viewpoint"
41};
42
43String TerrainFrameListener::msQueryRelativeVisCaptions[] =
44{
45        "visible pixels",
46        "relative visibility"
47};
48
49String TerrainFrameListener::msQueryMethodCaptions[] =
50{
51        "occlusion queries",
52        "item buffer"
53};
54
55Real TerrainFrameListener::msObjectTerrainOffsets[] =
56{
57        0,
58        -0.1,
59        //7,
60        0
61};
62
63Real TerrainFrameListener::msObjectScales[] =
64{
65        0.07,
66        0.03,
67        //0.1,
68        0.03
69};
70
71String TerrainFrameListener::msObjectCaptions[] =
72{
73        "robot",
74        "athene",
75        "natFX_Tree1_LOD2",
76        //"tree2",
77        //"HongKong_Tower",
78        "ninja"
79        //"ogrehead"
80};
81
82// output file for frame info
83const char* frames_out_filename = "frame.out";
84// output file for object positions / orientations
85const char* objects_out_filename = "objects.out";
86       
87std::ofstream video_out("video.lst");
88
89// if we are recording a demo
90static const bool DEMO_HACK = false;
91
92//using namespace GtpVisibility;
93
94//-----------------------------------------------------------------------
95TerrainFrameListener::TerrainFrameListener(RenderWindow* win, Camera* cam,
96                                                                                   SceneManager *sceneManager,
97                                                                                   CEGUI::Renderer *renderer,
98                                                                                   TerrainContentGenerator *sceneGenerator,
99                                                                                   Camera *vizCamera,
100                                                                                   SceneNode *camNode,
101                                                                                   Light *sunLight,
102                                                                                   TestCullingTerrainApplication *app):
103mCamera(cam),
104mWindow(win),
105mNumScreenShots(0),
106mTimeDelay(0),
107mSceneDetailIndex(0),
108mMoveScale(0.0f),
109mRotScale(0.0f),
110mTranslateVector(Vector3::ZERO),
111mAniso(1),
112mFiltering(TFO_BILINEAR),
113mGUIRenderer(renderer),
114mSceneMgr(sceneManager),
115mCurrentObject(NULL),
116mTerrainContentGenerator(sceneGenerator),
117mVisibilityThreshold(0),
118mAssumedVisibility(0),
119mCurrentAlgorithm(GtpVisibility::VisibilityEnvironment::COHERENT_HIERARCHICAL_CULLING),
120mNodeVizMode(NODEVIZ_NONE),
121mVizCameraHeight(Real(2000.0)),
122mCamNode(camNode),
123mAppState(WALKTHROUGH),
124mCurrentFrame(0),
125mReplayTimeElapsed(0),
126mRotateSpeed(72),
127mMoveSpeed(50),
128mVizCamera(vizCamera),
129mStatsOn(true),
130mShutdownRequested(false),
131mLMouseDown(false),
132mRMouseDown(false),
133mShowOctree(false),
134mShowViewCells(false),
135mUseDepthPass(false),
136mTestGeometryForVisibleLeaves(false),
137mTestGeometryBounds(false),
138mShowVisualization(false),
139mCullCamera(false),
140mRecordFrames(false),
141mShowShadows(false),
142mShowHelp(false),
143mDisplayCameraDetails(false),
144mVisualizeCulledNodes(false),
145mSunLight(sunLight),
146mShiftPressed(false),
147mShowQueryStats(false),
148mQueryManager(NULL),
149mVisibilityManager(NULL),
150mDelayedQueriesIssued(0.0),
151mDelayedTraversedNodes(0.0),
152mCurrentObjectType(0),
153mApplication(app),
154mUseAnimation(false),
155mDeleteObjects(false),
156mUseItemBuffer(false),
157mItemBufferMode(GtpVisibility::QueryManager::PATCH_VISIBILITY),
158mRecordVideo(false),
159mPureRenderTimeFps(0.0),
160mNumVideoFrames(0),
161mPrecomputedFps(0),
162mRecordDemo(false),
163mSavePrecomputedFps(false),
164mUseBufferedInputMouse(false),
165mVizScale(25),
166mUseViewCells(false),
167mViewCellsLoaded(false),
168mFloorDist(2),
169mFlushQueue(false),
170m_iShowBoundingBoxes(0),
171m_iBoundingBoxLevel(0),
172mMoveFactor(1000)
173{
174        mEventProcessor = new EventProcessor();
175       
176        mEventProcessor->initialise(win);
177        mEventProcessor->startProcessingEvents();
178        mEventProcessor->addMouseListener(this);
179        mEventProcessor->addMouseMotionListener(this);
180        mEventProcessor->addKeyListener(this);
181
182        mInputDevice = mEventProcessor->getInputReader();       
183
184        mInputDevice->setBufferedInput(true, mUseBufferedInputMouse);
185
186        // create ray query executor, used to place objects in terrain
187        mRayQueryExecutor = new RayQueryExecutor(mSceneMgr);
188       
189
190        //////////
191        //-- overlays
192       
193        mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
194        mHelpOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/HelpOverlay");
195        mQueryOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/QueryOverlay");
196        mCullStatsOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/CullStatsOverlay");
197
198        String ext = "Example/Visibility/";
199
200        //-- overlays
201   
202        initVisStatsOverlay(); // visibility stats overlay
203        initHelpOverlay();     // help overlay
204        initQueryOverlay();    // visibility query stats overlay
205       
206        // show stats overlays
207        if (!DEMO_HACK)
208        {
209                showStats(true);
210        }
211        else
212        {
213                mMyStatsOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/MyStatsOverlay");
214                mMyStatsAlgorithmInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/MyAlgorithmInfo");
215                mMyStatsAlgorithmInfo->setCaption("");
216       
217                const int top = 10;
218                mMyStatsAlgorithmInfo->setTop(top);
219
220                char str[100]; sprintf(str,": %d", 0);
221                mMyStatsFpsInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/MyFpsInfo");
222                mMyStatsFpsInfo->setCaption(str);
223
224                mMyStatsOverlay->show();
225        }
226
227        // loading view cells overlay
228        mLoadingOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/LoadingOverlay");
229        mMyLoadingInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/Loading/MyLoadingInfo");
230        mMyLoadingInfo->setCaption("loading view cells ...");
231
232        mLoadingOverlay->hide();
233
234        // hack: larger magnification for terrain to show single objects
235        if (TestCullingTerrainApplication::msShowHillyTerrain)
236                mVizScale = 25;
237        else
238                mVizScale = 1;
239
240        // the scale factor for the visualized bounding boxes
241        mSceneMgr->setOption("NodeVizScale", &mVizScale);
242
243        int assumedIncr;
244        mSceneMgr->getOption("AssumedVisibility", &assumedIncr);
245        changeAssumedVisibility(assumedIncr);
246
247        /////
248        // test geometry boundaries instead bounding box
249        mSceneMgr->getOption("TestGeometryBounds", &mTestGeometryBounds);
250        setTestGeometryBounds(mTestGeometryBounds);
251
252        /////////////////////////////////
253        // culling algorithm
254
255        bool isNormalExecution;
256               
257        mSceneMgr->getOption("NormalExecution", &isNormalExecution);
258       
259        if (isNormalExecution)
260                // no algorithm
261                mCurrentAlgorithm = GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS;
262        else
263                mSceneMgr->getOption("Algorithm", &mCurrentAlgorithm);
264       
265        // apply the chosen culling algorithm
266        applyCurrentAlgorithm();
267       
268
269        ///////////////////////////////
270        // set scene manager options
271       
272        //////////
273        mSceneMgr->getOption("TestGeometryForVisibleLeaves", &mTestGeometryForVisibleLeaves);
274        setTestGeometryForVisibleLeaves(mTestGeometryForVisibleLeaves);
275
276        /////////////
277        mSceneMgr->getOption("UseDepthPass", &mUseDepthPass);
278
279        if (mUseDepthPass)
280                mUseDepthPassInfo->setCaption(": true");
281        else
282                mUseDepthPassInfo->setCaption(": false");
283       
284        mSceneMgr->getOption("FlushQueue", &mFlushQueue);
285       
286        //////////
287        if (mFlushQueue)
288                LogManager::getSingleton().logMessage("initial setting: flushing queue");
289        else
290                LogManager::getSingleton().logMessage("initial setting: not flushing queue");
291
292        /////////////
293        mSceneMgr->setOption("ShowOctree", &mShowOctree);
294        mSceneMgr->setOption("ShowViewCells", &mShowViewCells);
295        mSceneMgr->setOption("CullCamera", &mCullCamera);
296        mSceneMgr->setOption("PrepareVisualization", &mShowVisualization);
297       
298        applyObjectType();
299
300
301        ///////////////
302        // initialize timer
303
304        mTimer = Root::getSingleton().getTimer();
305        mTimeFrameEnded = mTimeFrameStarted = mTimer->getMilliseconds();
306       
307        // reset statistics
308        mWalkthroughStats.Reset();
309
310}
311//-----------------------------------------------------------------------
312void TerrainFrameListener::switchMouseMode()
313{
314        mUseBufferedInputMouse = !mUseBufferedInputMouse;
315        mInputDevice->setBufferedInput(true, mUseBufferedInputMouse);
316
317        if (!mUseBufferedInputMouse)
318                CEGUI::MouseCursor::getSingleton().hide();
319        else
320                CEGUI::MouseCursor::getSingleton().show();
321}
322//-----------------------------------------------------------------------
323TerrainFrameListener::~TerrainFrameListener()
324{
325        OGRE_DELETE(mRayQueryExecutor);
326        OGRE_DELETE(mEventProcessor);
327        OGRE_DELETE(mQueryManager);
328}
329//-----------------------------------------------------------------------
330void TerrainFrameListener::mouseMoved(MouseEvent *e)
331{
332        // Update CEGUI with the mouse motion
333    CEGUI::System::getSingleton().injectMouseMove(e->getRelX() *
334                mGUIRenderer->getWidth(), e->getRelY() * mGUIRenderer->getHeight());
335}
336//-----------------------------------------------------------------------
337void TerrainFrameListener::mousePressed(MouseEvent* e)
338{
339        // Left mouse button down
340        if (e->getButtonID() & InputEvent::BUTTON0_MASK)
341        {
342                CEGUI::MouseCursor::getSingleton().hide();
343
344                // Setup the ray scene query
345                Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY());
346                Real val = Math::RangeRandom(0, 360); // random rotation
347
348                // get results, create a node/entity on the position
349                mCurrentObject =
350                        mTerrainContentGenerator->GenerateSceneObject(mouseRay.getOrigin(),
351                                                                                                                  Vector3(val, 0, 0),
352                                                                                                                  msObjectCaptions[mCurrentObjectType]);
353               
354                mLMouseDown = true;
355        }
356        // Right mouse button down
357        /*else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
358        {
359         CEGUI::MouseCursor::getSingleton().hide();
360         mRMouseDown = true;
361        }*/
362}
363//-----------------------------------------------------------------------
364void TerrainFrameListener::mouseDragDropped(MouseEvent* e)
365{
366        // Left mouse button up
367    if (e->getButtonID() & InputEvent::BUTTON0_MASK)
368    {
369                CEGUI::MouseCursor::getSingleton().show();
370               
371            mLMouseDown = false;
372    }
373    // Right mouse button up
374    else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
375    {
376        CEGUI::MouseCursor::getSingleton().show();
377
378                mRMouseDown = false;
379    }
380}
381//-----------------------------------------------------------------------
382void TerrainFrameListener::mouseReleased(MouseEvent* e)
383{
384    // Left mouse button up
385    if (e->getButtonID() & InputEvent::BUTTON0_MASK)
386    {
387                CEGUI::MouseCursor::getSingleton().show();
388               
389                // start animation: only robot has animation phases
390                if (mCurrentObject && (mCurrentObjectType == TestCullingTerrainApplication::ROBOT))
391                {
392                        // HACK: not neccesary the last element
393                        Entity *ent = mTerrainContentGenerator->GetGeneratedEntities()->back();
394                        EntityState *entState = new EntityState(ent, EntityState::MOVING, Math::RangeRandom(0.5, 1.5));
395                        mApplication->getEntityStates().push_back(entState);
396                }
397
398            mLMouseDown = false;
399    }
400    // Right mouse button up
401    else if (e->getButtonID() & InputEvent::BUTTON1_MASK)
402    {
403        CEGUI::MouseCursor::getSingleton().show();
404
405        mRMouseDown = false;
406    }
407}
408//-----------------------------------------------------------------------
409void TerrainFrameListener::mouseDragged(MouseEvent *e)
410{
411        // If we are dragging the left mouse button.             
412        if (mLMouseDown)
413    {
414                if (!mCurrentObject)
415                        return;
416
417                Vector3 queryResult;
418                Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY());
419
420                if (mRayQueryExecutor->executeRayQuery(&queryResult, mouseRay))
421                {
422                        // apply offset so object is ON terrain
423                        queryResult.y += msObjectTerrainOffsets[mCurrentObjectType];
424                        mCurrentObject->setPosition(queryResult);
425                }
426        }
427}
428//-----------------------------------------------------------------------
429bool TerrainFrameListener::frameStarted(const FrameEvent &evt)
430{
431        if (mWindow->isClosed())
432        {
433        return false;
434        }
435       
436        if (mDeleteObjects)
437        {
438                mApplication->deleteEntityStates();
439                mTerrainContentGenerator->RemoveGeneratedObjects();
440                mDeleteObjects = false;
441        }
442
443        if (mUseAnimation)
444        {
445                // update animation phases
446                mApplication->updateAnimations(evt.timeSinceLastFrame);
447        }
448
449        if (mDisplayCameraDetails)  // Print camera details
450    {       
451        mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
452                        " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation()));
453    }
454
455        //-- setup what is needed for immediate mouse/key movement
456        if (mTimeDelay >= 0)
457        {
458                mTimeDelay -= evt.timeSinceLastFrame;
459        }
460       
461        // If this is the first frame, pick a speed
462        if (evt.timeSinceLastFrame == 0)
463        {
464                mMoveScale = 1;
465                mRotScale = 0.1;
466        }
467        // Otherwise scale movement units by time passed since last frame
468        else
469        {
470                // Move about 100 units per second,
471                mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
472                // Take about 10 seconds for full rotation
473                mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
474        }
475
476        mRotX = 0;
477        mRotY = 0;
478        mTranslateVector = Vector3::ZERO;
479
480        if (!processUnbufferedKeyInput(evt))
481        {
482                return false;
483        }
484        if (!mUseBufferedInputMouse)
485        {
486                if (!processUnbufferedMouseInput(evt))
487                {       
488                        return false;   
489                }
490        }
491
492        if (mShowVisualization)
493        {
494                ////////////////
495                //-- set parameters for visualization
496
497                // draw octree bounding boxes because
498                // interesting for chc visualization
499                if (0 && mNodeVizMode != NODEVIZ_RENDER_PVS)
500                {
501                        mSceneMgr->setOption("ShowOctree", &mShowVisualization);
502                }
503               
504                ///////////////
505                //-- setup visualization camera
506
507                mVizCamera->setPosition(0, 0, 0);
508                mVizCamera->setOrientation(Quaternion::IDENTITY);
509
510                const Vector3 &camPos = mCamNode->getPosition();
511                mVizCamera->setPosition(camPos.x, mVizCameraHeight, camPos.z);
512
513                // point down -Z axis
514                mVizCamera->pitch(Radian(Degree(270.0)));
515
516                // rotation arounnd X axis
517                mVizCamera->yaw(Math::ATan2(-mCamera->getDerivedDirection().x,
518                        -mCamera->getDerivedDirection().z));
519               
520                // move by a constant so view plane is on "bottom" of viewport
521                mVizCamera->moveRelative(Vector3(0, mMoveFactor, 0));
522        }
523        else
524        {
525                // frame start time
526                mTimeFrameStarted = mTimer->getMilliseconds();
527        }
528
529        //////////////
530        //-- set application state
531
532        switch (mAppState)
533        {
534        case REPLAY:
535                /// set the current camera data to loaded frame information
536                setCurrentFrameInfo(evt.timeSinceLastFrame);
537
538                // HACK for demo: save new frame rates for the same walkthrough
539                if (mSavePrecomputedFps)
540                {
541                        addFrameInfo(mPrecomputedFpsFrameInfo, mCamNode, evt.timeSinceLastFrame);
542                }
543
544                break;
545        case WALKTHROUGH:
546                //-- recording the camera settings per frame
547                if (mRecordFrames)
548                {
549                        addFrameInfo(mFrameInfo, mCamNode, evt.timeSinceLastFrame);
550                        // print recording message
551                        mWindow->setDebugText("Recording frame " +
552                                StringConverter::toString((int)mFrameInfo.size() - 1));
553                }
554
555                // move camera according to input
556                moveCamera();
557
558                // clamp camera so we always walk along the terrain
559                if (TestCullingTerrainApplication::msShowHillyTerrain)
560                {
561                        mApplication->Clamp2Terrain(mCamNode, 5);
562                        //Ogre::LogManager::getSingleton().logMessage("clamp to terrain");
563                }
564                else
565                {
566                        mApplication->Clamp2FloorPlane(mFloorDist);
567                        //Ogre::LogManager::getSingleton().logMessage("clamp to floor");
568                }
569
570                break;
571
572        default:
573                Ogre::LogManager::getSingleton().logMessage("should not come here");
574                break;
575        };     
576
577        return true;
578}
579//-----------------------------------------------------------------------
580void TerrainFrameListener::applyVisibilityQuery(bool fromPoint,
581                                                                                                bool relativeVisibility,
582                                                                                                bool useItemBuffer)
583{
584        int itemBufferMode = useItemBuffer ? mItemBufferMode : 0;
585       
586        int queryModes = 0;
587        queryModes |= GtpVisibility::QueryManager::PATCH_VISIBILITY;
588        queryModes |= GtpVisibility::QueryManager::GEOMETRY_VISIBILITY;
589        queryModes |= GtpVisibility::QueryManager::NODE_VISIBILITY;
590
591        // no visibility manager available => no visibility scene manager, return
592        GtpVisibility::VisibilityManager *visManager = NULL;   
593        if (!mSceneMgr->getOption("VisibilityManager", &visManager))
594        {
595                Ogre::LogManager::getSingleton().logMessage("no vismanager found");
596                return;
597        }
598
599        PlatformHierarchyInterface *hierarchyInterface = NULL;
600        if (!mSceneMgr->getOption("HierarchyInterface", &hierarchyInterface))
601        {
602                Ogre::LogManager::getSingleton().logMessage("no hierarchy interface found");
603                return;
604        }
605
606        const bool approximateVisibility = false;
607
608        mQueryManager = new OcclusionQueriesQueryManager(hierarchyInterface,
609                                                                                                         mWindow->getViewport(0),
610                                                                                                         queryModes);
611
612        visManager->SetQueryManager(mQueryManager);
613
614        NodeInfoContainer visibleNodes;
615        MeshInfoContainer visibleGeometry;
616        PatchInfoContainer visiblePatches;
617
618        if (fromPoint)
619        {
620                mQueryManager->ComputeFromPointVisibility(mCamNode->getPosition(),
621                                                                                                  &visibleNodes,
622                                                                                                  &visibleGeometry,
623                                                                                                  &visiblePatches,
624                                                                                                  relativeVisibility,
625                                                                                                  approximateVisibility);
626        }
627        else
628        {
629                mQueryManager->ComputeCameraVisibility(*mCamera,
630                                                                                           &visibleNodes,
631                                                                                           &visibleGeometry,
632                                                                                           &visiblePatches,
633                                                                                           relativeVisibility,
634                                                                                           approximateVisibility);
635        }
636               
637        std::stringstream d;
638        d << "Query mode: " << queryModes << ", "
639          << msQueryTypeCaptions[fromPoint ?  1 : 0].c_str() << " "
640          << msQueryRelativeVisCaptions[relativeVisibility ? 1 : 0].c_str() << " "
641      << msQueryMethodCaptions[useItemBuffer ? 1 : 0].c_str();
642        LogManager::getSingleton().logMessage(d.str());
643
644
645        float averageNodeVis = 0, averageGeometryVis = 0, averagePatchVis = 0;
646        int geomSize = 0, nodesSize = 0, patchSize = 0;
647
648        /////////////////
649        //-- apply queries on geometry level
650
651        MeshInfoContainer::iterator geomIt, geomIt_end = visibleGeometry.end();
652
653        for (geomIt = visibleGeometry.begin(); geomIt != geomIt_end; ++geomIt)
654        {
655                // add if not 0
656                if ((*geomIt).GetVisiblePixels())
657                {
658                        float vis = relativeVisibility ?
659                                (*geomIt).ComputeRelativeVisibility() : (float)(*geomIt).GetVisiblePixels();
660       
661                        averageGeometryVis += vis;
662                        ++ geomSize;
663                       
664                        std::stringstream d;
665                        d << "Geometry " << geomSize << " id: " << (*geomIt).GetSource()->getSubEntity(0)->getId()
666                          << " visibility: "  << (*geomIt).GetVisiblePixels() << ", " << (*geomIt).GetProjectedPixels();
667                        LogManager::getSingleton().logMessage(d.str());
668                }
669        }
670
671
672        ////////////////
673        //-- apply queries on node level
674
675        NodeInfoContainer::iterator nodesIt, nodesIt_end = visibleNodes.end();
676
677        for (nodesIt = visibleNodes.begin(); nodesIt != nodesIt_end; ++nodesIt)
678        {
679                // add if not 0
680                if ((*nodesIt).GetVisiblePixels())
681                {
682                        float vis = relativeVisibility ?
683                                (*nodesIt).ComputeRelativeVisibility() : (float)(*nodesIt).GetVisiblePixels();
684               
685                        averageNodeVis += vis;
686                        ++ nodesSize;
687
688                        std::stringstream d; d << "Node visibility: " << vis;
689                        LogManager::getSingleton().logMessage(d.str());
690                }       
691        }
692
693
694        ////////////////
695        //-- apply queries on patch level
696
697
698        PatchInfoContainer::iterator patchIt, patchIt_end = visiblePatches.end();
699
700        for (patchIt = visiblePatches.begin(); patchIt != patchIt_end; ++ patchIt)
701        {
702                // add if not 0
703                if ((*patchIt).GetVisiblePixels())
704                {
705                        float vis = relativeVisibility ?
706                                (*patchIt).ComputeRelativeVisibility() : (float)(*patchIt).GetVisiblePixels();
707               
708                        averagePatchVis += vis;
709                        ++ patchSize;
710
711                        std::stringstream d; d << "Patch visibility: " << vis;
712                        LogManager::getSingleton().logMessage(d.str());
713                }       
714        }
715
716        ///////////////////////////////////////////////////////////////
717        //-- update visibility queries stats
718
719        if (nodesSize)
720                averageNodeVis /= (float)nodesSize;
721        if (geomSize)
722                averageGeometryVis /= (float)geomSize;
723        if (patchSize)
724                averagePatchVis /= (float)patchSize;
725
726
727    try
728        {
729                char str[100];
730               
731                sprintf(str, ": %s, %s, %s",
732                                msQueryTypeCaptions[fromPoint ?  1 : 0].c_str(),
733                                msQueryRelativeVisCaptions[relativeVisibility ? 1 : 0].c_str(),
734                                msQueryMethodCaptions[useItemBuffer ? 1 : 0].c_str());
735
736                mQueryTypeInfo->setCaption(str);
737
738                sprintf(str, ": %d", (int)nodesSize);
739                mQueryVisibleNodesInfo->setCaption(str);
740       
741                sprintf(str,": %d", (int)geomSize);
742                mQueryVisibleGeometryInfo->setCaption(str);
743               
744                sprintf(str,": %d", (int)patchSize);
745                mQueryVisiblePatchInfo->setCaption(str);
746
747                sprintf(str,": %3.3f", averageNodeVis);
748                mQueryNodeVisibilityInfo->setCaption(str);
749
750                sprintf(str,": %3.3f", averageGeometryVis);
751                mQueryGeometryVisibilityInfo->setCaption(str);
752
753                sprintf(str,": %3.3f", averagePatchVis);
754                mQueryPatchVisibilityInfo->setCaption(str);
755        }
756        catch (...)
757        {
758                // ignore
759        }
760
761        // show the results
762        if (!mShowQueryStats && !mShowHelp)
763        {
764                mQueryOverlay->show();
765                mShowQueryStats = true;
766        }
767
768        delete mQueryManager;
769}
770
771
772bool TerrainFrameListener::processUnbufferedMouseInput(const FrameEvent& evt)
773{
774        // Rotation factors, may not be used if the second mouse button is pressed.
775    // If the second mouse button is pressed, then the mouse movement results in
776    // sliding the camera, otherwise we rotate.
777    if (mInputDevice->getMouseButton(1))
778    {
779                mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13;
780                mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13;
781        }
782        else
783        {
784                mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13);
785                mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13);
786        }
787
788        return true;
789}
790//-----------------------------------------------------------------------
791bool TerrainFrameListener::frameEnded(const FrameEvent& evt)
792{
793        if (mShutdownRequested)
794                return false;
795
796        // timer end time
797        if (!mShowVisualization)
798        {
799                mTimeFrameEnded = mTimer->getMilliseconds();
800        }
801
802    updateStats();
803
804        if (mRecordVideo) // record current frame
805        {
806                takeVideoFrame(video_out);
807        }
808
809        //-- IMPORTANT: must be set, otherwise terrain is not rendered correctly
810        mSceneMgr->endFrame();
811
812        if (mTimeDelay <= 0) // simulates approx. one second
813                mTimeDelay = 1.0;
814
815        return true;
816}
817//-----------------------------------------------------------------------
818void TerrainFrameListener::moveCamera()
819{
820        // move node rather than camera so orientation is right in the visualization
821        mCamNode->yaw(mRotX, Ogre::Node::TS_WORLD);
822        //mCamNode->rotate(Vector3(0,1,0), mRotX, Ogre::Node::TS_WORLD);
823        mCamNode->pitch(mRotY);
824
825        mCamNode->translate(mCamNode->getLocalAxes(), mTranslateVector);
826}
827//-----------------------------------------------------------------------
828void TerrainFrameListener::writeFrames(const std::string filename,
829                                                                           const FrameInfoContainer &frameInfo) const
830{
831        std::ofstream ofstr(filename.c_str());
832        std::vector<frame_info>::const_iterator it, it_end;
833        it_end = frameInfo.end();
834
835        int i = 0;
836
837        for (it = frameInfo.begin(); it < it_end; ++ it, ++ i)
838        {
839                ofstr << StringConverter::toString((*it).position) << " "
840                          << StringConverter::toString((*it).orientation) << " "
841                          << StringConverter::toString((*it).timeElapsed) << " "
842                          << StringConverter::toString((*it).fps) << "\n";
843        }
844
845        std::stringstream d; d << "saved " << i << " frames to file " << filename;
846        Ogre::LogManager::getSingleton().logMessage(d.str());
847
848        ofstr.close();
849}
850//-----------------------------------------------------------------------
851void TerrainFrameListener::loadFrames(const std::string filename, 
852                                                                          FrameInfoContainer &frameInfo)
853{
854        std::ifstream ifstr(filename.c_str());
855        char line[256];
856        frame_info info;
857
858        // reset current values
859        frameInfo.clear();
860       
861        mCurrentFrame = 0;
862        int i = 0;
863        while (!ifstr.eof())
864        {
865                ifstr.getline(line, 256);
866                sscanf(line, "%f %f %f %f %f %f %f %f %f", &info.position.x, &info.position.y, &info.position.z,
867                           &info.orientation.w, &info.orientation.x, &info.orientation.y, &info.orientation.z,
868                           &info.timeElapsed, &info.fps);
869               
870                mFrameInfo.push_back(info);
871               
872                ++ i;
873        }
874       
875        std::stringstream d;
876        d << "loaded " << i << " frames from file " << filename;
877        Ogre::LogManager::getSingleton().logMessage(d.str());
878
879        ifstr.close();
880}
881//-----------------------------------------------------------------------
882void TerrainFrameListener::nextAppState()
883{
884        mCurrentFrame = 0;
885        int lastState = mAppState;
886
887        // transition to the next state
888        mAppState = (mAppState + 1) % STATE_NUM;
889
890        // if last state was replay state: post process
891        if (lastState == REPLAY)
892        {
893        // reset debug text
894                mWindow->setDebugText("");
895                               
896                // hack for producing demo:
897                // we produced precomputed fps during the last replay =>
898                // save them to file
899                if (mSavePrecomputedFps)
900                {
901                        std::string filename = msApprevAlgorithmCaptions[mCurrentAlgorithm] + "_frames.out";
902
903                        writeFrames(filename, mPrecomputedFpsFrameInfo);
904                        mPrecomputedFpsFrameInfo.clear();
905                }
906
907                std::stringstream d;
908                mWalkthroughStats.Print(d, msApprevAlgorithmCaptions[mCurrentAlgorithm]);
909               
910                LogManager::getSingleton().logMessage(d.str());
911        }
912       
913        //-- replay recorded walkthrough
914        if (mAppState == REPLAY)
915        {
916                // no standard recording during replay
917                mRecordFrames = false;
918
919                // no stats information
920                mWindow->setDebugText("");
921
922                // clear previous walktrough
923                mFrameInfo.clear();
924
925                std::string filename;
926               
927                // if recording demo,
928                // we use precomputed fps which corresponds to current method,
929                // e.g., for chc we load precomputed chc fps from disc.
930                if (mRecordDemo)
931                {
932                        filename = msApprevAlgorithmCaptions[mCurrentAlgorithm] + "_frames.out";
933                }
934                else // standard filename
935                {
936                        filename = frames_out_filename;
937                }
938
939                //-- load recorded walkthrough from disk
940                loadFrames(filename, mFrameInfo);
941               
942               
943                // if there are still no recorded frames,
944                // no walkthrough was recorded => set next state
945                if (mFrameInfo.empty())
946                {
947                        nextAppState();
948                }
949                else // actual replay
950                {
951                        mWindow->setDebugText("Replay");
952                       
953                        // reset, because we measure fps stats during walkthrough
954                        // (warning: average fps broken)
955                        mWindow->resetStatistics();
956                        mWalkthroughStats.Reset();
957
958                        //-- initialise frame data
959                        mReplayTimeElapsed = 0;
960
961                        mCamNode->setPosition(mFrameInfo[0].position);
962                        mCamNode->setOrientation(mFrameInfo[0].orientation);
963                }
964        }
965
966}
967//-----------------------------------------------------------------------
968void TerrainFrameListener::toggleRecord()
969{
970        mRecordFrames = !mRecordFrames;
971
972        if (mRecordFrames)
973        {
974                // starting new recording => clear old frame info
975                mFrameInfo.clear();
976        }
977        else // recording just ended => write frame info to file
978        {
979                writeFrames(frames_out_filename, mFrameInfo);
980                mWindow->setDebugText("");
981        }
982}
983//-----------------------------------------------------------------------
984void TerrainFrameListener::changeThreshold(int incr)
985{
986        mVisibilityThreshold += incr;
987
988        if (mVisibilityThreshold < 0)
989        {
990                mVisibilityThreshold = 0;
991        }
992
993        char str[100]; sprintf(str,": %d", mVisibilityThreshold);
994
995        mSceneMgr->setOption("Threshold", &mVisibilityThreshold);
996        mThresholdInfo->setCaption(str);
997}
998//-----------------------------------------------------------------------
999void TerrainFrameListener::changeAssumedVisibility(int incr)
1000{
1001        mAssumedVisibility += incr;
1002
1003        if (mAssumedVisibility < 0)
1004                mAssumedVisibility = 0;
1005
1006        char str[100]; sprintf(str,": %d", mAssumedVisibility);
1007
1008        mSceneMgr->setOption("AssumedVisibility", &mAssumedVisibility);
1009        mAssumedVisibilityInfo->setCaption(str);
1010}
1011//-----------------------------------------------------------------------
1012void TerrainFrameListener::changeVizScale(const int incr)
1013{
1014        mVizScale += incr;
1015
1016        if (mVizScale < 1)
1017                mVizScale = 1;
1018
1019        mSceneMgr->setOption("NodeVizScale", &mVizScale);
1020}
1021//-----------------------------------------------------------------------
1022void TerrainFrameListener::changeFloorDist(const float incr)
1023{
1024        mFloorDist += incr;
1025
1026        if (mFloorDist < 2)
1027        {       
1028                mFloorDist = 2;
1029        }
1030}
1031//-----------------------------------------------------------------------
1032void TerrainFrameListener::zoomVizCamera(int zoom)
1033{
1034        mVizCameraHeight += zoom;
1035
1036        if(mVizCameraHeight < 0)
1037                mVizCameraHeight = 0;
1038}
1039//-----------------------------------------------------------------------
1040void TerrainFrameListener::nextAlgorithm()
1041{
1042        // possible algorithms: 3 culling algorithms + standard rendering
1043        mCurrentAlgorithm = (mCurrentAlgorithm + 1) %
1044                (GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS + 1);
1045        applyCurrentAlgorithm();
1046}
1047//-----------------------------------------------------------------------
1048void TerrainFrameListener::applyObjectType()
1049{
1050        if (mCurrentObjectType >= 3) // TODO: define a constant
1051                mCurrentObjectType = 0;
1052
1053        // parameters for new object
1054        mTerrainContentGenerator->SetOffset(msObjectTerrainOffsets[mCurrentObjectType]);
1055        Real scale = msObjectScales[mCurrentObjectType];
1056        mTerrainContentGenerator->SetScale(Vector3(scale, scale, scale));
1057
1058        mCurrentObjectTypeInfo->setCaption(": " + msObjectCaptions[mCurrentObjectType]);
1059}
1060//-----------------------------------------------------------------------
1061void TerrainFrameListener::applyCurrentAlgorithm()
1062{
1063        bool isNormalExecution;
1064       
1065        if (mCurrentAlgorithm < GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS)
1066        {
1067                isNormalExecution = false;
1068                mSceneMgr->setOption("Algorithm", &mCurrentAlgorithm);
1069        }
1070        else
1071        {       // standard rendering without changed render queue flow
1072                isNormalExecution = true;
1073        }
1074       
1075        mSceneMgr->setOption("NormalExecution", &isNormalExecution);
1076        mAlgorithmInfo->setCaption(": " + msAlgorithmCaptions[mCurrentAlgorithm]);
1077
1078        if (1)
1079        {
1080                std::stringstream d; d << "algorithm: " << msAlgorithmCaptions[mCurrentAlgorithm];
1081                Ogre::LogManager::getSingleton().logMessage(d.str());
1082        }
1083}
1084//-----------------------------------------------------------------------
1085void TerrainFrameListener::updateStats()
1086{
1087        unsigned int opt = 0;
1088        char str[100];
1089       
1090        static String currFpsString = "Current FPS: ";
1091        static String avgFpsString = "Average FPS: ";
1092        static String bestFpsString = "Best FPS: ";
1093        static String worstFpsString = "Worst FPS: ";
1094        static String trisString = "Triangle Count: ";
1095
1096        int currentFps;
1097       
1098        // HACK for demo: use precomputed FPS instead of real FPS
1099        if (mRecordDemo)
1100        {
1101                currentFps = mPrecomputedFps;
1102        }
1103        else
1104        {
1105                currentFps = mWindow->getStatistics().lastFPS;
1106        }
1107
1108#if 0
1109        // HACK: take pure rendering time, only measures the render call
1110        long pureRenderTime = mTimeFrameEnded - mTimeFrameStarted;
1111
1112        if (pureRenderTime)
1113        {
1114                mPureRenderTimeFps = 1000.0f / (float) pureRenderTime;
1115        }
1116        currentFps = mPureRenderRenderTimeFps;
1117        //std::stringstream d; d << "Pure render time fps: " << mPureRenderTimeFps << "\n";
1118        //Ogre::LogManager::getSingleton().logMessage(d.str());
1119#endif
1120       
1121        unsigned int nodeInfo[3];
1122    mSceneMgr->getOption("NumRenderedNodes", nodeInfo);
1123        mSceneMgr->getOption("NumQueryCulledNodes", nodeInfo+1);
1124        mSceneMgr->getOption("NumFrustumCulledNodes", nodeInfo+2);
1125
1126
1127        mWalkthroughStats.UpdateFrame(currentFps,
1128                                                                  mWindow->getBestFPS(),
1129                                                                  mWindow->getWorstFPS(),
1130                                                                  (int)mWindow->getTriangleCount(),
1131                                                                  nodeInfo[0],
1132                                                                  nodeInfo[1],
1133                                                                  nodeInfo[2]);
1134
1135        // HACK: compute average fps ourselfs, because ogre avg. fps is wrong
1136        // TODO: update only once per second
1137        float avgFps = (float)mWalkthroughStats.mAccFps / (float)(mWalkthroughStats.mFrameCount);
1138       
1139
1140        // update stats when necessary
1141    try
1142        {
1143                OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
1144                OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
1145                OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
1146                OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
1147
1148                const RenderTarget::FrameStats& stats = mWindow->getStatistics();
1149
1150                // HACK: take newly computed avg. fps instead of Ogre avg fps and update only once per second
1151                if (mTimeDelay < 0)
1152                {               
1153                        guiAvg->setCaption(avgFpsString + StringConverter::toString(avgFps) + " ms");
1154                        //guiCurr->setCaption(currFpsString + StringConverter::toString(currentFps));
1155                }
1156
1157                if (0)
1158                {
1159                        std::stringstream d;
1160                        d << "fps: " << StringConverter::toString(currentFps) << ", "
1161                          << "avg fps: " << StringConverter::toString(avgFps);
1162                        LogManager::getSingleton().logMessage(d.str());
1163                }
1164
1165                //guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
1166                guiCurr->setCaption(currFpsString + StringConverter::toString(currentFps));
1167               
1168                //std::stringstream d; d << "frame rate :" << stats.lastFPS;
1169                //Ogre::LogManager::getSingleton().logMessage(d.str());
1170
1171                guiBest->setCaption(bestFpsString + StringConverter::toString(stats.bestFPS)
1172                                                        + " " + StringConverter::toString(stats.bestFrameTime) + " ms");
1173                guiWorst->setCaption(worstFpsString + StringConverter::toString(stats.worstFPS)
1174                                                         + " " + StringConverter::toString(stats.worstFrameTime) + " ms");
1175
1176                OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
1177        guiTris->setCaption(trisString + StringConverter::toString(stats.triangleCount));
1178               
1179                //LogManager::getSingleton().logMessage(StringConverter::toString(stats.triangleCount));
1180
1181                OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
1182                guiDbg->setCaption(mWindow->getDebugText());
1183
1184
1185                //-- culling stats
1186
1187                mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt);
1188                mFrustumCulledNodesInfo->setCaption(str);
1189
1190                mSceneMgr->getOption("NumQueryCulledNodes", &opt); sprintf(str,": %d", opt);
1191                mQueryCulledNodesInfo->setCaption(str);
1192       
1193                mSceneMgr->getOption("NumHierarchyNodes", &opt); sprintf(str,": %d", opt);
1194                mHierarchyNodesInfo->setCaption(str);
1195
1196                mSceneMgr->getOption("NumRenderedNodes", &opt); sprintf(str,": %d", opt);
1197                mRenderedNodesInfo->setCaption(str);
1198
1199                sprintf(str,": %d", mTerrainContentGenerator->GetObjectCount());
1200                mObjectsCountInfo->setCaption(str);
1201
1202                // take old value into account in order to create no sudden changes
1203                mSceneMgr->getOption("NumQueriesIssued", &opt);
1204                mDelayedQueriesIssued = mDelayedQueriesIssued * 0.8 + (float)opt * 0.2f;
1205                sprintf(str,": %d", (int)mDelayedQueriesIssued);
1206                mQueriesIssuedInfo->setCaption(str);
1207
1208                mSceneMgr->getOption("NumTraversedNodes", &opt);
1209                mDelayedTraversedNodes = mDelayedTraversedNodes * 0.8 + (float)opt * 0.2f;
1210                sprintf(str,": %d", (int)mDelayedTraversedNodes);
1211                mTraversedNodesInfo->setCaption(str);
1212
1213                if (mRecordVideo)
1214                {
1215                        // update stats for demo
1216                        mMyStatsAlgorithmInfo->setCaption(msApprevAlgorithmCaptions[mCurrentAlgorithm]);
1217                        sprintf(str,": %d", (int)currentFps);
1218                        mMyStatsFpsInfo->setCaption(str);
1219                }
1220
1221        }
1222        catch (...)
1223        {
1224                // ignore
1225        }
1226}
1227//-----------------------------------------------------------------------
1228void TerrainFrameListener::setTestGeometryForVisibleLeaves(bool testGeometryForVisibleLeaves)
1229{
1230        mSceneMgr->setOption("TestGeometryForVisibleLeaves", &mTestGeometryForVisibleLeaves);
1231       
1232        // disable optimization for transparent objects, becaue otherwise visible
1233        // transparents could be skipped
1234        if (mTestGeometryForVisibleLeaves)
1235                mTestGeometryForVisibleLeavesInfo->setCaption(": true");
1236        else
1237                mTestGeometryForVisibleLeavesInfo->setCaption(": false");
1238}
1239//-----------------------------------------------------------------------
1240void TerrainFrameListener::setTestGeometryBounds(bool testGeometryBounds)
1241{
1242        mSceneMgr->setOption("TestGeometryBounds", &mTestGeometryBounds);
1243       
1244        if (mTestGeometryBounds)
1245                LogManager::getSingleton().logMessage("Testing geometry boundaries");
1246        else
1247                LogManager::getSingleton().logMessage("Testing bounding box of hierarchy node");
1248}
1249
1250//-----------------------------------------------------------------------
1251void TerrainFrameListener::toggleShowOctree()
1252{
1253        mShowOctree = !mShowOctree;
1254        mSceneMgr->setOption("ShowOctree", &mShowOctree);
1255}
1256//-----------------------------------------------------------------------
1257void TerrainFrameListener::toggleShowViewCells()
1258{
1259        mShowViewCells = !mShowViewCells;
1260        mSceneMgr->setOption("ShowViewCells", &mShowViewCells);
1261}
1262//-----------------------------------------------------------------------
1263void TerrainFrameListener::toggleUseViewCells()
1264{
1265        // HACK: no view cells for hilly terrain
1266        if (mApplication->msShowHillyTerrain)
1267                return;
1268
1269        mUseViewCells = !mUseViewCells;
1270
1271        // load on demand
1272        if (mUseViewCells)// && !mViewCellsLoaded)
1273        {
1274                LogManager::getSingleton().logMessage("using view cells");
1275                mLoadingOverlay->show();
1276
1277                // call once to load view cell loading overlay
1278                mWindow->update();
1279                mViewCellsLoaded = mApplication->LoadViewCells(mApplication->mViewCellsFilename);
1280               
1281                if (!mViewCellsLoaded)
1282                        LogManager::getSingleton().logMessage("loading view cells failed");
1283                else
1284                        LogManager::getSingleton().logMessage("view cells successfully loaded");
1285       
1286                mLoadingOverlay->hide();
1287        }
1288
1289        if (mUseViewCells)
1290                mViewCellsInfo->setCaption(": on");
1291        else
1292                mViewCellsInfo->setCaption(": off");
1293
1294        mSceneMgr->setOption("UseViewCells", &mUseViewCells);
1295}
1296//-----------------------------------------------------------------------
1297void TerrainFrameListener::toggleUseDepthPass()
1298{
1299        mUseDepthPass = !mUseDepthPass;
1300
1301        mSceneMgr->setOption("UseDepthPass", &mUseDepthPass);
1302       
1303        if (mUseDepthPass)
1304        {
1305                mUseDepthPassInfo->setCaption(": true");
1306        }
1307        else
1308        {
1309                mUseDepthPassInfo->setCaption(": false");
1310        }
1311}
1312//-----------------------------------------------------------------------
1313void TerrainFrameListener::toggleFlushQueue()
1314{
1315        mFlushQueue = !mFlushQueue;
1316
1317        mSceneMgr->setOption("FlushQueue", &mFlushQueue);
1318       
1319        if (mFlushQueue)
1320        {
1321                LogManager::getSingleton().logMessage("flushing queue");
1322                //mFlushQueueInfo->setCaption(": true");
1323        }
1324        else
1325        {
1326                LogManager::getSingleton().logMessage("not flushing queue");
1327                //mFlushQueueInfo->setCaption(": false");
1328        }
1329}
1330
1331void TerrainFrameListener::showBoundingBoxes()
1332{
1333        m_iShowBoundingBoxes++;
1334        m_iShowBoundingBoxes%=2;
1335        mSceneMgr->setOption("ShowBiHierarchy", (void*)&m_iShowBoundingBoxes);
1336}
1337
1338
1339//-----------------------------------------------------------------------
1340void TerrainFrameListener::toggleShowViz()
1341{
1342        mVisualizeCulledNodes = mShowVisualization = !mShowVisualization;
1343       
1344        // create viewport with priority VIZ_VIEWPORT_Z_ORDER:
1345        // will be rendered over standard viewport
1346        if (mShowVisualization)
1347        {       
1348                Viewport *vizvp = mWindow->addViewport(mVizCamera,
1349                        VIZ_VIEWPORT_Z_ORDER, 0.6, 0.6, 0.4, 0.4);
1350                               
1351                vizvp->setBackgroundColour(ColourValue(0.0, 0.3, 0.2, 1));
1352
1353                vizvp->setOverlaysEnabled(false);
1354                // Alter the camera aspect ratio to match the viewport
1355        mVizCamera->setAspectRatio(Real(vizvp->getActualWidth()) /
1356                                                                   Real(vizvp->getActualHeight()));
1357               
1358                mSceneMgr->setOption("VisualizeCulledNodes", &mVisualizeCulledNodes);
1359       
1360        }
1361        else
1362        {
1363                // remove visualization viewport
1364                mWindow->removeViewport(VIZ_VIEWPORT_Z_ORDER);
1365
1366                // octree bounding boxes are shown for visualization purpose, reset now
1367                mSceneMgr->setOption("ShowOctree", &mShowOctree);
1368        }
1369}
1370//-----------------------------------------------------------------------
1371void TerrainFrameListener::toggleShowShadows()
1372{
1373        mShowShadows = !mShowShadows;
1374
1375        mSunLight->setCastShadows(mShowShadows);
1376
1377        if (mShowShadows)
1378        {
1379                mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
1380                //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
1381                //mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);           
1382        }
1383        else
1384        {
1385                mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE);
1386        }
1387
1388}
1389//-----------------------------------------------------------------------
1390void TerrainFrameListener::nextNodeVizMode()
1391{
1392        mNodeVizMode = (mNodeVizMode + 1) % NODEVIZ_MODES_NUM;
1393
1394        bool renderNodesForViz =
1395                (mNodeVizMode == NODEVIZ_RENDER_NODES) ||
1396                (mNodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
1397
1398        bool renderNodesContentForViz = (mNodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
1399        //bool renderNodesContentForViz = mNodeVizMode == NODEVIZ_RENDER_GEOMETRY;
1400
1401        bool renderPvsForViz = (mNodeVizMode == NODEVIZ_RENDER_PVS);
1402
1403        mSceneMgr->setOption("RenderNodesForViz", &renderNodesForViz);
1404        mSceneMgr->setOption("RenderNodesContentForViz", &renderNodesContentForViz);
1405        mSceneMgr->setOption("RenderPvsForViz", &renderPvsForViz);
1406}
1407//-----------------------------------------------------------------------
1408void TerrainFrameListener::keyPressed(KeyEvent* e)
1409{
1410        // hide exact visibility query overlay
1411        if (mShowQueryStats)
1412        {
1413                mQueryOverlay->hide();
1414                mShowQueryStats = false;
1415        }
1416
1417        switch(e->getKey())
1418        {
1419       
1420        case KC_SUBTRACT:
1421                changeThreshold(-10);
1422                break;
1423        case KC_ADD:
1424                changeThreshold(10);
1425                break;
1426
1427        // assumed visible #frames
1428        case KC_9:
1429                changeAssumedVisibility(-5);
1430                break;
1431        case KC_0:
1432                changeAssumedVisibility(5);
1433                break;
1434
1435        case KC_ESCAPE:
1436                mShutdownRequested = true;
1437                e->consume();
1438                return;
1439        // the visibility algorithm
1440        case KC_SPACE:
1441                nextAlgorithm();
1442                break;
1443        case KC_LSHIFT:
1444                mShiftPressed = true;
1445                break;
1446        case KC_DELETE:
1447                mDeleteObjects = true;
1448                break;
1449        // not working yet
1450        case KC_C:
1451                if (mItemBufferMode != GtpVisibility::QueryManager::GEOMETRY_VISIBILITY)
1452                {
1453                        mItemBufferMode = GtpVisibility::QueryManager::GEOMETRY_VISIBILITY;
1454                }
1455                else
1456                {
1457                        mItemBufferMode = GtpVisibility::QueryManager::PATCH_VISIBILITY;
1458                }
1459                break;
1460         case KC_E: // hack for recording demo using precomputed fps
1461                mSavePrecomputedFps = !mSavePrecomputedFps;
1462                break;
1463    case KC_F:
1464                nextFilter();
1465                break;
1466        case KC_G:
1467                mTestGeometryForVisibleLeaves = !mTestGeometryForVisibleLeaves;
1468                setTestGeometryForVisibleLeaves(mTestGeometryForVisibleLeaves);
1469                break;
1470        case KC_H:
1471                toggleShowShadows();
1472                break;
1473        case KC_L:
1474                toggleShowViewCells();
1475                break;
1476        case KC_M: // hack for recording demo using precomputed fps
1477                mRecordDemo = !mRecordDemo;
1478                break;
1479        case KC_O:
1480                switchMouseMode();
1481                break;
1482        case KC_P:
1483                toggleDisplayCameraDetails();
1484                break;
1485        // if view cells + PVS are used for rendering
1486        case KC_V:
1487                toggleUseViewCells();
1488                break;
1489        case KC_Q:
1490                mTestGeometryBounds = !mTestGeometryBounds;
1491                setTestGeometryBounds(mTestGeometryBounds);
1492                break;
1493        case KC_R:
1494                nextSceneDetailLevel();
1495                break;
1496        case KC_T:
1497                toggleShowOctree();
1498                break;
1499        case KC_U:
1500                mCamNode->resetOrientation();
1501                mCamNode->setPosition(mApplication->mInitialPosition);
1502                break;
1503        case KC_X:
1504                toggleUseDepthPass();
1505                break;
1506        case KC_I:
1507                toggleFlushQueue();
1508                break;
1509        case KC_Z:
1510                mCamNode->resetOrientation();
1511                break;
1512        case KC_B:
1513                showBoundingBoxes();
1514                break;
1515        case KC_3:
1516                if (m_iBoundingBoxLevel>0) m_iBoundingBoxLevel--;
1517                mSceneMgr->setOption("HiLiteLevel", (void*)&m_iBoundingBoxLevel);
1518                break;
1519        case KC_4:
1520                m_iBoundingBoxLevel++;
1521                mSceneMgr->setOption("HiLiteLevel", (void*)&m_iBoundingBoxLevel);
1522                break;
1523
1524
1525        ///////////////
1526        //-- visualization
1527
1528        case KC_1:
1529                toggleShowViz();
1530                break;
1531        case KC_2:
1532                nextNodeVizMode();
1533                break;
1534       
1535        case KC_F12:
1536                {
1537                        LogManager::getSingleton().logMessage("generating 500 objects");
1538                        // generate new objects
1539                        const int numObjects = 500;
1540                        mApplication->generateScene(numObjects, mCurrentObjectType);
1541                }
1542                break;
1543        case KC_F1:
1544                toggleShowHelp();
1545                break;
1546        case KC_F2:
1547                mStatsOn = !mStatsOn;
1548                showStats(mStatsOn);
1549                break;
1550        case KC_F3:
1551                nextAppState();
1552                break;
1553        case KC_F4:
1554                toggleRecord();
1555                break;
1556        case KC_F5:
1557                {
1558                        mSceneMgr->_findVisibleObjects(mCamera, false);
1559                        if (0) applyVisibilityQuery(false, mShiftPressed, mUseItemBuffer);
1560                        break;
1561                }
1562        case KC_F6:
1563                {
1564                        const bool fromPoint = true;
1565                        if (1) applyVisibilityQuery(fromPoint, mShiftPressed, mUseItemBuffer);
1566                        break;
1567                }       
1568        // change type of object to be generated
1569        case KC_F7:
1570                ++ mCurrentObjectType;
1571                applyObjectType();
1572                break;
1573        case KC_F8:
1574                mTerrainContentGenerator->WriteObjects(objects_out_filename);
1575                break;
1576        case KC_F9:
1577                mUseAnimation = !mUseAnimation;
1578                break;
1579        case KC_F10:
1580                mRecordVideo = !mRecordVideo;
1581                break;         
1582        case KC_F11:
1583                takeScreenshot();
1584                break;
1585        default:
1586                break;
1587        }
1588
1589        CEGUI::System::getSingleton().injectKeyDown(e->getKey());
1590        CEGUI::System::getSingleton().injectChar(e->getKeyChar());
1591        e->consume();
1592}
1593//-----------------------------------------------------------------------
1594void TerrainFrameListener::keyReleased(KeyEvent* e)
1595{
1596        if (e->getKey() == KC_LSHIFT)
1597        {
1598                mShiftPressed = false;
1599        }
1600       
1601        CEGUI::System::getSingleton().injectKeyUp(e->getKey());
1602        e->consume();
1603}
1604//-----------------------------------------------------------------------
1605void TerrainFrameListener::keyClicked(KeyEvent* e)
1606{
1607        // Do nothing
1608        e->consume();
1609}
1610//-----------------------------------------------------------------------
1611void TerrainFrameListener::addFrameInfo(FrameInfoContainer &frameInfos,
1612                                                                                SceneNode *camNode,
1613                                                                                Real timeElapsed)
1614{
1615        frame_info info;
1616
1617        info.orientation = mCamNode->getOrientation();
1618        info.position = mCamNode->getPosition();
1619        info.timeElapsed = timeElapsed;
1620        info.fps = mWindow->getStatistics().lastFPS;
1621
1622        frameInfos.push_back(info);
1623}
1624//-----------------------------------------------------------------------
1625void TerrainFrameListener::setCurrentFrameInfo(const Real timeElapsed)
1626{
1627        //-- find current frame relative to elapsed frame time         
1628        mReplayTimeElapsed -= timeElapsed;
1629       
1630        while ((mReplayTimeElapsed <= 0) && (mCurrentFrame < (int)mFrameInfo.size() - 1))
1631        {
1632                mReplayTimeElapsed += mFrameInfo[mCurrentFrame ++].timeElapsed;
1633        }
1634
1635
1636        // TODO: crashes here if recording / replaying on the same time!!
1637        const frame_info new_frame = mFrameInfo[mCurrentFrame];
1638        const frame_info old_frame = mFrameInfo[mCurrentFrame - 1];
1639               
1640        /////////////
1641        //-- interpolate frames
1642        Real factor = 1;
1643
1644        if (old_frame.timeElapsed > 0)
1645        {
1646                factor = mReplayTimeElapsed / old_frame.timeElapsed;
1647        }
1648
1649        const Vector3 camPos = old_frame.position + factor
1650                * (new_frame.position - old_frame.position);
1651
1652        // interpolate the orientation
1653        const Quaternion camOrienation =
1654                Quaternion::Slerp(factor, old_frame.orientation, new_frame.orientation, true);
1655
1656        // HACK for demo: interpolate precomputed fps
1657        mPrecomputedFps = old_frame.fps + factor * (new_frame.fps - old_frame.fps);
1658
1659        mCamNode->setPosition(camPos);
1660        mCamNode->setOrientation(camOrienation);
1661       
1662        // stop replaying after one full walkthrough
1663        if (mCurrentFrame == (int)mFrameInfo.size() - 1)
1664        {
1665                nextAppState();
1666        }
1667}
1668//-----------------------------------------------------------------------   
1669bool TerrainFrameListener::processUnbufferedKeyInput(const FrameEvent& evt)
1670{
1671        bool cursorPressed = false;
1672       
1673        /* Move camera forward by keypress. */
1674    if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W))
1675        {
1676                mTranslateVector.z = -mMoveScale;
1677                cursorPressed = true;
1678        }
1679    /* Move camera backward by keypress. */
1680    if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S))
1681    {
1682                mTranslateVector.z = mMoveScale;
1683                cursorPressed = true;
1684    }
1685
1686        if (mInputDevice->isKeyDown(KC_A))
1687        {
1688                mTranslateVector.x -= mMoveScale;
1689                mTranslateVector.y += mMoveScale;
1690
1691                cursorPressed = true;
1692        }
1693
1694        if (mInputDevice->isKeyDown(KC_D))
1695        {
1696                mTranslateVector.x += mMoveScale;
1697                mTranslateVector.y -= mMoveScale;
1698
1699                cursorPressed = true;
1700        }
1701
1702    if (mInputDevice->isKeyDown(KC_RIGHT))
1703    {
1704        mCamNode->yaw(-mRotScale, Ogre::Node::TS_WORLD);
1705                cursorPressed = true;
1706    }
1707
1708    if (mInputDevice->isKeyDown(KC_LEFT))
1709    {
1710        mCamNode->yaw(mRotScale, Ogre::Node::TS_WORLD);
1711                cursorPressed = true;
1712    }
1713
1714        // visualization camera
1715        if (mInputDevice->isKeyDown(KC_3))
1716                zoomVizCamera(50);
1717
1718        if (mInputDevice->isKeyDown(KC_4))
1719                zoomVizCamera(-50);
1720
1721        // scale of the visualized objects
1722#if 0
1723        if (mInputDevice->isKeyDown(KC_5))
1724                changeVizScale(-1);
1725
1726        if (mInputDevice->isKeyDown(KC_6))
1727                changeVizScale(1);
1728#else
1729
1730        const int mFactor = 20;
1731        if (mInputDevice->isKeyDown(KC_5))
1732                mMoveFactor += mFactor;
1733
1734        if (mInputDevice->isKeyDown(KC_6))
1735                mMoveFactor -= mFactor;
1736#endif
1737
1738        // distance to floor
1739        if (mInputDevice->isKeyDown(KC_7))
1740                changeFloorDist(-1);
1741
1742        if (mInputDevice->isKeyDown(KC_8))
1743                changeFloorDist(1);
1744
1745
1746        // show the results
1747        if (cursorPressed && mShowQueryStats)
1748        {
1749                mQueryOverlay->hide();
1750                mShowQueryStats = false;
1751        }
1752
1753    // Return true to continue rendering
1754    return true;
1755}
1756//-----------------------------------------------------------------------
1757void TerrainFrameListener::nextFilter()
1758{
1759        switch (mFiltering)
1760        {
1761        case TFO_BILINEAR:
1762                mFiltering = TFO_TRILINEAR;
1763                mAniso = 1;
1764                break;
1765        case TFO_TRILINEAR:
1766                mFiltering = TFO_ANISOTROPIC;
1767                mAniso = 8;
1768                break;
1769        case TFO_ANISOTROPIC:
1770                mFiltering = TFO_BILINEAR;
1771                mAniso = 1;
1772                break;
1773        default:
1774                break;
1775        }
1776
1777    MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
1778    MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
1779
1780        // reload stats
1781    showStats(mStatsOn);
1782}
1783//-----------------------------------------------------------------------
1784void TerrainFrameListener::nextSceneDetailLevel()
1785{
1786#if OGRE_103
1787        mSceneDetailIndex = (mSceneDetailIndex + 1) % 3;
1788        switch (mSceneDetailIndex)
1789        {
1790                case 0:
1791                        mCamera->setDetailLevel(SDL_SOLID);
1792                        break;
1793                case 1:
1794                        mCamera->setDetailLevel(SDL_WIREFRAME);
1795                        break;
1796                case 2:
1797                        mCamera->setDetailLevel(SDL_POINTS);
1798                        break;
1799        }
1800#endif
1801}
1802//-----------------------------------------------------------------------
1803void TerrainFrameListener::takeVideoFrame(std::ofstream &ofstr)
1804{
1805        char name[50];
1806
1807        sprintf(name, "frame_%05d.tga", ++mNumVideoFrames);
1808    mWindow->writeContentsToFile(name);
1809    //mWindow->setDebugText(String("Wrote ") + name);
1810
1811        ofstr << name << "\n";
1812}
1813//-----------------------------------------------------------------------
1814void TerrainFrameListener::takeScreenshot()
1815{
1816        char name[50];
1817
1818        sprintf(name, "screenshot_%05d.png", ++mNumScreenShots);
1819    mWindow->writeContentsToFile(name);
1820    //mWindow->setDebugText(String("Wrote ") + name);
1821}
1822//-----------------------------------------------------------------------
1823void TerrainFrameListener::toggleDisplayCameraDetails()
1824{
1825        mDisplayCameraDetails = !mDisplayCameraDetails;
1826       
1827    if (!mDisplayCameraDetails)
1828        {
1829                mWindow->setDebugText("");
1830        }
1831}
1832//-----------------------------------------------------------------------
1833void TerrainFrameListener::showStats(bool show)
1834{
1835        if (mDebugOverlay && mCullStatsOverlay)
1836        {
1837                if (show)
1838                {
1839                        mDebugOverlay->show();
1840                        mCullStatsOverlay->show();
1841                }
1842                else
1843                {
1844                        mDebugOverlay->hide();
1845                        mCullStatsOverlay->hide();
1846                }
1847        }
1848}
1849
1850//-----------------------------------------------------------------------
1851void TerrainFrameListener::toggleShowHelp()
1852{
1853        mShowHelp = !mShowHelp;
1854
1855        if (mShowHelp)
1856        {
1857                mHelpOverlay->show();
1858        }
1859        else
1860        {
1861                mHelpOverlay->hide();
1862        }
1863}
1864//-----------------------------------------------------------------------
1865void TerrainFrameListener::initOverlayElement(OverlayElement **elInfo, String ext,
1866                                                                                          String name, int top, String caption)
1867{
1868        OverlayElement *el =
1869                OverlayManager::getSingleton().getOverlayElement(ext + name);
1870
1871        (*elInfo) = OverlayManager::getSingleton().getOverlayElement(ext + name + "Info");
1872        (*elInfo)->setCaption(caption);
1873
1874        el->setTop(top);
1875        (*elInfo)->setTop(top);
1876}
1877//-----------------------------------------------------------------------
1878void TerrainFrameListener::initHelpOverlayElement(String name, int top)
1879{
1880        OverlayElement *el = OverlayManager::getSingleton().getOverlayElement(
1881                "Example/Visibility/Help/" + name);
1882
1883        el->setTop(top);
1884}
1885//-----------------------------------------------------------------------
1886void TerrainFrameListener::initHelpOverlay()
1887{
1888        const int vert_space = 15;
1889        int top = 30;
1890
1891        initHelpOverlayElement("ShowHelp", top); top += vert_space;
1892        initHelpOverlayElement("Stats", top); top += vert_space;
1893        initHelpOverlayElement("AppState", top); top += vert_space;
1894        initHelpOverlayElement("Recorded", top); top += vert_space;
1895        initHelpOverlayElement("Animation", top); top += vert_space;
1896        initHelpOverlayElement("Video", top); top += vert_space;
1897        initHelpOverlayElement("Screenshots", top); top += vert_space;
1898        initHelpOverlayElement("WriteOut", top); top += vert_space;
1899
1900
1901        top +=vert_space;
1902        initHelpOverlayElement("SceneDetail", top); top += vert_space;
1903        initHelpOverlayElement("DisplayCameraDetails", top); top += vert_space;
1904        initHelpOverlayElement("DisplayOctree", top); top += vert_space;
1905        initHelpOverlayElement("UseShadows", top); top += vert_space;
1906        initHelpOverlayElement("Filter", top); top += vert_space;
1907
1908        //-- visualization
1909        top += vert_space;
1910        initHelpOverlayElement("VizSection", top); top += vert_space;
1911        initHelpOverlayElement("Viz", top); top += vert_space;
1912        initHelpOverlayElement("NextVizMode", top); top += vert_space;
1913        initHelpOverlayElement("ZoomViz", top); top += vert_space;
1914
1915
1916        //-- visibility queries
1917        top += vert_space;
1918        initHelpOverlayElement("VisQuery", top); top += vert_space;
1919        initHelpOverlayElement("FromCameraQuery", top); top += vert_space;
1920        initHelpOverlayElement("FromPointQuery", top); top += vert_space;
1921        initHelpOverlayElement("QueryType", top); top += vert_space;
1922        initHelpOverlayElement("QueryTarget", top); top += vert_space;
1923
1924        //-- object generation
1925        top += vert_space;
1926        initHelpOverlayElement("SceneObjects", top); top += vert_space;
1927        initHelpOverlayElement("PlaceObjects", top); top += vert_space;
1928        initHelpOverlayElement("GenerateObjects", top); top += vert_space;
1929        initHelpOverlayElement("RemoveObjects", top); top += vert_space;
1930        initHelpOverlayElement("DropObject", top); top += vert_space;
1931
1932        OverlayElement *helpPanel = OverlayManager::getSingleton().getOverlayElement(
1933                "Example/Visibility/Help/HelpPanel");
1934
1935        helpPanel->setHeight(top + 10);
1936}
1937//-----------------------------------------------------------------------
1938void TerrainFrameListener::initVisStatsOverlay()
1939{
1940        const int border_height = 10;
1941        const int vert_space = 15;
1942
1943        //-- visibility culling stats overlay
1944        int top = border_height;
1945
1946        String ext = "Example/Visibility/";
1947       
1948        initOverlayElement(&mAlgorithmInfo, ext, "Algorithm", top,
1949                ": " + msAlgorithmCaptions[mCurrentAlgorithm]); top += vert_space;
1950
1951        initOverlayElement(&mThresholdInfo, ext, "Threshold", top, ": 0"); top += vert_space;
1952        initOverlayElement(&mTestGeometryForVisibleLeavesInfo, ext,
1953                                           "TestGeometryForVisibleLeaves", top, ": true"); top += vert_space;
1954        initOverlayElement(&mUseDepthPassInfo, ext, "UseDepthPass", top, ": false"); top += vert_space;
1955        initOverlayElement(&mAssumedVisibilityInfo, ext, "AssumedVisibility", top, ": 0"); top += vert_space;
1956        initOverlayElement(&mCurrentObjectTypeInfo, ext, "CurrentObjectType", top, ": "); top += vert_space;
1957        initOverlayElement(&mViewCellsInfo, ext, "ViewCells", top, ": "); top += vert_space;
1958        //initOverlayElement(&mHelpInfo, ext, "Help", top, ": "); top += vert_space;
1959
1960        OverlayElement *optionsPanel = OverlayManager::getSingleton().
1961                getOverlayElement("Example/Visibility/VisibilityPanel");
1962
1963        optionsPanel->setHeight(top + border_height);
1964
1965        top = border_height;
1966        //ext = "Example/Visibility/";
1967        initOverlayElement(&mFrustumCulledNodesInfo, ext, "FrustumCulledNodes", top, ": 0"); top += vert_space;
1968        initOverlayElement(&mQueryCulledNodesInfo, ext, "QueryCulledNodes", top, ": 0"); top += vert_space;
1969        initOverlayElement(&mTraversedNodesInfo, ext, "TraversedNodes", top, ": 0"); top += vert_space;
1970        initOverlayElement(&mHierarchyNodesInfo, ext, "HierarchyNodes", top, ": 0"); top += vert_space;
1971        initOverlayElement(&mRenderedNodesInfo, ext, "RenderedNodes", top, ": 0"); top += vert_space;
1972        initOverlayElement(&mObjectsCountInfo, ext, "ObjectsCount", top, ": 0"); top += vert_space;
1973        initOverlayElement(&mQueriesIssuedInfo, ext, "QueriesIssued", top, ": 0"); top += vert_space;
1974
1975        OverlayElement *visPanel = OverlayManager::getSingleton().
1976                getOverlayElement("Example/Visibility/VisibilityStatsPanel");
1977
1978        visPanel->setHeight(top + border_height);
1979}
1980//-----------------------------------------------------------------------
1981void TerrainFrameListener::initQueryOverlay()
1982{
1983        const int border_height = 10;
1984        const int vert_space = 15;
1985
1986        //-- visibility culling stats overlay
1987        int top = border_height + 25;
1988
1989        const String ext = "Example/Visibility/Query/";
1990           
1991        initOverlayElement(&mQueryTypeInfo , ext, "QueryType", top,     ": 0"); top += vert_space;
1992       
1993        initOverlayElement(&mQueryVisibleNodesInfo , ext, "VisibleNodes", top,  ": 0"); top += vert_space;
1994        initOverlayElement(&mQueryVisibleGeometryInfo , ext, "VisibleGeometry", top,    ": 0"); top += vert_space;
1995        initOverlayElement(&mQueryVisiblePatchInfo , ext, "VisiblePatches", top,        ": 0"); top += vert_space;
1996       
1997        initOverlayElement(&mQueryNodeVisibilityInfo , ext, "NodeVisibility", top,      ": 0"); top += vert_space;
1998        initOverlayElement(&mQueryGeometryVisibilityInfo , ext, "GeometryVisibility", top,      ": 0"); top += vert_space;
1999        initOverlayElement(&mQueryPatchVisibilityInfo , ext, "PatchVisibility", top,    ": 0"); top += vert_space;
2000
2001        OverlayElement *queryPanel =
2002                OverlayManager::getSingleton().getOverlayElement("Example/Visibility/Query/QueryPanel");
2003
2004        queryPanel->setHeight(top + border_height);
2005}
2006//-----------------------------------------------------------------------
2007void TerrainFrameListener::setAlgorithm(const int algorithm)
2008{
2009        mCurrentAlgorithm = algorithm;
2010        applyCurrentAlgorithm();
2011}
Note: See TracBrowser for help on using the repository browser.