source: GTP/trunk/App/Demos/Vis/KdTreeDemo/OGRE/src/TestKdTreeAppListener.cpp @ 1300

Revision 1300, 52.9 KB checked in by szydlowski, 18 years ago (diff)

view cells load/use implemented

Line 
1#include <fstream>
2#include <cstdlib>
3
4#include <OgrePanelOverlayElement.h>
5#include "TestKdTreeAppListener.h"
6#include "TestKdTree.h"
7#include <windows.h>
8
9const Real       KdTreeAppListener::DEMO_WAIT = 5.0;
10const String KdTreeAppListener::NA = ": N/A";
11const String KdTreeAppListener::RENDERMETHOD[] = { "INT", "VFC", "SWC", "CHC" };
12const String KdTreeAppListener::RENDERMETHODCAPTION[] =
13{
14        "Internal Frustum Culling",
15        "View Frustum Culling",
16        "Stop and Wait Culling",
17        "Coherent Hierarchical Culling"
18};
19const String KdTreeAppListener::BUILDMETHOD[] = { "RE", "PQ" };
20const String KdTreeAppListener::BUILDMETHODCAPTION[] = { "Recursive", "Priority Queue" };
21const String KdTreeAppListener::SCENEMANAGER[] = { "KDT", "KTE", "OCM", "OCT", "TER", "GEN" };
22const String KdTreeAppListener::SCENEMANAGERNAME[] =
23{
24        "KdTreeSceneManager",
25        "KdTreeTerrainSceneManager",
26        "OcclusionCullingSceneManager",
27        "OctreeSceneManager",
28        "TerrainSceneManager",
29        "DefaultSceneManager"
30};
31
32void KdTreeAppListener::updateStats(void)
33{
34        static unsigned int opt = 0;
35        static char str[100];
36
37        static String currFps = "Current FPS: ";
38        static String avgFps = "Average FPS: ";
39        static String bestFps = "Best FPS: ";
40        static String worstFps = "Worst FPS: ";
41        static String tris = "Triangle Count: ";
42
43        // update stats when necessary
44        try {
45                OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
46                OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
47                OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
48                OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");
49
50                const RenderTarget::FrameStats& stats = mWindow->getStatistics();
51
52                guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
53                guiCurr->setCaption(currFps + StringConverter::toString((int)stats.lastFPS));
54                guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
55                        +" "+StringConverter::toString(stats.bestFrameTime)+" ms");
56                guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
57                        +" "+StringConverter::toString(stats.worstFrameTime)+" ms");
58
59                OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
60                guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
61
62                OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");
63                guiDbg->setCaption(mWindow->getDebugText());
64
65
66                //-- culling stats
67                mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt);
68                mFrustumCulledNodesInfo->setCaption(str);
69
70                mSceneMgr->getOption("NumQueryCulledNodes", &opt); sprintf(str,": %d", opt);
71                mQueryCulledNodesInfo->setCaption(str);
72
73                mSceneMgr->getOption("NumHierarchyNodes", &opt); sprintf(str,": %d", opt);
74                mHierarchyNodesInfo->setCaption(str);
75
76                mSceneMgr->getOption("NumRenderedNodes", &opt); sprintf(str,": %d", opt);
77                mRenderedNodesInfo->setCaption(str);
78
79                // take old value into account in order to create no sudden changes
80                mSceneMgr->getOption("NumQueriesIssued", &opt);
81                mDelayedQueriesIssued = mDelayedQueriesIssued * 0.8 + (float)opt * 0.2f;
82                sprintf(str,": %d", (int)mDelayedQueriesIssued);
83                mQueriesIssuedInfo->setCaption(str);
84
85                mSceneMgr->getOption("NumTraversedNodes", &opt);
86                mDelayedTraversedNodes = mDelayedTraversedNodes * 0.8 + (float)opt * 0.2f;
87                sprintf(str,": %d", (int)mDelayedTraversedNodes);
88                mTraversedNodesInfo->setCaption(str);
89        }
90        catch(...)
91        {
92                // ignore
93        }
94}
95
96// Constructor takes a RenderWindow because it uses that to determine input context
97KdTreeAppListener::KdTreeAppListener(RenderWindow* win, SceneManager* sm, const Options& options,
98                                                                         bool useBufferedInputKeys, bool useBufferedInputMouse):
99// basic
100mWindow(win),
101mSceneMgr(sm),
102mOptions(options),
103mUseBufferedInputKeys(useBufferedInputKeys),
104mUseBufferedInputMouse(useBufferedInputMouse),
105// elements
106mCamNode(0),
107mCamera(0),
108mTopCam(0),
109// toggle
110mStatsOn(true),
111mVizCamera(false),
112mFreeMove(false),
113mTopCamFollow(true),
114mShowTree(SHOWTREE_OFF),
115// view cells
116mViewCellsLoaded(false),
117mUseViewCells(false),
118mUseVisibilityFilter(false),
119//counters
120mSeqNum(0),
121mNumScreenShots(0),
122// rendering/texture options
123mSceneDetailIndex(PM_SOLID),
124mFiltering(TFO_ANISOTROPIC),
125mAniso(8),
126// chc stats
127mDelayedQueriesIssued(0.0f),
128mDelayedTraversedNodes(0.0f),
129// movement
130mTranslateVector(Vector3::ZERO),
131mVizCamTransVect(Vector3::ZERO),
132mRotX(0.0f),
133mRotY(0.0f),
134mMoveScale(0.0f),
135mRotScale(0.0f),
136mDeathAngle(0.0f),
137mRaySceneQuery(0),
138// just to stop toggles flipping too fast
139mTimeUntilNextToggle(0.0f),
140// stuff for walkthrough recording/playback
141mTimeUntilNextLogWrite(options.mDemoInterval),
142mTimeRemaining(0.0f),
143mWaitBeforeDemoStart(0.0f),
144mAppState(AS_NORMAL)
145{
146        mInputTypeSwitchingOn = mUseBufferedInputKeys || mUseBufferedInputMouse;
147
148        if (mInputTypeSwitchingOn)
149        {
150                mEventProcessor = new EventProcessor();
151                mEventProcessor->initialise(win);
152                mEventProcessor->startProcessingEvents();
153                mEventProcessor->addKeyListener(this);
154                mInputDevice = mEventProcessor->getInputReader();
155
156        }
157        else
158        {
159                mInputDevice = PlatformManager::getSingleton().createInputReader();
160                mInputDevice->initialise(win,true, true);
161        }
162
163        MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
164        MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
165
166        mCamera = sm->getCamera("PlayerCam");
167        mTopCam = sm->getCamera("TopCam");
168        mCamNode = sm->getSceneNode("PlayerCamNode");
169
170        mRaySceneQuery = mSceneMgr->createRayQuery(Ray(mCamNode->getPosition(), Vector3::NEGATIVE_UNIT_Y));
171
172        mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");
173        mKdTreeOverlay = OverlayManager::getSingleton().getByName("KdTree/DebugOverlay");
174        mDemoOverlay = 0;
175        mDemoStatus = 0;
176        mDemoTime = 0;
177
178        // loading view cells overlay
179        mLoadingOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/LoadingOverlay");
180        mMyLoadingInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/Loading/MyLoadingInfo");
181        mMyLoadingInfo->setCaption("loading view cells ...");
182
183        mLoadingOverlay->hide();
184
185        initKdTreeOverlay();
186        initStatsOverlay();
187
188        // set view cells
189        if (mOptions.mSceneType == ST_GEOMETRY)
190        {
191                switch(mOptions.mViewCells)
192                {
193                case VCM_ON:
194                        toggleUseViewCells();
195                        break;
196                case VCM_FILTER:
197                        toggleUseViewCells();
198                        toggleUseVisibilityFilter();
199                        break;
200                }
201        }
202
203        if (!mOptions.mDemoInfileName.empty())
204                loadFrames(mOptions.mDemoInfileName, mFrameList);
205
206        if (!mOptions.mDemoInfileName.empty() && mOptions.mDemoMode)
207        {
208                // force X second wait when in demo mode - avoids initial low framerate due to loading delays
209                mWaitBeforeDemoStart = DEMO_WAIT;
210                // set playback icon
211                togglePlayback();
212                // hide all other overlays
213                mStatsOn = false;
214        }
215
216        showDebugOverlay(mStatsOn);
217        setDemoOverlay();
218}
219//-----------------------------------------------------------------------
220KdTreeAppListener::~KdTreeAppListener()
221{
222        if (mInputTypeSwitchingOn)
223        {
224                delete mEventProcessor;
225        }
226        else
227        {
228                PlatformManager::getSingleton().destroyInputReader( mInputDevice );
229        }
230}
231//-----------------------------------------------------------------------
232void KdTreeAppListener::initOverlayElement(OverlayElement **elInfo, String ext,
233        String name, int top, String caption)
234{
235        OverlayElement *el =
236                OverlayManager::getSingleton().getOverlayElement(ext + name);
237
238        (*elInfo) = OverlayManager::getSingleton().getOverlayElement(ext + name + "Info");
239        (*elInfo)->setCaption(caption);
240
241        el->setTop(top);
242        (*elInfo)->setTop(top);
243}
244//-----------------------------------------------------------------------
245void KdTreeAppListener::initStatsOverlay()
246{
247        const int border_height = 10;
248        const int vert_space = 15;
249
250        //-- visibility culling stats overlay
251        int top = border_height;
252
253        String ext = "KdTree/Visibility/";
254
255        initOverlayElement(&mFrustumCulledNodesInfo, ext, "FrustumCulledNodes", top, ": 0"); top += vert_space;
256        initOverlayElement(&mQueryCulledNodesInfo, ext, "QueryCulledNodes", top, ": 0"); top += vert_space;
257        initOverlayElement(&mTraversedNodesInfo, ext, "TraversedNodes", top, ": 0"); top += vert_space;
258        initOverlayElement(&mHierarchyNodesInfo, ext, "HierarchyNodes", top, ": 0"); top += vert_space;
259        initOverlayElement(&mRenderedNodesInfo, ext, "RenderedNodes", top, ": 0"); top += vert_space;
260        initOverlayElement(&mObjectsCountInfo, ext, "ObjectsCount", top, ": 0"); top += vert_space;
261        initOverlayElement(&mQueriesIssuedInfo, ext, "QueriesIssued", top, ": 0"); top += vert_space;
262
263        OverlayElement *visPanel = OverlayManager::getSingleton().
264                getOverlayElement("KdTree/VisibilityStatsPanel");
265
266        visPanel->setHeight(top + border_height);
267}
268//-----------------------------------------------------------------------
269void KdTreeAppListener::initKdTreeOverlay()
270{
271        const int border_height = 10;
272        const int vert_space = 15;
273        int top = border_height;
274
275        String ext = "KdTree/";
276        String sMD, sKT, sKI, sHL, sBM, sRM, sFM, sTC, sEV, sVC, sVF;
277
278        int maxd;
279        if (mSceneMgr->getOption("KdTreeMaxDepth", &maxd))
280                sMD = ": " + StringConverter::toString(maxd);
281        else
282                sMD = NA;
283
284        Real kt;
285        if (mSceneMgr->getOption("KT", &kt))
286                sKT = ": " + StringConverter::toString(kt);
287        else
288                sKT = NA;
289
290        Real ki;
291        if (mSceneMgr->getOption("KI", &ki))
292                sKI = ": " + StringConverter::toString(ki);
293        else
294                sKI = NA;
295
296        int hl;
297        if (mSceneMgr->getOption("HiLiteLevel", &hl))
298                sHL = ": " + StringConverter::toString(hl);
299        else
300                sHL = NA;
301        if (mShowTree == SHOWTREE_OFF)
302                sHL = ": off";
303
304        int bm;
305        if (mSceneMgr->getOption("BuildMethod", &bm))
306                sBM = ": " + BUILDMETHODCAPTION[bm];
307        else
308                sBM = NA;
309
310        int rm;
311        if (mSceneMgr->getOption("RenderMethod", &rm))
312                sRM = ": " + RENDERMETHODCAPTION[rm];
313        else
314                sRM = NA;
315
316        // hack to allow mode switching in OCM
317        if (mOptions.mSceneManager == SM_OCM)
318        {
319                rm = CONV_KDT_TO_OCM_ALG(mOptions.mRenderMethod);
320                sRM = ": " + RENDERMETHODCAPTION[CONV_OCM_TO_KDT_ALG(rm)];
321        }
322
323        bool enh;
324        if (mSceneMgr->getOption("EnhancedVisibility", &enh))
325        {
326                if (enh)
327                        sEV = ": Enhanced";
328                else
329                        sEV = ": Simple";
330        }
331        else
332        {
333                sEV = NA;
334        }
335
336        sFM = NA;
337        if (mFreeMove)
338                sFM = ": Free";
339        else
340                sFM = ": Ground";
341
342        sTC = NA;
343        if (mTopCamFollow)
344                sTC = ": Follow";
345        else
346                sTC = ": Free";
347
348        if (mSceneMgr->getOption("UseViewCells", &mUseViewCells) && mOptions.mSceneType == ST_GEOMETRY)
349        {
350                if (mUseViewCells)
351                        sVC = ": on";
352                else
353                        sVC = ": off";
354        }
355        else
356        {
357                if (mOptions.mSceneType == ST_GEOMETRY && mOptions.myApp->getViewCellsFileName() != "" &&
358                        (mOptions.mSceneManager == SM_KDT ||
359                         mOptions.mSceneManager == SM_KTE ||
360                         mOptions.mSceneManager == SM_OCM))
361                {
362                        sVC = ": off";
363                }
364                else
365                {
366                        sVC = NA;
367                }
368        }
369
370        if (mSceneMgr->getOption("UseVisibilityFilter", &mUseVisibilityFilter) && mOptions.mSceneType == ST_GEOMETRY)
371        {
372                if (mUseVisibilityFilter)
373                        sVF = ": on";
374                else
375                        sVF = ": off";
376        }
377        else
378        {
379                if (mOptions.mSceneType == ST_GEOMETRY && mOptions.myApp->getViewCellsFileName() != "" &&
380                        (mOptions.mSceneManager == SM_KDT ||
381                         mOptions.mSceneManager == SM_KTE ||
382                         mOptions.mSceneManager == SM_OCM))
383                {
384                        sVF = ": off";
385                }
386                else
387                {
388                        sVF = NA;
389                }
390        }
391
392        initOverlayElement(&mRenderMethodInfo, ext, "RenderMethod", top, sRM); top += vert_space;
393        initOverlayElement(&mEnhancedVisInfo, ext, "EnhancedVis", top, sEV); top += vert_space;
394        initOverlayElement(&mBuildMethodInfo, ext, "BuildMethod", top, sBM); top += vert_space;
395        initOverlayElement(&mKdTreeMaxDepthInfo, ext, "KdTreeMaxDepth", top, sMD); top += vert_space;
396        initOverlayElement(&mHighlightLevelInfo, ext, "HighlightLevel", top, sHL); top += vert_space;
397        initOverlayElement(&mKTInfo, ext, "KT", top, sKT); top += vert_space;
398        initOverlayElement(&mKIInfo, ext, "KI", top, sKI); top += vert_space;
399        initOverlayElement(&mMovementInfo, ext, "Movement", top, sFM); top += vert_space;
400        initOverlayElement(&mTopCamInfo, ext, "TopCam", top, sTC); top += vert_space;
401        initOverlayElement(&mViewCellsInfo, ext, "ViewCells", top, sVC); top += vert_space;
402        initOverlayElement(&mViewFilterInfo, ext, "ViewFilter", top, sVF); top += vert_space;
403
404        OverlayElement *visPanel = OverlayManager::getSingleton().
405                getOverlayElement("KdTree/OptionsPanel");
406
407        visPanel->setHeight(top + border_height);
408}
409
410void KdTreeAppListener::showDebugOverlay(bool show)
411{
412        if (mDebugOverlay && mKdTreeOverlay)
413        {
414                if (show)
415                {
416                        mDebugOverlay->show();
417                        mKdTreeOverlay->show();
418                }
419                else
420                {
421                        mDebugOverlay->hide();
422                        mKdTreeOverlay->hide();
423                }
424        }
425}
426
427void KdTreeAppListener::toggleUseViewCells()
428{
429        // viewcells apply only for scenes loaded from geometry
430        if (mOptions.mSceneType != ST_GEOMETRY)
431                return;
432
433        mUseViewCells = !mUseViewCells;
434
435
436        // load on demand
437        if (mUseViewCells && !mViewCellsLoaded)
438        {
439                mLoadingOverlay->show();
440
441                // call once to load view cell loading overlay
442                mWindow->update();
443                mViewCellsLoaded = mSceneMgr->setOption("LoadViewCells", mOptions.myApp->getViewCellsFileName().c_str());
444
445                if (!mViewCellsLoaded)
446                {
447                        LogManager::getSingleton().logMessage("#@#@ Error: loading view cells from " +
448                                mOptions.myApp->getViewCellsFileName() + " failed.");
449                }
450
451                mLoadingOverlay->hide();
452        }
453
454        if (mSceneMgr->setOption("UseViewCells", &mUseViewCells))
455        {
456                if (mUseViewCells)
457                        mViewCellsInfo->setCaption(": on");
458                else
459                        mViewCellsInfo->setCaption(": off");
460        }
461        else
462        {
463                mViewCellsInfo->setCaption(NA);
464        }
465}
466
467void KdTreeAppListener::toggleUseVisibilityFilter()
468{
469        mUseVisibilityFilter = !mUseVisibilityFilter;
470        if (mSceneMgr->setOption("UseVisibilityFilter", &mUseVisibilityFilter))
471        {
472                if (mUseVisibilityFilter)
473                        mViewFilterInfo->setCaption(": on");
474                else
475                        mViewFilterInfo->setCaption(": off");
476        }
477        else
478        {
479                mViewFilterInfo->setCaption(NA);
480        }
481}
482
483void KdTreeAppListener::toggleVizCamera()
484{
485        static int nodeVizMode = 0;
486
487        nodeVizMode = (nodeVizMode + 1) % NODEVIZ_MODES_NUM;
488
489        if (nodeVizMode != 0)
490        {
491                if (!mVizCamera)
492                {
493                        Viewport* tvp = mWindow->addViewport(mTopCam,
494                                VIZ_VIEWPORT_Z_ORDER, 0.66, 0.66, 0.34, 0.34);
495                        tvp->setBackgroundColour(ColourValue(1.0, 0.0, 0.0));
496                        tvp->setOverlaysEnabled(false);
497
498                        mTopCam->setAspectRatio(
499                                Real(tvp->getActualWidth())/Real(tvp->getActualHeight()));
500                        mVizCamera = true;
501                        mSceneMgr->setOption("VisualizeCulledNodes", &mVizCamera);
502                }
503
504                bool renderNodesForViz = (nodeVizMode == NODEVIZ_RENDER_NODES) ||
505                        (nodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
506                bool renderNodesContentForViz = (nodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT);
507
508                mSceneMgr->setOption("RenderNodesForViz", &renderNodesForViz);
509                mSceneMgr->setOption("RenderNodesContentForViz", &renderNodesContentForViz);
510        }
511        else
512        {
513                mWindow->removeViewport(VIZ_VIEWPORT_Z_ORDER);
514                mVizCamera = false;
515                mSceneMgr->setOption("VisualizeCulledNodes", &mVizCamera);
516        }
517}
518
519void KdTreeAppListener::toggleShowBoxes()
520{
521        mShowTree = (mShowTree + 1) % SHOWTREE_MODES_NUM;
522        bool show = false, all = false;
523
524        switch (mShowTree)
525        {
526        case SHOWTREE_OFF:
527                break;
528        case SHOWTREE_HILITE:
529                show = true;
530                break;
531        case SHOWTREE_ALL:
532                show = all = true;
533                break;
534        }
535
536        // set display
537
538        if (mSceneMgr->getTypeName() == "OctreeSceneManager")
539                mSceneMgr->setOption("ShowOctree", &show);
540        else if (
541                mSceneMgr->getTypeName() == "KdTreeSceneManager" ||
542                mSceneMgr->getTypeName() == "KdTreeTerrainSceneManager")
543                mSceneMgr->setOption("ShowKdTree", &show);
544
545        // set showall
546        mSceneMgr->setOption("ShowAllBoxes", &all);
547
548        if (!show)
549                mHighlightLevelInfo->setCaption(": off");
550        else
551        {
552                int hl;
553                if (mSceneMgr->getOption("HiLiteLevel", &hl))
554                        mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl));
555                else
556                        mHighlightLevelInfo->setCaption(NA);
557        }
558}
559
560void KdTreeAppListener::toggleEnhancedVisibility()
561{
562        bool mode;
563        if (mSceneMgr->getOption("EnhancedVisibility", &mode))
564        {
565                mode = !mode;
566                if (mSceneMgr->setOption("EnhancedVisibility", &mode))
567                {
568                        if (mode)
569                                mEnhancedVisInfo->setCaption(": Enhanced");
570                        else
571                                mEnhancedVisInfo->setCaption(": Simple");
572
573                        mOptions.mEnhancedVisibility = mode;
574                }
575        }
576        else
577        {
578                mEnhancedVisInfo->setCaption(NA);
579        }
580}
581
582void KdTreeAppListener::toggleBuildMethod()
583{
584        int bm;
585
586        if (mSceneMgr->getOption("BuildMethod", &bm))
587        {
588                bm = (bm + 1) % KdTree::KDBM_SIZE;
589                if (mSceneMgr->setOption("BuildMethod", &bm))
590                {
591                        mBuildMethodInfo->setCaption(": " + BUILDMETHODCAPTION[bm]);
592                        mOptions.mBuildMethod = bm;
593                }
594        }
595        else
596        {
597                mBuildMethodInfo->setCaption(NA);
598        }
599}
600
601void KdTreeAppListener::toggleRenderMethod()
602{
603        int rm;
604
605        if (mSceneMgr->getOption("RenderMethod", &rm))
606        {
607                rm = (rm + 1) % KdTree::KDRM_SIZE;
608                if (mSceneMgr->setOption("RenderMethod", &rm))
609                {
610                        mRenderMethodInfo->setCaption(": " + RENDERMETHODCAPTION[rm]);
611                        mOptions.mRenderMethod = rm;
612                }
613        }
614        else
615        {
616                mRenderMethodInfo->setCaption(NA);
617        }
618
619        // hack to allow mode switching in OCM, cannot extract setting from sm
620        if (mOptions.mSceneManager == SM_OCM)
621        {
622                static int alg = CONV_KDT_TO_OCM_ALG(mOptions.mRenderMethod);
623                alg = (alg + 1) % 3;
624                if (mSceneMgr->setOption("Algorithm", &alg))
625                        mRenderMethodInfo->setCaption(": " + RENDERMETHODCAPTION[CONV_OCM_TO_KDT_ALG(alg)]);
626        }
627}
628
629bool KdTreeAppListener::processUnbufferedKeyInput(const FrameEvent& evt)
630{
631        // ignore all keystrokes except escape when in demo mode
632        if (mOptions.mDemoMode)
633        {
634                if (mInputDevice->isKeyDown(KC_ESCAPE))
635                        return false;
636                else
637                        return true;
638        }
639
640        if (mInputDevice->isKeyDown(KC_F1) && mTimeUntilNextToggle <= 0)
641        {
642                // TODO show help overlay
643        }
644
645        // show/hide vis viewport
646        if (mInputDevice->isKeyDown(KC_F2) && mTimeUntilNextToggle <= 0)
647        {
648                toggleVizCamera();
649                mTimeUntilNextToggle = 0.5;
650        }
651
652        // show/hide kdtree boxes
653        if (mInputDevice->isKeyDown(KC_F3) && mTimeUntilNextToggle <= 0)
654        {
655                toggleShowBoxes();
656                mTimeUntilNextToggle = 0.5;
657        }
658
659        if (mInputDevice->isKeyDown(KC_F4) && mTimeUntilNextToggle <= 0)
660        {
661                bool toggleShow;
662                mSceneMgr->getOption("ShowNodes", &toggleShow);
663                toggleShow = !toggleShow;
664                mSceneMgr->setOption("ShowNodes", &toggleShow);
665                mTimeUntilNextToggle = 0.5;
666        }
667
668        // demo recording stuff
669        if (mInputDevice->isKeyDown(KC_F5) && mTimeUntilNextToggle <= 0)
670        {
671                toggleRecord();
672                mTimeUntilNextToggle = 0.5;
673        }
674
675        if (mInputDevice->isKeyDown(KC_F6) && mTimeUntilNextToggle <= 0)
676        {
677                if (!mOptions.mDemoOutfileName.empty() && !mFrameList.empty())
678                        saveFrames(mOptions.mDemoOutfileName, mFrameList);
679                mTimeUntilNextToggle = 0.5;
680        }
681
682        if (mInputDevice->isKeyDown(KC_F7) && mTimeUntilNextToggle <= 0)
683        {
684                SceneNode *entnode = mSceneMgr->getSceneNode("AnchorNode");
685                if (!mOptions.myApp->saveSceneASCII(mOptions.mSceneOutfileName, entnode))
686                        LogManager::getSingleton().logMessage(
687                        "##Error##: Failed to save scene to " + mOptions.mSceneOutfileName);
688                mTimeUntilNextToggle = 0.5;
689        }
690
691        if (mInputDevice->isKeyDown(KC_F8) && mTimeUntilNextToggle <= 0)
692        {
693                // fill scene only once (for now), stop if anchor node exists
694                try
695                {
696                        SceneNode *entnode = mSceneMgr->getSceneNode("AnchorNode");
697                }
698                catch (Exception)
699                {
700                        // read interesting params from config file
701                        ConfigFile terrainconf;
702                        std::stringstream s;
703                        Real x,y,z;
704                       
705                        terrainconf.load("terrain.cfg");
706
707                        s << terrainconf.getSetting("PageWorldX");
708                        s >> x;
709                        s.clear();
710
711                        s << terrainconf.getSetting("MaxHeight");
712                        s >> y;
713                        s.clear();
714
715                        s << terrainconf.getSetting("PageWorldZ");
716                        s >> z;
717                        s.clear();
718
719                        mOptions.myApp->createTerrainScene(x, y * 0.3, z);
720
721                        // rebuild tree
722                        mSceneMgr->setOption("RebuildKdTree", 0);
723                }
724
725                mTimeUntilNextToggle = 0.5;
726        }
727
728
729        if (mInputDevice->isKeyDown(KC_F9) && mTimeUntilNextToggle <= 0)
730        {
731                togglePlayback();
732                mTimeUntilNextToggle = 0.5;
733        }
734
735        if (mInputDevice->isKeyDown(KC_0) && mTimeUntilNextToggle <= 0)
736        {
737                toggleBuildMethod();
738                mTimeUntilNextToggle = 0.5;
739        }
740
741        if (mInputDevice->isKeyDown(KC_SPACE) && mTimeUntilNextToggle <= 0)
742        {
743                toggleRenderMethod();
744                mTimeUntilNextToggle = 0.5;
745        }
746
747        if (mInputDevice->isKeyDown(KC_C) && mTimeUntilNextToggle <= 0)
748        {
749                toggleUseViewCells();
750                mTimeUntilNextToggle = 0.5;
751        }
752
753        if (mInputDevice->isKeyDown(KC_X) && mTimeUntilNextToggle <= 0)
754        {
755                toggleUseVisibilityFilter();
756                mTimeUntilNextToggle = 0.5;
757        }
758
759        if (mInputDevice->isKeyDown(KC_B) && mTimeUntilNextToggle <= 0)
760        {
761                mSceneMgr->showBoundingBoxes( ! mSceneMgr->getShowBoundingBoxes() );
762                mTimeUntilNextToggle = 0.5;
763        }
764
765        const static int vizCamSpeedup = 12;
766        // moving the cull camera
767        if (mInputDevice->isKeyDown(KC_NUMPAD2))
768        {
769                mVizCamTransVect.y = -mMoveScale * vizCamSpeedup;
770        }
771        if (mInputDevice->isKeyDown(KC_NUMPAD8))
772        {
773                mVizCamTransVect.y = mMoveScale * vizCamSpeedup;
774        }
775        if (mInputDevice->isKeyDown(KC_NUMPAD4))
776        {
777                mVizCamTransVect.x = -mMoveScale * vizCamSpeedup;
778        }
779        if (mInputDevice->isKeyDown(KC_NUMPAD6))
780        {
781                mVizCamTransVect.x = mMoveScale * vizCamSpeedup;
782        }
783        if (mInputDevice->isKeyDown(KC_SUBTRACT))
784        {
785                mVizCamTransVect.z = mMoveScale * vizCamSpeedup;
786        }
787        if (mInputDevice->isKeyDown(KC_ADD))
788        {
789                mVizCamTransVect.z = -mMoveScale * vizCamSpeedup;
790        }
791
792        if ((mInputDevice->isKeyDown(KC_1) || mInputDevice->isKeyDown(KC_2)) && mTimeUntilNextToggle <= 0)
793        {
794                int currdepth;
795                if (mSceneMgr->getOption("KdTreeMaxDepth", &currdepth))
796                {
797                        if (mInputDevice->isKeyDown(KC_1))
798                                currdepth--;
799                        else if (mInputDevice->isKeyDown(KC_2))
800                                currdepth++;
801
802                        if (mSceneMgr->setOption("KdTreeMaxDepth", &currdepth))
803                        {
804                                mKdTreeMaxDepthInfo->setCaption(": " + StringConverter::toString(currdepth));
805                                int hl;
806                                if (mSceneMgr->getOption("HiLiteLevel", &hl))
807                                        mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl));
808                                else
809                                        mHighlightLevelInfo->setCaption(NA);
810                        }
811                }
812                else
813                {
814                        mKdTreeMaxDepthInfo->setCaption(NA);
815                        mHighlightLevelInfo->setCaption(NA);
816                }
817
818                if (mShowTree == SHOWTREE_OFF)
819                        mHighlightLevelInfo->setCaption(": off");
820
821                mTimeUntilNextToggle = 0.2;
822        }
823
824        if ((mInputDevice->isKeyDown(KC_3) || mInputDevice->isKeyDown(KC_4)) && mTimeUntilNextToggle <= 0)
825        {
826                int hl;
827                if (mSceneMgr->getOption("HiLiteLevel", &hl))
828                {
829                        if (mInputDevice->isKeyDown(KC_3))
830                                hl--;
831                        else if (mInputDevice->isKeyDown(KC_4))
832                                hl++;
833
834                        if (mSceneMgr->setOption("HiLiteLevel", &hl))
835                                mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl));
836                }
837                else
838                {
839                        mHighlightLevelInfo->setCaption(NA);
840                }
841
842                if (mShowTree == SHOWTREE_OFF)
843                        mHighlightLevelInfo->setCaption(": off");
844
845                mTimeUntilNextToggle = 0.2;
846        }
847
848
849        if ((mInputDevice->isKeyDown(KC_5) ||mInputDevice->isKeyDown(KC_6)) && mTimeUntilNextToggle <= 0)
850        {
851                Real kt;
852                if (mSceneMgr->getOption("KT", &kt))
853                {
854                        if (mInputDevice->isKeyDown(KC_5))
855                                kt -= 0.1;
856                        else if (mInputDevice->isKeyDown(KC_6))
857                                kt += 0.1;
858
859                        if (kt < 0.1)
860                                kt = 0.1;
861
862                        if (mSceneMgr->setOption("KT", &kt))
863                                mKTInfo->setCaption(": " + StringConverter::toString(kt));
864                }
865                else
866                {
867                        mKTInfo->setCaption(NA);
868                }
869
870                mTimeUntilNextToggle = 0.2;
871        }
872
873        if ((mInputDevice->isKeyDown(KC_7) || mInputDevice->isKeyDown(KC_8)) && mTimeUntilNextToggle <= 0)
874        {
875                Real ki;
876                if (mSceneMgr->getOption("KI", &ki))
877                {
878                        if (mInputDevice->isKeyDown(KC_7))
879                                ki -= 0.1;
880                        else if (mInputDevice->isKeyDown(KC_8))
881                                ki += 0.1;
882
883                        if (ki < 0.1)
884                                ki = 0.1;
885
886                        if (mSceneMgr->setOption("KI", &ki))
887                                mKIInfo->setCaption(": " + StringConverter::toString(ki));
888                }
889                else
890                {
891                        mKIInfo->setCaption(NA);
892                }
893
894                mTimeUntilNextToggle = 0.2;
895        }
896
897        if (mInputDevice->isKeyDown(KC_U) && mTimeUntilNextToggle <= 0)
898        {
899                mFreeMove = !mFreeMove;
900                String move = ": N/A";
901                if (mFreeMove)
902                        move = ": Free";
903                else
904                        move = ": Ground";
905
906                mMovementInfo->setCaption(move);
907
908                mTimeUntilNextToggle = 0.5;
909        }
910
911        if (mInputDevice->isKeyDown(KC_I) && mTimeUntilNextToggle <= 0)
912        {
913                mTopCamFollow = !mTopCamFollow;
914                String move = ": N/A";
915                if (mTopCamFollow)
916                        move = ": Follow";
917                else
918                        move = ": Free";
919
920                mTopCamInfo->setCaption(move);
921
922                mTimeUntilNextToggle = 0.5;
923        }
924
925        if (mInputDevice->isKeyDown(KC_BACK) && mTimeUntilNextToggle <= 0)
926        {
927                mSceneMgr->setOption("RebuildKdTree", 0);
928                mTimeUntilNextToggle = 1;
929        }
930
931        //if (mInputDevice->isKeyDown(KC_N) && mTimeUntilNextToggle <= 0)
932        //{
933        //      //Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "robot.mesh");
934        //      Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "razor.mesh");
935        //      //Vector3 position(Math::RangeRandom(100, 1125), -0, Math::RangeRandom(-1125, 1125));
936        //      Vector3 position(Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000));
937        //      //Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), Vector3::UNIT_Y);
938        //      Vector3 axis(Math::RangeRandom(-1,1),Math::RangeRandom(-1,1),Math::RangeRandom(-1,1));
939        //      axis.normalise();
940        //      Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), axis);
941        //      Vector3 scale(Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5));
942        //      SceneNode * anchor = mSceneMgr->getSceneNode("AnchorNode");
943        //      SceneNode *sn = anchor->createChildSceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum), position, orientation);
944        //      sn->attachObject(ent);
945        //      sn->setScale(scale);
946        //      mTimeUntilNextToggle = 0.5;
947        //      mSeqNum++;
948        //}
949
950        //if (mInputDevice->isKeyDown(KC_J) && mTimeUntilNextToggle <= 0)
951        //{
952        //      if (mSeqNum > 0)
953        //      {
954        //              mSeqNum--;
955        //              mSceneMgr->destroySceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum));
956        //              mSceneMgr->destroyEntity("randominsert" + StringConverter::toString(mSeqNum));
957        //              mTimeUntilNextToggle = 0.5;
958        //      }
959        //}
960
961        //if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0)
962        //{
963        //      LogManager::getSingleton().logMessage("############## Camera Position:");
964        //      LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getPosition()));
965        //      LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getOrientation()));
966        //      LogManager::getSingleton().logMessage("############## Cull Camera Position:");
967        //      LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition()));
968        //      LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation()));
969        //      mTimeUntilNextToggle = 1.0;
970        //}
971
972        if (mInputDevice->isKeyDown(KC_A))
973        {
974                // Move camera left
975                mTranslateVector.x = -mMoveScale;
976        }
977
978        if (mInputDevice->isKeyDown(KC_D))
979        {
980                // Move camera RIGHT
981                mTranslateVector.x = mMoveScale;
982        }
983
984        /* Move camera forward by keypress. */
985        if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) )
986        {
987                mTranslateVector.z = -mMoveScale;
988        }
989
990        /* Move camera backward by keypress. */
991        if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) )
992        {
993                mTranslateVector.z = mMoveScale;
994        }
995
996        if (mInputDevice->isKeyDown(KC_PGUP))
997        {
998                // Move camera up
999                mTranslateVector.y = mMoveScale;
1000        }
1001
1002        if (mInputDevice->isKeyDown(KC_PGDOWN))
1003        {
1004                // Move camera down
1005                mTranslateVector.y = -mMoveScale;
1006        }
1007
1008        if (mInputDevice->isKeyDown(KC_RIGHT))
1009        {
1010                mCamNode->yaw(-mRotScale, Ogre::Node::TS_WORLD);
1011        }
1012
1013        if (mInputDevice->isKeyDown(KC_LEFT))
1014        {
1015                mCamNode->yaw(mRotScale, Ogre::Node::TS_WORLD);
1016        }
1017
1018        if( mInputDevice->isKeyDown( KC_ESCAPE) )
1019        {           
1020                return false;
1021        }
1022
1023        // see if switching is on, and you want to toggle
1024        if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_M) && mTimeUntilNextToggle <= 0)
1025        {
1026                switchMouseMode();
1027                mTimeUntilNextToggle = 1;
1028        }
1029
1030        if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_K) && mTimeUntilNextToggle <= 0)
1031        {
1032                // must be going from immediate keyboard to buffered keyboard
1033                switchKeyMode();
1034                mTimeUntilNextToggle = 1;
1035        }
1036        if (mInputDevice->isKeyDown(KC_F) && mTimeUntilNextToggle <= 0)
1037        {
1038                mStatsOn = !mStatsOn;
1039                showDebugOverlay(mStatsOn);
1040
1041                mTimeUntilNextToggle = 1;
1042        }
1043        if (mInputDevice->isKeyDown(KC_T) && mTimeUntilNextToggle <= 0)
1044        {
1045                switch(mFiltering)
1046                {
1047                case TFO_BILINEAR:
1048                        mFiltering = TFO_TRILINEAR;
1049                        mAniso = 1;
1050                        break;
1051                case TFO_TRILINEAR:
1052                        mFiltering = TFO_ANISOTROPIC;
1053                        mAniso = 8;
1054                        break;
1055                case TFO_ANISOTROPIC:
1056                        mFiltering = TFO_BILINEAR;
1057                        mAniso = 1;
1058                        break;
1059                default:
1060                        break;
1061                }
1062                MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);
1063                MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);
1064
1065
1066                showDebugOverlay(mStatsOn);
1067
1068                mTimeUntilNextToggle = 1;
1069        }
1070
1071        if (mInputDevice->isKeyDown(KC_SYSRQ) && mTimeUntilNextToggle <= 0)
1072        {
1073                char tmp[20];
1074                sprintf(tmp, "screenshot_%d.png", ++mNumScreenShots);
1075                mWindow->writeContentsToFile(tmp);
1076                mTimeUntilNextToggle = 0.5;
1077                mWindow->setDebugText(String("Wrote ") + tmp);
1078        }
1079
1080        if (mInputDevice->isKeyDown(KC_R) && mTimeUntilNextToggle <=0)
1081        {
1082                mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;
1083                switch(mSceneDetailIndex) {
1084                        case 0 : mCamera->setPolygonMode(PM_SOLID) ; break ;
1085                        case 1 : mCamera->setPolygonMode(PM_WIREFRAME) ; break ;
1086                        case 2 : mCamera->setPolygonMode(PM_POINTS) ; break ;
1087                }
1088                mTimeUntilNextToggle = 0.5;
1089        }
1090
1091        static bool displayCameraDetails = false;
1092        if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0)
1093        {
1094                displayCameraDetails = !displayCameraDetails;
1095                mTimeUntilNextToggle = 0.5;
1096                if (!displayCameraDetails)
1097                {
1098                        mWindow->setDebugText("");
1099                }
1100                else
1101                {
1102                        LogManager::getSingleton().logMessage("############## Camera Position:");
1103                        LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getDerivedPosition()));
1104                        LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getDerivedOrientation()));
1105                        LogManager::getSingleton().logMessage("############## Cull Camera Position:");
1106                        LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition()));
1107                        LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation()));
1108                }
1109        }
1110        if (displayCameraDetails)
1111        {
1112                // Print camera details
1113                mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) + " " +
1114                        "O: " + StringConverter::toString(mCamera->getDerivedOrientation()));
1115        }
1116
1117        // Return true to continue rendering
1118        return true;
1119}
1120
1121bool KdTreeAppListener::processUnbufferedMouseInput(const FrameEvent& evt)
1122{
1123        /* Rotation factors, may not be used if the second mouse button is pressed. */
1124
1125        /* If the second mouse button is pressed, then the mouse movement results in
1126        sliding the camera, otherwise we rotate. */
1127        if( mInputDevice->getMouseButton( 1 ) )
1128        {
1129                mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13;
1130                mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13;
1131        }
1132        else
1133        {
1134                mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13);
1135                mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13);
1136        }
1137
1138
1139        return true;
1140}
1141
1142void KdTreeAppListener::moveCamera()
1143{
1144
1145        // Make all the changes to the camera
1146        // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW (e.g. airplane)
1147        mCamNode->yaw(mRotX, Ogre::Node::TS_WORLD);
1148        mCamNode->pitch(mRotY);
1149        //mCamNode->moveRelative(mTranslateVector);
1150        mCamNode->translate(mCamNode->getLocalAxes(), mTranslateVector);
1151        mTopCam->moveRelative(mVizCamTransVect);
1152        if (mTopCamFollow)
1153        {
1154                Vector3 toppos = mTopCam->getPosition();
1155                Vector3 campos = mCamNode->getPosition();
1156                mTopCam->setPosition(Vector3::ZERO);
1157                mTopCam->setOrientation(Quaternion::IDENTITY);
1158                mTopCam->setPosition(campos.x, toppos.y, campos.z);
1159                mTopCam->pitch(Radian(-Math::HALF_PI));
1160        }
1161
1162        if (!mFreeMove)
1163        {
1164                if (mOptions.mSceneType == ST_TERRAIN)
1165                {
1166                        static Vector3 pos;
1167                        static Ray updateRay;
1168                        pos = mCamNode->getPosition();
1169                        updateRay.setOrigin(pos);
1170                        updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y);
1171                        mRaySceneQuery->setRay(updateRay);
1172                        RaySceneQueryResult& qryResult = mRaySceneQuery->execute();
1173                        RaySceneQueryResult::iterator i = qryResult.begin();
1174                        if (i != qryResult.end() && i->worldFragment)
1175                        {
1176                                SceneQuery::WorldFragment* wf = i->worldFragment;
1177                                mCamNode->setPosition(pos.x, wf->singleIntersection.y + 10, pos.z);
1178                        }
1179                }
1180                else
1181                {
1182                        static Vector3 pos;
1183                        static Ray updateRay;
1184                        pos = mCamNode->getPosition();
1185                        updateRay.setOrigin(pos);
1186                        updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y);
1187                        mRaySceneQuery->setRay(updateRay);
1188                        RaySceneQueryResult& qryResult = mRaySceneQuery->execute();
1189                        RaySceneQueryResult::iterator i = qryResult.begin();
1190                        while (i != qryResult.end() && i->movable)
1191                        {
1192                                if (i->movable->getName() != "PlayerCam")
1193                                {
1194                                        MovableObject *mov = i->movable;
1195                                        mCamNode->setPosition(pos.x, mov->getWorldBoundingBox().getCenter().y + 2, pos.z);
1196                                        break;
1197                                }
1198                                i++;
1199                        }
1200                }
1201        }
1202}
1203
1204// Override frameStarted event to process that (don't care about frameEnded)
1205bool KdTreeAppListener::frameStarted(const FrameEvent& evt)
1206{
1207        if(mWindow->isClosed())
1208                return false;
1209
1210        if (!mInputTypeSwitchingOn)
1211        {
1212                mInputDevice->capture();
1213        }
1214
1215
1216        if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
1217        {
1218                // one of the input modes is immediate, so setup what is needed for immediate mouse/key movement
1219                if (mTimeUntilNextToggle >= 0)
1220                        mTimeUntilNextToggle -= evt.timeSinceLastFrame;
1221
1222                // If this is the first frame, pick a speed
1223                if (evt.timeSinceLastFrame == 0)
1224                {
1225                        mMoveScale = 1;
1226                        mRotScale = 0.1;
1227                }
1228                // Otherwise scale movement units by time passed since last frame
1229                else
1230                {
1231                        // Move about 100 units per second,
1232                        mMoveScale = mOptions.mMoveSpeed * evt.timeSinceLastFrame;
1233                        // Take about 10 seconds for full rotation
1234                        mRotScale = mOptions.mRotateSpeed * evt.timeSinceLastFrame;
1235                }
1236                mRotX = 0;
1237                mRotY = 0;
1238                mTranslateVector = Vector3::ZERO;
1239                mVizCamTransVect = Vector3::ZERO;
1240        }
1241
1242        if (mUseBufferedInputKeys)
1243        {
1244                // no need to do any processing here, it is handled by event processor and
1245                // you get the results as KeyEvents
1246        }
1247        else
1248        {
1249                if (processUnbufferedKeyInput(evt) == false)
1250                {
1251                        return false;
1252                }
1253        }
1254        if (mUseBufferedInputMouse)
1255        {
1256                // no need to do any processing here, it is handled by event processor and
1257                // you get the results as MouseEvents
1258        }
1259        else
1260        {
1261                if (processUnbufferedMouseInput(evt) == false)
1262                {
1263                        return false;
1264                }
1265        }
1266       
1267        // do nothing until delay passes to stabilize frame rate
1268        mWaitBeforeDemoStart -= evt.timeSinceLastFrame;
1269        if (mWaitBeforeDemoStart > 0.0)
1270        {
1271                // do full turn to preload geometry
1272                static Real dps = (360 / DEMO_WAIT);
1273                mCamNode->yaw(Radian(Degree(dps * evt.timeSinceLastFrame)), Ogre::Node::TS_WORLD);
1274                return true;
1275        }
1276
1277        // demo playback - replace position with stored one
1278        if (mAppState == AS_PLAYBACK)
1279        {
1280                // update time
1281                mTimeRemaining -= evt.timeSinceLastFrame;
1282
1283                // update stats
1284                ++ mDemoStats.mNumFrames;
1285                ++ mDemoStats.mTotalNumFrames;
1286                mDemoStats.mEllapsedTime += evt.timeSinceLastFrame;
1287                mDemoStats.mTotalEllapsedTime += evt.timeSinceLastFrame;
1288
1289                // set time display
1290                int m = (int)mDemoStats.mTotalEllapsedTime / 60;
1291                int s = (int)mDemoStats.mTotalEllapsedTime % 60;
1292
1293                mDemoTime->setCaption(
1294                        StringConverter::toString(m, 2, '0') + ":" +
1295                        StringConverter::toString(s, 2, '0'));
1296
1297                // set FPS display
1298                const RenderTarget::FrameStats& stats = mWindow->getStatistics();
1299                mDemoFPSDisp->setCaption(StringConverter::toString((int)stats.lastFPS));
1300
1301                // store fps when in demo mode
1302                if (mOptions.mDemoMode)
1303                {
1304                        // save FPS
1305                        mTimeUntilNextLogWrite -= evt.timeSinceLastFrame;
1306                        if (mTimeUntilNextLogWrite <= 0.0)
1307                        {
1308                                mTimeUntilNextLogWrite += mOptions.mDemoInterval;
1309                                //const RenderTarget::FrameStats& stats = mWindow->getStatistics();
1310                                //mDemoFPS.push_back(stats.lastFPS);
1311                                mDemoFPS.push_back(mDemoStats.mNumFrames / mDemoStats.mEllapsedTime);
1312                                mDemoStats.mNumFrames = 0;
1313                                mDemoStats.mEllapsedTime = 0.0f;
1314                        }
1315                }
1316
1317                static FrameList::iterator lastFrame;
1318                if (mCurrFrame == mFrameList.begin())
1319                        lastFrame = mCurrFrame;
1320
1321                // advance to next stored frame
1322                while (mTimeRemaining <= 0.0 && mCurrFrame != mFrameList.end())
1323                {
1324                        lastFrame = mCurrFrame;
1325                        ++ mCurrFrame;
1326                        mTimeRemaining += mCurrFrame->mElapsedTime;
1327                }
1328
1329                // when reached last frame, reset and stop playback
1330                if (mCurrFrame == mFrameList.end())
1331                {
1332                        togglePlayback();
1333                        // exit app when in demo mode
1334                        if (mOptions.mDemoMode)
1335                        {
1336                                saveLog();
1337                                if (mOptions.mBurnIn)
1338                                        togglePlayback();
1339                                else
1340                                        return false;
1341                        }
1342                }
1343                // interpolate position & orientation and modify move vectors
1344                else
1345                {
1346                       
1347                        // interpolation factor
1348                        Real factor = 1.0 - mTimeRemaining / mCurrFrame->mElapsedTime;
1349
1350                        // interpolate position and orientation
1351                        Vector3 pos = lastFrame->mPosition +
1352                                factor * (mCurrFrame->mPosition - lastFrame->mPosition);
1353
1354                        Quaternion or = Quaternion::Slerp(factor, lastFrame->mOrientation,
1355                                mCurrFrame->mOrientation);
1356
1357                        // update camera
1358                        mCamNode->setPosition(pos);
1359                        mCamNode->setOrientation(or);
1360
1361                        // update viz camera
1362                        mTopCam->moveRelative(mVizCamTransVect);
1363                        if (mTopCamFollow)
1364                        {
1365                                Vector3 toppos = mTopCam->getPosition();
1366                                Vector3 campos = mCamNode->getPosition();
1367                                mTopCam->setPosition(Vector3::ZERO);
1368                                mTopCam->setOrientation(Quaternion::IDENTITY);
1369                                mTopCam->setPosition(campos.x, toppos.y, campos.z);
1370                                mTopCam->pitch(Radian(-Math::HALF_PI));
1371                        }
1372
1373                }
1374        }
1375        else
1376        {
1377                if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys)
1378                {
1379                        // one of the input modes is immediate, so update the movement vector
1380
1381                        moveCamera();
1382
1383                }
1384        }
1385
1386        //saveFrameInfo(evt.timeSinceLastFrame);
1387        if (mAppState == AS_RECORD)
1388        {
1389                // update stats
1390                ++ mDemoStats.mTotalNumFrames;
1391                mDemoStats.mTotalEllapsedTime += evt.timeSinceLastFrame;
1392
1393                // set time display
1394                int m = (int)mDemoStats.mTotalEllapsedTime / 60;
1395                int s = (int)mDemoStats.mTotalEllapsedTime % 60;
1396
1397                mDemoTime->setCaption(
1398                        StringConverter::toString(m, 2, '0') + ":" +
1399                        StringConverter::toString(s, 2, '0'));
1400
1401                // set FPS display
1402                const RenderTarget::FrameStats& stats = mWindow->getStatistics();
1403                mDemoFPSDisp->setCaption(StringConverter::toString((int)stats.lastFPS));
1404
1405                // store frame
1406                mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), evt.timeSinceLastFrame));
1407        }
1408
1409
1410        //Camera        *followCam = mSceneMgr->getCamera("FollowCam");
1411        //if (followCam->getAutoTrackTarget() != 0)
1412        //{
1413        //      // Move the death thingy & update lookat camera FOV
1414        //      SceneNode *deathPivotNode = mSceneMgr->getSceneNode("deathPivotNode");
1415        //      SceneNode *deathNode = mSceneMgr->getSceneNode("movingNode");
1416        //      SceneNode *pivotNode = mSceneMgr->getSceneNode("pivotNode");
1417
1418        //      Vector3 fcpos = followCam->getPosition();
1419        //      Vector3 oldpos = deathNode->getWorldPosition();
1420
1421        //      Radian deltaAngle = Radian(evt.timeSinceLastFrame / mRotationPeriod * Math::TWO_PI);
1422        //      deathPivotNode->rotate(Vector3::UNIT_Y, deltaAngle);
1423        //      pivotNode->rotate(Vector3::UNIT_Y, deltaAngle * 4);
1424
1425        //      Vector3 pos = deathNode->getWorldPosition();
1426
1427        //      Real olddist = (oldpos - fcpos).length();
1428        //      Real dist = (pos - fcpos).length();
1429
1430        //      Radian oldfov = followCam->getFOVy();
1431        //      Radian fov = Radian(olddist / dist) * oldfov;
1432
1433        //      followCam->setFOVy(fov);
1434        //}
1435
1436        return true;
1437}
1438
1439bool KdTreeAppListener::frameEnded(const FrameEvent& evt)
1440{
1441        if (!mOptions.mDemoMode)
1442                updateStats();
1443
1444        return true;
1445}
1446
1447void KdTreeAppListener::switchMouseMode()
1448{
1449        mUseBufferedInputMouse = !mUseBufferedInputMouse;
1450        mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse);
1451}
1452void KdTreeAppListener::switchKeyMode()
1453{
1454        mUseBufferedInputKeys = !mUseBufferedInputKeys;
1455        mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse);
1456}
1457
1458void KdTreeAppListener::keyClicked(KeyEvent* e)
1459{
1460        if (e->getKeyChar() == 'm')
1461        {
1462                switchMouseMode();
1463        }
1464        else if (e->getKeyChar() == 'k')
1465        {
1466
1467                switchKeyMode();
1468        }
1469}
1470
1471/************************************************************************/
1472/* functions for recording & playback of demos                          */
1473/************************************************************************/
1474
1475//-----------------------------------------------------------------------------
1476void KdTreeAppListener::toggleRecord()
1477{
1478        // start recording
1479        if (mAppState == AS_NORMAL)
1480        {
1481                // change state
1482                mAppState = AS_RECORD;
1483
1484                // clear old recording
1485                mFrameList.clear();
1486
1487                // reset stats
1488                mDemoStats.mNumFrames = 0;
1489                mDemoStats.mTotalNumFrames = 0;
1490                mDemoStats.mEllapsedTime = 0.0f;
1491                mDemoStats.mTotalEllapsedTime = 0.0f;
1492        }
1493        // stop recording
1494        else if (mAppState == AS_RECORD)
1495        {
1496                // change state
1497                mAppState = AS_NORMAL;
1498
1499        }
1500        // update display
1501        setDemoOverlay();
1502}
1503
1504//-----------------------------------------------------------------------------
1505void KdTreeAppListener::togglePlayback()
1506{
1507        static Vector3 pos;
1508        static Quaternion or;
1509
1510        // start playback
1511        if (mAppState == AS_NORMAL && !mFrameList.empty())
1512        {
1513                // change state
1514                mAppState = AS_PLAYBACK;
1515
1516                // save old position
1517                pos = mCamNode->getPosition();
1518                or = mCamNode->getOrientation();
1519
1520                // reset demo
1521                mCurrFrame = mFrameList.begin();
1522                mTimeRemaining = mCurrFrame->mElapsedTime;
1523
1524                // reset stats
1525                mDemoStats.mNumFrames = 0;
1526                mDemoStats.mTotalNumFrames = 0;
1527                mDemoStats.mEllapsedTime = 0.0f;
1528                mDemoStats.mTotalEllapsedTime = 0.0f;
1529                mDemoFPS.clear();
1530        }
1531        // stop playback
1532        else if (mAppState == AS_PLAYBACK)
1533        {
1534                // change state
1535                mAppState = AS_NORMAL;
1536
1537                // restore old position
1538                mCamNode->setPosition(pos);
1539                mCamNode->setOrientation(or);
1540        }
1541
1542        // update display
1543        setDemoOverlay();
1544}
1545
1546
1547//-----------------------------------------------------------------------------
1548void KdTreeAppListener::saveFrames(const String& filename, FrameList& framelist)
1549{
1550        size_t dot = filename.find_last_of(".");
1551        String ext = filename.substr(dot + 1, filename.length());
1552        if (ext == "txt")
1553                saveFramesAscii(filename, framelist);
1554        else if (ext == "bin")
1555                saveFramesBinary(filename, framelist);
1556        else
1557                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames");
1558}
1559
1560//-----------------------------------------------------------------------------
1561void KdTreeAppListener::saveFramesAscii(const String& filename, FrameList& framelist)
1562{
1563        // open file
1564        std::ofstream dest(filename.c_str());
1565        if (dest.is_open())
1566        {
1567                FrameList::iterator it = framelist.begin();
1568                FrameList::iterator end = framelist.end();
1569
1570                // dump values
1571                while (it != end)
1572                {
1573                        dest <<
1574                                StringConverter::toString(it->mPosition) << " " <<
1575                                StringConverter::toString(it->mOrientation) << " " <<
1576                                StringConverter::toString(it->mElapsedTime) << "\n";
1577                        ++ it;
1578                }
1579
1580                dest.close();
1581        }
1582        else
1583        {
1584                LogManager::getSingleton().logMessage("##Error##: Failed to open file for saving demo: " + filename);
1585        }
1586
1587
1588}
1589
1590//-----------------------------------------------------------------------------
1591void KdTreeAppListener::saveFramesBinary(const String& filename, FrameList& framelist)
1592{
1593        std::ofstream dest(filename.c_str(), std::ios_base::out | std::ios_base::binary);
1594
1595        if (dest.is_open())
1596        {
1597                FrameList::iterator it = framelist.begin();
1598                FrameList::iterator end = framelist.end();
1599
1600                int size = sizeof(Real);
1601
1602                // dump values
1603                while (it != end)
1604                {
1605                        dest.write((char *)&it->mPosition.x, size);
1606                        dest.write((char *)&it->mPosition.y, size);
1607                        dest.write((char *)&it->mPosition.z, size);
1608                        dest.write((char *)&it->mOrientation.w, size);
1609                        dest.write((char *)&it->mOrientation.x, size);
1610                        dest.write((char *)&it->mOrientation.y, size);
1611                        dest.write((char *)&it->mOrientation.z, size);
1612                        dest.write((char *)&it->mElapsedTime, size);
1613                        ++ it;
1614                }
1615
1616                dest.close();
1617        }
1618        else
1619        {
1620                LogManager::getSingleton().logMessage("##Error##: Failed to open file for saving demo: " + filename);
1621        }
1622}
1623
1624//-----------------------------------------------------------------------------
1625void KdTreeAppListener::loadFrames(const String& filename, FrameList& framelist)
1626{
1627        size_t dot = filename.find_last_of(".");
1628        String ext = filename.substr(dot + 1, filename.length());
1629        if (ext == "txt")
1630                loadFramesAscii(filename, framelist);
1631        else if (ext == "bin")
1632                loadFramesBinary(filename, framelist);
1633        else
1634                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames");
1635}
1636
1637//-----------------------------------------------------------------------------
1638void KdTreeAppListener::loadFramesAscii(const String& filename, FrameList& framelist)
1639{
1640        // open file
1641        std::ifstream src(filename.c_str());
1642        if (src.is_open())
1643        {
1644                // clear the list
1645                framelist.clear();
1646
1647                Vector3 pos;
1648                Quaternion or;
1649                Real time;
1650
1651                while (!src.eof())
1652                {
1653                        src >> pos.x;   
1654                        src >> pos.y;   
1655                        src >> pos.z;
1656
1657                        src >> or.w;
1658                        src >> or.x;
1659                        src >> or.y;
1660                        src >> or.z;
1661
1662                        src >> time;
1663
1664                        framelist.push_back(FrameInfo(pos, or, time));
1665                }
1666
1667                // HACK pop last frame, was doubled while reading
1668                framelist.pop_back();
1669
1670                src.close();
1671        }
1672        else
1673        {
1674                LogManager::getSingleton().logMessage("##Error##: Failed to open file for reading demo: " + filename);
1675        }
1676}
1677
1678//-----------------------------------------------------------------------------
1679void KdTreeAppListener::loadFramesBinary(const String& filename, FrameList& framelist)
1680{
1681        // open file
1682        std::ifstream src(filename.c_str(), std::ios_base::out | std::ios_base::binary);
1683        if (src.is_open())
1684        {
1685                // clear the list
1686                framelist.clear();
1687
1688                int size = sizeof(Real);
1689
1690                Vector3 pos;
1691                Quaternion or;
1692                Real time;
1693
1694                while (!src.eof())
1695                {
1696                        src.read((char *)&pos.x, size);
1697                        src.read((char *)&pos.y, size);
1698                        src.read((char *)&pos.z, size);
1699                        src.read((char *)&or.w, size);
1700                        src.read((char *)&or.x, size);
1701                        src.read((char *)&or.y, size);
1702                        src.read((char *)&or.z, size);
1703                        src.read((char *)&time, size);
1704
1705                        framelist.push_back(FrameInfo(pos, or, time));
1706                }
1707
1708                // HACK pop last frame, was doubled while reading
1709                framelist.pop_back();
1710
1711                src.close();
1712        }
1713        else
1714        {
1715                LogManager::getSingleton().logMessage("##Error##: Failed to open file for reading demo: " + filename);
1716        }
1717}
1718
1719//-----------------------------------------------------------------------------
1720void KdTreeAppListener::saveLog()
1721{
1722        // field separator and record separator
1723        static const String fs = ",", rs ="\n", ds = ":";
1724        // stats
1725        Real minFPS = Math::POS_INFINITY, maxFPS = 0.0, avgFPS = 0.0;
1726        String line, storedname;
1727        String demopath, demoname;
1728        StringUtil::splitFilename(mOptions.mDemoInfileName, demoname, demopath);
1729       
1730        // check if logfile exists
1731        std::ifstream logread(mOptions.mDemoLogfileName.c_str());
1732        if (logread.is_open())
1733        {
1734                // read first line, shuold start with the name of the demo
1735                // if matches, OK, otherwise do something
1736                logread >> line;
1737                storedname = line.substr(0,line.find_first_of(','));
1738                if (storedname != demoname)
1739                {
1740                        LogManager::getSingleton().logMessage(
1741                                "##Error##: Saved demo stats do not match the current demo: " +
1742                                storedname + " != " + demoname);
1743                        logread.close();
1744                        return;
1745                }
1746        }
1747        // otherwise write header
1748        else
1749        {
1750                std::ofstream logheader(mOptions.mDemoLogfileName.c_str());
1751                if (logheader.is_open())
1752                {
1753                        // demo title
1754                        logheader << demoname << fs;
1755                        // seconds
1756                        for (size_t i = 0; i < mDemoFPS.size(); i ++)
1757                        {
1758                                logheader << (i+1) << fs;
1759                        }
1760                        // minFPS, avgFPS, maxFPS, comment, record separator
1761                        logheader << "\"min FPS\"" << fs << "\"avg FPS\"" << fs << "\"max FPS\"" << fs
1762                                << "\"# Frames \"" << fs << "\"Total Time\"" << fs << "\"Comment\"" << rs;
1763                        logheader.close();
1764                }
1765                else
1766                {
1767                        LogManager::getSingleton().logMessage(
1768                                "##Error##: Failed to write log demo header to " +
1769                                mOptions.mDemoLogfileName);
1770                        return;
1771
1772                }
1773        }
1774
1775        // append current stats
1776        std::ofstream logwrite(mOptions.mDemoLogfileName.c_str(), std::ios_base::app);
1777        if (logwrite.is_open())
1778        {
1779                // demo settings
1780                logwrite << "\"" << SCENEMANAGER[mOptions.mSceneManager];
1781                if (mOptions.mSceneManager == SM_KDT || mOptions.mSceneManager == SM_KTE)
1782                {
1783                        // info about enhanced visibility if internal rendering
1784                        String senhvis;
1785                        if (mOptions.mRenderMethod == KdTree::KDRM_INTERNAL)
1786                        {
1787                                if (mOptions.mEnhancedVisibility)
1788                                        senhvis = "E" + ds;
1789                                else
1790                                        senhvis = "S" + ds;
1791                        }
1792
1793                        logwrite << ds << RENDERMETHOD[mOptions.mRenderMethod] << ds << senhvis <<
1794                                mOptions.mMaxDepth << ds << mOptions.mKT << ds << mOptions.mKI << ds <<
1795                                BUILDMETHOD[mOptions.mBuildMethod];
1796                }
1797                else if (mOptions.mSceneManager == SM_OCM && mOptions.mRenderMethod != KdTree::KDRM_INTERNAL)
1798                {
1799                        logwrite << ds << RENDERMETHOD[CONV_OCM_TO_KDT_ALG(mOptions.mRenderMethod)];
1800                }
1801                logwrite << "\"" << fs;
1802                // per second stats
1803                for (std::list<Real>::iterator it = mDemoFPS.begin(); it != mDemoFPS.end(); it ++)
1804                {
1805                        if (*it < minFPS)
1806                                minFPS = *it;
1807
1808                        if (*it > maxFPS)
1809                                maxFPS = *it;
1810
1811                        //avgFPS += *it;
1812
1813                        logwrite << (int)(*it) << fs;
1814
1815                }
1816                //avgFPS /= mDemoFPS.size();
1817                avgFPS = mDemoStats.mTotalNumFrames / mDemoStats.mTotalEllapsedTime;
1818                // minFPS, avgFPS, maxFPS, comment, record separator
1819                logwrite << (int)minFPS << fs << (int)avgFPS << fs << (int)maxFPS << fs
1820                        << mDemoStats.mTotalNumFrames << fs << mDemoStats.mTotalEllapsedTime << fs
1821                        << "\"" << mOptions.mComment << "\"" << rs;
1822                logwrite.close();
1823        }
1824        else
1825        {
1826                LogManager::getSingleton().logMessage(
1827                        "##Error##: Failed to write demo log to " +
1828                        mOptions.mDemoLogfileName);
1829        }
1830}
1831
1832//-----------------------------------------------------------------------------
1833void KdTreeAppListener::saveFrameInfo(Real elapsedTime)
1834{
1835        mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), elapsedTime));
1836}
1837
1838//-----------------------------------------------------------------------------
1839void KdTreeAppListener::setDemoOverlay()
1840{
1841        // init overlay if not present
1842        if (!mDemoOverlay || !mDemoStatus || !mDemoTime)
1843        {
1844                OGRE_DELETE(mDemoOverlay);
1845                OGRE_DELETE(mDemoStatus);
1846                OGRE_DELETE(mDemoTime);
1847
1848                mDemoStatus = OverlayManager::getSingleton().createOverlayElement("Panel", "KdTree/DemoStatus");
1849                mDemoStatus->setMetricsMode(GMM_PIXELS);
1850                mDemoStatus->setDimensions(32, 32);
1851                mDemoStatus->setLeft(64);
1852
1853                mDemoTime = static_cast<TextAreaOverlayElement *>
1854                        (OverlayManager::getSingleton().createOverlayElement("TextArea", "KdTree/DemoTime"));
1855                mDemoTime->setMetricsMode(GMM_PIXELS);
1856                mDemoTime->setTop(6);
1857                mDemoTime->setLeft(104);
1858                mDemoTime->setFontName("TrebuchetMSBold");
1859                mDemoTime->setCharHeight(24.0);
1860                mDemoTime->setCaption("00:00");
1861
1862                mDemoFPSDisp = static_cast<TextAreaOverlayElement *>
1863                        (OverlayManager::getSingleton().createOverlayElement("TextArea", "KdTree/DemoFPS"));
1864                mDemoFPSDisp->setMetricsMode(GMM_PIXELS);
1865                mDemoFPSDisp->setAlignment(TextAreaOverlayElement::Right);
1866                mDemoFPSDisp->setTop(6);
1867                mDemoFPSDisp->setLeft(48);
1868                mDemoFPSDisp->setFontName("TrebuchetMSBold");
1869                mDemoFPSDisp->setCharHeight(24.0);
1870                mDemoFPSDisp->setCaption("0");
1871
1872                PanelOverlayElement *demoCont = static_cast<PanelOverlayElement *>
1873                        (OverlayManager::getSingleton().createOverlayElement("Panel", "KdTree/DemoTimePanel"));
1874                demoCont->setMetricsMode(GMM_PIXELS);
1875                demoCont->setHorizontalAlignment(GHA_CENTER);
1876                demoCont->setVerticalAlignment(GVA_TOP);
1877                demoCont->setTop(5);
1878                demoCont->setLeft(-80);
1879                demoCont->setDimensions(160, 32);
1880                demoCont->addChild(mDemoFPSDisp);
1881                demoCont->addChild(mDemoStatus);
1882                demoCont->addChild(mDemoTime);
1883                //demoCont->setMaterialName("Core/StatsBlockCenter");
1884
1885                mDemoOverlay = OverlayManager::getSingleton().create("KdTree/DemoOverlay");
1886                mDemoOverlay->setZOrder(500);
1887                //mDemoOverlay->add2D(static_cast<PanelOverlayElement *>(mDemoStatus));
1888                mDemoOverlay->add2D(demoCont);
1889        }
1890
1891        switch(mAppState)
1892        {
1893        case AS_NORMAL:
1894                mDemoOverlay->hide();
1895                break;
1896        case AS_PLAYBACK:
1897                mDemoStatus->setMaterialName("KdTree/DemoPlayButton");
1898                mDemoTime->setColourTop(ColourValue(0.5, 0.7, 0.5));
1899                mDemoTime->setColourBottom(ColourValue(0.3, 0.5, 0.3));
1900                mDemoFPSDisp->setColourTop(ColourValue(0.5, 0.7, 0.5));
1901                mDemoFPSDisp->setColourBottom(ColourValue(0.3, 0.5, 0.3));
1902                mDemoOverlay->show();
1903                break;
1904        case AS_RECORD:
1905                mDemoStatus->setMaterialName("KdTree/DemoRecordButton");
1906                mDemoTime->setColourTop(ColourValue(0.7, 0.5, 0.5));
1907                mDemoTime->setColourBottom(ColourValue(0.5, 0.3, 0.3));
1908                mDemoFPSDisp->setColourTop(ColourValue(0.7, 0.5, 0.5));
1909                mDemoFPSDisp->setColourBottom(ColourValue(0.5, 0.3, 0.3));
1910                mDemoOverlay->show();
1911                break;
1912        default:
1913            break;
1914        }
1915
1916}
Note: See TracBrowser for help on using the repository browser.