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

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