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

Revision 1273, 47.2 KB checked in by szydlowski, 18 years ago (diff)

Added the KdTerrainSceneManager?, a subclass of the KdTreeSceneManager? capable of rendering terrain like the TerrainSceneManager? from Ogre.
All the *Kd*Terrain* classes are identical to their octree counterparts, save prefixing all classes and structures with Kd to avoid namespace clashes.
This was necessary, since the TerrainSceneManager? was hard coded in these classes, and all references had to be replaced with the KdTerrainSceneManager?.
Also added a comprehensive README for the demo application.

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