#include #include #include #include "TestKdTreeAppListener.h" #include "TestKdTree.h" #include const Real KdTreeAppListener::DEMO_WAIT = 5.0; const String KdTreeAppListener::NA = ": N/A"; const String KdTreeAppListener::RENDERMETHOD[] = { "INT", "VFC", "SWC", "CHC" }; const String KdTreeAppListener::RENDERMETHODCAPTION[] = { "Internal Frustum Culling", "View Frustum Culling", "Stop and Wait Culling", "Coherent Hierarchical Culling" }; const String KdTreeAppListener::BUILDMETHOD[] = { "RE", "PQ" }; const String KdTreeAppListener::BUILDMETHODCAPTION[] = { "Recursive", "Priority Queue" }; const String KdTreeAppListener::SCENEMANAGER[] = { "KDT", "KTE", "OCM", "OCT", "TER", "GEN" }; const String KdTreeAppListener::SCENEMANAGERNAME[] = { "KdTreeSceneManager", "KdTreeTerrainSceneManager", "OcclusionCullingSceneManager", "OctreeSceneManager", "TerrainSceneManager", "DefaultSceneManager" }; void KdTreeAppListener::updateStats(void) { static unsigned int opt = 0; static char str[100]; static String currFps = "Current FPS: "; static String avgFps = "Average FPS: "; static String bestFps = "Best FPS: "; static String worstFps = "Worst FPS: "; static String tris = "Triangle Count: "; // update stats when necessary try { OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps"); OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps"); const RenderTarget::FrameStats& stats = mWindow->getStatistics(); guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS)); guiCurr->setCaption(currFps + StringConverter::toString((int)stats.lastFPS)); guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS) +" "+StringConverter::toString(stats.bestFrameTime)+" ms"); guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS) +" "+StringConverter::toString(stats.worstFrameTime)+" ms"); OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris"); guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount)); OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); guiDbg->setCaption(mWindow->getDebugText()); //-- culling stats mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt); mFrustumCulledNodesInfo->setCaption(str); mSceneMgr->getOption("NumQueryCulledNodes", &opt); sprintf(str,": %d", opt); mQueryCulledNodesInfo->setCaption(str); mSceneMgr->getOption("NumHierarchyNodes", &opt); sprintf(str,": %d", opt); mHierarchyNodesInfo->setCaption(str); mSceneMgr->getOption("NumRenderedNodes", &opt); sprintf(str,": %d", opt); mRenderedNodesInfo->setCaption(str); // take old value into account in order to create no sudden changes mSceneMgr->getOption("NumQueriesIssued", &opt); mDelayedQueriesIssued = mDelayedQueriesIssued * 0.8 + (float)opt * 0.2f; sprintf(str,": %d", (int)mDelayedQueriesIssued); mQueriesIssuedInfo->setCaption(str); mSceneMgr->getOption("NumTraversedNodes", &opt); mDelayedTraversedNodes = mDelayedTraversedNodes * 0.8 + (float)opt * 0.2f; sprintf(str,": %d", (int)mDelayedTraversedNodes); mTraversedNodesInfo->setCaption(str); } catch(...) { // ignore } } // Constructor takes a RenderWindow because it uses that to determine input context KdTreeAppListener::KdTreeAppListener(RenderWindow* win, SceneManager* sm, const Options& options, bool useBufferedInputKeys, bool useBufferedInputMouse): // basic mWindow(win), mSceneMgr(sm), mOptions(options), mUseBufferedInputKeys(useBufferedInputKeys), mUseBufferedInputMouse(useBufferedInputMouse), // elements mCamNode(0), mCamera(0), mTopCam(0), // toggle mStatsOn(true), mVizCamera(false), mFreeMove(false), mTopCamFollow(true), mShowTree(SHOWTREE_OFF), // view cells mViewCellsLoaded(false), mUseViewCells(false), mUseVisibilityFilter(false), //counters mSeqNum(0), mNumScreenShots(0), // rendering/texture options mSceneDetailIndex(PM_SOLID), mFiltering(TFO_ANISOTROPIC), mAniso(8), // chc stats mDelayedQueriesIssued(0.0f), mDelayedTraversedNodes(0.0f), // movement mTranslateVector(Vector3::ZERO), mVizCamTransVect(Vector3::ZERO), mRotX(0.0f), mRotY(0.0f), mMoveScale(0.0f), mRotScale(0.0f), mDeathAngle(0.0f), mRaySceneQuery(0), // just to stop toggles flipping too fast mTimeUntilNextToggle(0.0f), // stuff for walkthrough recording/playback mTimeUntilNextLogWrite(options.mDemoInterval), mTimeRemaining(0.0f), mWaitBeforeDemoStart(0.0f), mAppState(AS_NORMAL) { mInputTypeSwitchingOn = mUseBufferedInputKeys || mUseBufferedInputMouse; if (mInputTypeSwitchingOn) { mEventProcessor = new EventProcessor(); mEventProcessor->initialise(win); mEventProcessor->startProcessingEvents(); mEventProcessor->addKeyListener(this); mInputDevice = mEventProcessor->getInputReader(); } else { mInputDevice = PlatformManager::getSingleton().createInputReader(); mInputDevice->initialise(win,true, true); } MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering); MaterialManager::getSingleton().setDefaultAnisotropy(mAniso); mCamera = sm->getCamera("PlayerCam"); mTopCam = sm->getCamera("TopCam"); mCamNode = sm->getSceneNode("PlayerCamNode"); mRaySceneQuery = mSceneMgr->createRayQuery(Ray(mCamNode->getPosition(), Vector3::NEGATIVE_UNIT_Y)); mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay"); mKdTreeOverlay = OverlayManager::getSingleton().getByName("KdTree/DebugOverlay"); mDemoOverlay = 0; mDemoStatus = 0; mDemoTime = 0; // loading view cells overlay mLoadingOverlay = OverlayManager::getSingleton().getByName("Example/Visibility/LoadingOverlay"); mMyLoadingInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/Loading/MyLoadingInfo"); mMyLoadingInfo->setCaption("loading view cells ..."); mLoadingOverlay->hide(); initKdTreeOverlay(); initStatsOverlay(); // set view cells if (mOptions.mSceneType == ST_GEOMETRY) { switch(mOptions.mViewCells) { case VCM_ON: toggleUseViewCells(); break; case VCM_FILTER: toggleUseViewCells(); toggleUseVisibilityFilter(); break; } } if (!mOptions.mDemoInfileName.empty()) loadFrames(mOptions.mDemoInfileName, mFrameList); if (!mOptions.mDemoInfileName.empty() && mOptions.mDemoMode) { // force X second wait when in demo mode - avoids initial low framerate due to loading delays mWaitBeforeDemoStart = DEMO_WAIT; // set playback icon togglePlayback(); // hide all other overlays mStatsOn = false; } showDebugOverlay(mStatsOn); setDemoOverlay(); } //----------------------------------------------------------------------- KdTreeAppListener::~KdTreeAppListener() { if (mInputTypeSwitchingOn) { delete mEventProcessor; } else { PlatformManager::getSingleton().destroyInputReader( mInputDevice ); } } //----------------------------------------------------------------------- void KdTreeAppListener::initOverlayElement(OverlayElement **elInfo, String ext, String name, int top, String caption) { OverlayElement *el = OverlayManager::getSingleton().getOverlayElement(ext + name); (*elInfo) = OverlayManager::getSingleton().getOverlayElement(ext + name + "Info"); (*elInfo)->setCaption(caption); el->setTop(top); (*elInfo)->setTop(top); } //----------------------------------------------------------------------- void KdTreeAppListener::initStatsOverlay() { const int border_height = 10; const int vert_space = 15; //-- visibility culling stats overlay int top = border_height; String ext = "KdTree/Visibility/"; initOverlayElement(&mFrustumCulledNodesInfo, ext, "FrustumCulledNodes", top, ": 0"); top += vert_space; initOverlayElement(&mQueryCulledNodesInfo, ext, "QueryCulledNodes", top, ": 0"); top += vert_space; initOverlayElement(&mTraversedNodesInfo, ext, "TraversedNodes", top, ": 0"); top += vert_space; initOverlayElement(&mHierarchyNodesInfo, ext, "HierarchyNodes", top, ": 0"); top += vert_space; initOverlayElement(&mRenderedNodesInfo, ext, "RenderedNodes", top, ": 0"); top += vert_space; initOverlayElement(&mObjectsCountInfo, ext, "ObjectsCount", top, ": 0"); top += vert_space; initOverlayElement(&mQueriesIssuedInfo, ext, "QueriesIssued", top, ": 0"); top += vert_space; OverlayElement *visPanel = OverlayManager::getSingleton(). getOverlayElement("KdTree/VisibilityStatsPanel"); visPanel->setHeight(top + border_height); } //----------------------------------------------------------------------- void KdTreeAppListener::initKdTreeOverlay() { const int border_height = 10; const int vert_space = 15; int top = border_height; String ext = "KdTree/"; String sMD, sKT, sKI, sHL, sBM, sRM, sFM, sTC, sEV, sVC, sVF; int maxd; if (mSceneMgr->getOption("KdTreeMaxDepth", &maxd)) sMD = ": " + StringConverter::toString(maxd); else sMD = NA; Real kt; if (mSceneMgr->getOption("KT", &kt)) sKT = ": " + StringConverter::toString(kt); else sKT = NA; Real ki; if (mSceneMgr->getOption("KI", &ki)) sKI = ": " + StringConverter::toString(ki); else sKI = NA; int hl; if (mSceneMgr->getOption("HiLiteLevel", &hl)) sHL = ": " + StringConverter::toString(hl); else sHL = NA; if (mShowTree == SHOWTREE_OFF) sHL = ": off"; int bm; if (mSceneMgr->getOption("BuildMethod", &bm)) sBM = ": " + BUILDMETHODCAPTION[bm]; else sBM = NA; int rm; if (mSceneMgr->getOption("RenderMethod", &rm)) sRM = ": " + RENDERMETHODCAPTION[rm]; else sRM = NA; // hack to allow mode switching in OCM if (mOptions.mSceneManager == SM_OCM) { rm = CONV_KDT_TO_OCM_ALG(mOptions.mRenderMethod); sRM = ": " + RENDERMETHODCAPTION[CONV_OCM_TO_KDT_ALG(rm)]; } bool enh; if (mSceneMgr->getOption("EnhancedVisibility", &enh)) { if (enh) sEV = ": Enhanced"; else sEV = ": Simple"; } else { sEV = NA; } sFM = NA; if (mFreeMove) sFM = ": Free"; else sFM = ": Ground"; sTC = NA; if (mTopCamFollow) sTC = ": Follow"; else sTC = ": Free"; if (mSceneMgr->getOption("UseViewCells", &mUseViewCells) && mOptions.mSceneType == ST_GEOMETRY) { if (mUseViewCells) sVC = ": on"; else sVC = ": off"; } else { if (mOptions.mSceneType == ST_GEOMETRY && mOptions.myApp->getViewCellsFileName() != "" && (mOptions.mSceneManager == SM_KDT || mOptions.mSceneManager == SM_KTE || mOptions.mSceneManager == SM_OCM)) { sVC = ": off"; } else { sVC = NA; } } if (mSceneMgr->getOption("UseVisibilityFilter", &mUseVisibilityFilter) && mOptions.mSceneType == ST_GEOMETRY) { if (mUseVisibilityFilter) sVF = ": on"; else sVF = ": off"; } else { if (mOptions.mSceneType == ST_GEOMETRY && mOptions.myApp->getViewCellsFileName() != "" && (mOptions.mSceneManager == SM_KDT || mOptions.mSceneManager == SM_KTE || mOptions.mSceneManager == SM_OCM)) { sVF = ": off"; } else { sVF = NA; } } initOverlayElement(&mRenderMethodInfo, ext, "RenderMethod", top, sRM); top += vert_space; initOverlayElement(&mEnhancedVisInfo, ext, "EnhancedVis", top, sEV); top += vert_space; initOverlayElement(&mBuildMethodInfo, ext, "BuildMethod", top, sBM); top += vert_space; initOverlayElement(&mKdTreeMaxDepthInfo, ext, "KdTreeMaxDepth", top, sMD); top += vert_space; initOverlayElement(&mHighlightLevelInfo, ext, "HighlightLevel", top, sHL); top += vert_space; initOverlayElement(&mKTInfo, ext, "KT", top, sKT); top += vert_space; initOverlayElement(&mKIInfo, ext, "KI", top, sKI); top += vert_space; initOverlayElement(&mMovementInfo, ext, "Movement", top, sFM); top += vert_space; initOverlayElement(&mTopCamInfo, ext, "TopCam", top, sTC); top += vert_space; initOverlayElement(&mViewCellsInfo, ext, "ViewCells", top, sVC); top += vert_space; initOverlayElement(&mViewFilterInfo, ext, "ViewFilter", top, sVF); top += vert_space; OverlayElement *visPanel = OverlayManager::getSingleton(). getOverlayElement("KdTree/OptionsPanel"); visPanel->setHeight(top + border_height); } void KdTreeAppListener::showDebugOverlay(bool show) { if (mDebugOverlay && mKdTreeOverlay) { if (show) { mDebugOverlay->show(); mKdTreeOverlay->show(); } else { mDebugOverlay->hide(); mKdTreeOverlay->hide(); } } } void KdTreeAppListener::toggleUseViewCells() { // viewcells apply only for scenes loaded from geometry if (mOptions.mSceneType != ST_GEOMETRY) return; mUseViewCells = !mUseViewCells; // load on demand if (mUseViewCells && !mViewCellsLoaded) { mLoadingOverlay->show(); // call once to load view cell loading overlay mWindow->update(); mViewCellsLoaded = mSceneMgr->setOption("LoadViewCells", mOptions.myApp->getViewCellsFileName().c_str()); if (!mViewCellsLoaded) { LogManager::getSingleton().logMessage("#@#@ Error: loading view cells from " + mOptions.myApp->getViewCellsFileName() + " failed."); } mLoadingOverlay->hide(); } if (mSceneMgr->setOption("UseViewCells", &mUseViewCells)) { if (mUseViewCells) mViewCellsInfo->setCaption(": on"); else mViewCellsInfo->setCaption(": off"); } else { mViewCellsInfo->setCaption(NA); } } void KdTreeAppListener::toggleUseVisibilityFilter() { mUseVisibilityFilter = !mUseVisibilityFilter; if (mSceneMgr->setOption("UseVisibilityFilter", &mUseVisibilityFilter)) { if (mUseVisibilityFilter) mViewFilterInfo->setCaption(": on"); else mViewFilterInfo->setCaption(": off"); } else { mViewFilterInfo->setCaption(NA); } } void KdTreeAppListener::toggleVizCamera() { static int nodeVizMode = 0; nodeVizMode = (nodeVizMode + 1) % NODEVIZ_MODES_NUM; if (nodeVizMode != 0) { if (!mVizCamera) { Viewport* tvp = mWindow->addViewport(mTopCam, VIZ_VIEWPORT_Z_ORDER, 0.66, 0.66, 0.34, 0.34); tvp->setBackgroundColour(ColourValue(1.0, 0.0, 0.0)); tvp->setOverlaysEnabled(false); mTopCam->setAspectRatio( Real(tvp->getActualWidth())/Real(tvp->getActualHeight())); mVizCamera = true; mSceneMgr->setOption("VisualizeCulledNodes", &mVizCamera); } bool renderNodesForViz = (nodeVizMode == NODEVIZ_RENDER_NODES) || (nodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT); bool renderNodesContentForViz = (nodeVizMode == NODEVIZ_RENDER_NODES_AND_CONTENT); mSceneMgr->setOption("RenderNodesForViz", &renderNodesForViz); mSceneMgr->setOption("RenderNodesContentForViz", &renderNodesContentForViz); } else { mWindow->removeViewport(VIZ_VIEWPORT_Z_ORDER); mVizCamera = false; mSceneMgr->setOption("VisualizeCulledNodes", &mVizCamera); } } void KdTreeAppListener::toggleShowBoxes() { mShowTree = (mShowTree + 1) % SHOWTREE_MODES_NUM; bool show = false, all = false; switch (mShowTree) { case SHOWTREE_OFF: break; case SHOWTREE_HILITE: show = true; break; case SHOWTREE_ALL: show = all = true; break; } // set display if (mSceneMgr->getTypeName() == "OctreeSceneManager") mSceneMgr->setOption("ShowOctree", &show); else if ( mSceneMgr->getTypeName() == "KdTreeSceneManager" || mSceneMgr->getTypeName() == "KdTreeTerrainSceneManager") mSceneMgr->setOption("ShowKdTree", &show); // set showall mSceneMgr->setOption("ShowAllBoxes", &all); if (!show) mHighlightLevelInfo->setCaption(": off"); else { int hl; if (mSceneMgr->getOption("HiLiteLevel", &hl)) mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl)); else mHighlightLevelInfo->setCaption(NA); } } void KdTreeAppListener::toggleEnhancedVisibility() { bool mode; if (mSceneMgr->getOption("EnhancedVisibility", &mode)) { mode = !mode; if (mSceneMgr->setOption("EnhancedVisibility", &mode)) { if (mode) mEnhancedVisInfo->setCaption(": Enhanced"); else mEnhancedVisInfo->setCaption(": Simple"); mOptions.mEnhancedVisibility = mode; } } else { mEnhancedVisInfo->setCaption(NA); } } void KdTreeAppListener::toggleBuildMethod() { int bm; if (mSceneMgr->getOption("BuildMethod", &bm)) { bm = (bm + 1) % KdTree::KDBM_SIZE; if (mSceneMgr->setOption("BuildMethod", &bm)) { mBuildMethodInfo->setCaption(": " + BUILDMETHODCAPTION[bm]); mOptions.mBuildMethod = bm; } } else { mBuildMethodInfo->setCaption(NA); } } void KdTreeAppListener::toggleRenderMethod() { int rm; if (mSceneMgr->getOption("RenderMethod", &rm)) { rm = (rm + 1) % KdTree::KDRM_SIZE; if (mSceneMgr->setOption("RenderMethod", &rm)) { mRenderMethodInfo->setCaption(": " + RENDERMETHODCAPTION[rm]); mOptions.mRenderMethod = rm; } } else { mRenderMethodInfo->setCaption(NA); } // hack to allow mode switching in OCM, cannot extract setting from sm if (mOptions.mSceneManager == SM_OCM) { static int alg = CONV_KDT_TO_OCM_ALG(mOptions.mRenderMethod); alg = (alg + 1) % 3; if (mSceneMgr->setOption("Algorithm", &alg)) mRenderMethodInfo->setCaption(": " + RENDERMETHODCAPTION[CONV_OCM_TO_KDT_ALG(alg)]); } } bool KdTreeAppListener::processUnbufferedKeyInput(const FrameEvent& evt) { // ignore all keystrokes except escape when in demo mode if (mOptions.mDemoMode) { if (mInputDevice->isKeyDown(KC_ESCAPE)) return false; else return true; } if (mInputDevice->isKeyDown(KC_F1) && mTimeUntilNextToggle <= 0) { // TODO show help overlay } // show/hide vis viewport if (mInputDevice->isKeyDown(KC_F2) && mTimeUntilNextToggle <= 0) { toggleVizCamera(); mTimeUntilNextToggle = 0.5; } // show/hide kdtree boxes if (mInputDevice->isKeyDown(KC_F3) && mTimeUntilNextToggle <= 0) { toggleShowBoxes(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_F4) && mTimeUntilNextToggle <= 0) { bool toggleShow; mSceneMgr->getOption("ShowNodes", &toggleShow); toggleShow = !toggleShow; mSceneMgr->setOption("ShowNodes", &toggleShow); mTimeUntilNextToggle = 0.5; } // demo recording stuff if (mInputDevice->isKeyDown(KC_F5) && mTimeUntilNextToggle <= 0) { toggleRecord(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_F6) && mTimeUntilNextToggle <= 0) { if (!mOptions.mDemoOutfileName.empty() && !mFrameList.empty()) saveFrames(mOptions.mDemoOutfileName, mFrameList); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_F7) && mTimeUntilNextToggle <= 0) { SceneNode *entnode = mSceneMgr->getSceneNode("AnchorNode"); if (!mOptions.myApp->saveSceneASCII(mOptions.mSceneOutfileName, entnode)) LogManager::getSingleton().logMessage( "##Error##: Failed to save scene to " + mOptions.mSceneOutfileName); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_F8) && mTimeUntilNextToggle <= 0) { // fill scene only once (for now), stop if anchor node exists try { SceneNode *entnode = mSceneMgr->getSceneNode("AnchorNode"); } catch (Exception) { // read interesting params from config file ConfigFile terrainconf; std::stringstream s; Real x,y,z; terrainconf.load("terrain.cfg"); s << terrainconf.getSetting("PageWorldX"); s >> x; s.clear(); s << terrainconf.getSetting("MaxHeight"); s >> y; s.clear(); s << terrainconf.getSetting("PageWorldZ"); s >> z; s.clear(); mOptions.myApp->createTerrainScene(x, y * 0.3, z); // rebuild tree mSceneMgr->setOption("RebuildKdTree", 0); } mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_F9) && mTimeUntilNextToggle <= 0) { togglePlayback(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_0) && mTimeUntilNextToggle <= 0) { toggleBuildMethod(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_SPACE) && mTimeUntilNextToggle <= 0) { toggleRenderMethod(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_C) && mTimeUntilNextToggle <= 0) { toggleUseViewCells(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_X) && mTimeUntilNextToggle <= 0) { toggleUseVisibilityFilter(); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_B) && mTimeUntilNextToggle <= 0) { mSceneMgr->showBoundingBoxes( ! mSceneMgr->getShowBoundingBoxes() ); mTimeUntilNextToggle = 0.5; } const static int vizCamSpeedup = 12; // moving the cull camera if (mInputDevice->isKeyDown(KC_NUMPAD2)) { mVizCamTransVect.y = -mMoveScale * vizCamSpeedup; } if (mInputDevice->isKeyDown(KC_NUMPAD8)) { mVizCamTransVect.y = mMoveScale * vizCamSpeedup; } if (mInputDevice->isKeyDown(KC_NUMPAD4)) { mVizCamTransVect.x = -mMoveScale * vizCamSpeedup; } if (mInputDevice->isKeyDown(KC_NUMPAD6)) { mVizCamTransVect.x = mMoveScale * vizCamSpeedup; } if (mInputDevice->isKeyDown(KC_SUBTRACT)) { mVizCamTransVect.z = mMoveScale * vizCamSpeedup; } if (mInputDevice->isKeyDown(KC_ADD)) { mVizCamTransVect.z = -mMoveScale * vizCamSpeedup; } if ((mInputDevice->isKeyDown(KC_1) || mInputDevice->isKeyDown(KC_2)) && mTimeUntilNextToggle <= 0) { int currdepth; if (mSceneMgr->getOption("KdTreeMaxDepth", &currdepth)) { if (mInputDevice->isKeyDown(KC_1)) currdepth--; else if (mInputDevice->isKeyDown(KC_2)) currdepth++; if (mSceneMgr->setOption("KdTreeMaxDepth", &currdepth)) { mKdTreeMaxDepthInfo->setCaption(": " + StringConverter::toString(currdepth)); int hl; if (mSceneMgr->getOption("HiLiteLevel", &hl)) mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl)); else mHighlightLevelInfo->setCaption(NA); } } else { mKdTreeMaxDepthInfo->setCaption(NA); mHighlightLevelInfo->setCaption(NA); } if (mShowTree == SHOWTREE_OFF) mHighlightLevelInfo->setCaption(": off"); mTimeUntilNextToggle = 0.2; } if ((mInputDevice->isKeyDown(KC_3) || mInputDevice->isKeyDown(KC_4)) && mTimeUntilNextToggle <= 0) { int hl; if (mSceneMgr->getOption("HiLiteLevel", &hl)) { if (mInputDevice->isKeyDown(KC_3)) hl--; else if (mInputDevice->isKeyDown(KC_4)) hl++; if (mSceneMgr->setOption("HiLiteLevel", &hl)) mHighlightLevelInfo->setCaption(": " + StringConverter::toString(hl)); } else { mHighlightLevelInfo->setCaption(NA); } if (mShowTree == SHOWTREE_OFF) mHighlightLevelInfo->setCaption(": off"); mTimeUntilNextToggle = 0.2; } if ((mInputDevice->isKeyDown(KC_5) ||mInputDevice->isKeyDown(KC_6)) && mTimeUntilNextToggle <= 0) { Real kt; if (mSceneMgr->getOption("KT", &kt)) { if (mInputDevice->isKeyDown(KC_5)) kt -= 0.1; else if (mInputDevice->isKeyDown(KC_6)) kt += 0.1; if (kt < 0.1) kt = 0.1; if (mSceneMgr->setOption("KT", &kt)) mKTInfo->setCaption(": " + StringConverter::toString(kt)); } else { mKTInfo->setCaption(NA); } mTimeUntilNextToggle = 0.2; } if ((mInputDevice->isKeyDown(KC_7) || mInputDevice->isKeyDown(KC_8)) && mTimeUntilNextToggle <= 0) { Real ki; if (mSceneMgr->getOption("KI", &ki)) { if (mInputDevice->isKeyDown(KC_7)) ki -= 0.1; else if (mInputDevice->isKeyDown(KC_8)) ki += 0.1; if (ki < 0.1) ki = 0.1; if (mSceneMgr->setOption("KI", &ki)) mKIInfo->setCaption(": " + StringConverter::toString(ki)); } else { mKIInfo->setCaption(NA); } mTimeUntilNextToggle = 0.2; } if (mInputDevice->isKeyDown(KC_U) && mTimeUntilNextToggle <= 0) { mFreeMove = !mFreeMove; String move = ": N/A"; if (mFreeMove) move = ": Free"; else move = ": Ground"; mMovementInfo->setCaption(move); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_I) && mTimeUntilNextToggle <= 0) { mTopCamFollow = !mTopCamFollow; String move = ": N/A"; if (mTopCamFollow) move = ": Follow"; else move = ": Free"; mTopCamInfo->setCaption(move); mTimeUntilNextToggle = 0.5; } if (mInputDevice->isKeyDown(KC_BACK) && mTimeUntilNextToggle <= 0) { mSceneMgr->setOption("RebuildKdTree", 0); mTimeUntilNextToggle = 1; } //if (mInputDevice->isKeyDown(KC_N) && mTimeUntilNextToggle <= 0) //{ // //Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "robot.mesh"); // Entity * ent = mSceneMgr->createEntity("randominsert" + StringConverter::toString(mSeqNum), "razor.mesh"); // //Vector3 position(Math::RangeRandom(100, 1125), -0, Math::RangeRandom(-1125, 1125)); // Vector3 position(Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000), Math::RangeRandom(-5000, 5000)); // //Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), Vector3::UNIT_Y); // Vector3 axis(Math::RangeRandom(-1,1),Math::RangeRandom(-1,1),Math::RangeRandom(-1,1)); // axis.normalise(); // Quaternion orientation(Radian(Math::RangeRandom(-Math::PI, Math::PI)), axis); // Vector3 scale(Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5),Math::RangeRandom(0.5, 5)); // SceneNode * anchor = mSceneMgr->getSceneNode("AnchorNode"); // SceneNode *sn = anchor->createChildSceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum), position, orientation); // sn->attachObject(ent); // sn->setScale(scale); // mTimeUntilNextToggle = 0.5; // mSeqNum++; //} //if (mInputDevice->isKeyDown(KC_J) && mTimeUntilNextToggle <= 0) //{ // if (mSeqNum > 0) // { // mSeqNum--; // mSceneMgr->destroySceneNode("RandomInsertNode" + StringConverter::toString(mSeqNum)); // mSceneMgr->destroyEntity("randominsert" + StringConverter::toString(mSeqNum)); // mTimeUntilNextToggle = 0.5; // } //} //if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0) //{ // LogManager::getSingleton().logMessage("############## Camera Position:"); // LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getPosition())); // LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getOrientation())); // LogManager::getSingleton().logMessage("############## Cull Camera Position:"); // LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition())); // LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation())); // mTimeUntilNextToggle = 1.0; //} if (mInputDevice->isKeyDown(KC_A)) { // Move camera left mTranslateVector.x = -mMoveScale; } if (mInputDevice->isKeyDown(KC_D)) { // Move camera RIGHT mTranslateVector.x = mMoveScale; } /* Move camera forward by keypress. */ if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) ) { mTranslateVector.z = -mMoveScale; } /* Move camera backward by keypress. */ if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) ) { mTranslateVector.z = mMoveScale; } if (mInputDevice->isKeyDown(KC_PGUP)) { // Move camera up mTranslateVector.y = mMoveScale; } if (mInputDevice->isKeyDown(KC_PGDOWN)) { // Move camera down mTranslateVector.y = -mMoveScale; } if (mInputDevice->isKeyDown(KC_RIGHT)) { mCamNode->yaw(-mRotScale, Ogre::Node::TS_WORLD); } if (mInputDevice->isKeyDown(KC_LEFT)) { mCamNode->yaw(mRotScale, Ogre::Node::TS_WORLD); } if( mInputDevice->isKeyDown( KC_ESCAPE) ) { return false; } // see if switching is on, and you want to toggle if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_M) && mTimeUntilNextToggle <= 0) { switchMouseMode(); mTimeUntilNextToggle = 1; } if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_K) && mTimeUntilNextToggle <= 0) { // must be going from immediate keyboard to buffered keyboard switchKeyMode(); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_F) && mTimeUntilNextToggle <= 0) { mStatsOn = !mStatsOn; showDebugOverlay(mStatsOn); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_T) && mTimeUntilNextToggle <= 0) { switch(mFiltering) { case TFO_BILINEAR: mFiltering = TFO_TRILINEAR; mAniso = 1; break; case TFO_TRILINEAR: mFiltering = TFO_ANISOTROPIC; mAniso = 8; break; case TFO_ANISOTROPIC: mFiltering = TFO_BILINEAR; mAniso = 1; break; default: break; } MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering); MaterialManager::getSingleton().setDefaultAnisotropy(mAniso); showDebugOverlay(mStatsOn); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_SYSRQ) && mTimeUntilNextToggle <= 0) { char tmp[20]; sprintf(tmp, "screenshot_%d.png", ++mNumScreenShots); mWindow->writeContentsToFile(tmp); mTimeUntilNextToggle = 0.5; mWindow->setDebugText(String("Wrote ") + tmp); } if (mInputDevice->isKeyDown(KC_R) && mTimeUntilNextToggle <=0) { mSceneDetailIndex = (mSceneDetailIndex+1)%3 ; switch(mSceneDetailIndex) { case 0 : mCamera->setPolygonMode(PM_SOLID) ; break ; case 1 : mCamera->setPolygonMode(PM_WIREFRAME) ; break ; case 2 : mCamera->setPolygonMode(PM_POINTS) ; break ; } mTimeUntilNextToggle = 0.5; } static bool displayCameraDetails = false; if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0) { displayCameraDetails = !displayCameraDetails; mTimeUntilNextToggle = 0.5; if (!displayCameraDetails) { mWindow->setDebugText(""); } else { LogManager::getSingleton().logMessage("############## Camera Position:"); LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getDerivedPosition())); LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mCamera->getDerivedOrientation())); LogManager::getSingleton().logMessage("############## Cull Camera Position:"); LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getPosition())); LogManager::getSingleton().logMessage("############## " + StringConverter::toString(mTopCam->getOrientation())); } } if (displayCameraDetails) { // Print camera details mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) + " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation())); } // Return true to continue rendering return true; } bool KdTreeAppListener::processUnbufferedMouseInput(const FrameEvent& evt) { /* Rotation factors, may not be used if the second mouse button is pressed. */ /* If the second mouse button is pressed, then the mouse movement results in sliding the camera, otherwise we rotate. */ if( mInputDevice->getMouseButton( 1 ) ) { mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13; mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13; } else { mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13); mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13); } return true; } void KdTreeAppListener::moveCamera() { // Make all the changes to the camera // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW (e.g. airplane) mCamNode->yaw(mRotX, Ogre::Node::TS_WORLD); mCamNode->pitch(mRotY); //mCamNode->moveRelative(mTranslateVector); mCamNode->translate(mCamNode->getLocalAxes(), mTranslateVector); mTopCam->moveRelative(mVizCamTransVect); if (mTopCamFollow) { Vector3 toppos = mTopCam->getPosition(); Vector3 campos = mCamNode->getPosition(); mTopCam->setPosition(Vector3::ZERO); mTopCam->setOrientation(Quaternion::IDENTITY); mTopCam->setPosition(campos.x, toppos.y, campos.z); mTopCam->pitch(Radian(-Math::HALF_PI)); } if (!mFreeMove) { if (mOptions.mSceneType == ST_TERRAIN) { static Vector3 pos; static Ray updateRay; pos = mCamNode->getPosition(); updateRay.setOrigin(pos); updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y); mRaySceneQuery->setRay(updateRay); RaySceneQueryResult& qryResult = mRaySceneQuery->execute(); RaySceneQueryResult::iterator i = qryResult.begin(); if (i != qryResult.end() && i->worldFragment) { SceneQuery::WorldFragment* wf = i->worldFragment; mCamNode->setPosition(pos.x, wf->singleIntersection.y + 10, pos.z); } } else { static Vector3 pos; static Ray updateRay; pos = mCamNode->getPosition(); updateRay.setOrigin(pos); updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y); mRaySceneQuery->setRay(updateRay); RaySceneQueryResult& qryResult = mRaySceneQuery->execute(); RaySceneQueryResult::iterator i = qryResult.begin(); while (i != qryResult.end() && i->movable) { if (i->movable->getName() != "PlayerCam") { MovableObject *mov = i->movable; mCamNode->setPosition(pos.x, mov->getWorldBoundingBox().getCenter().y + 2, pos.z); break; } i++; } } } } // Override frameStarted event to process that (don't care about frameEnded) bool KdTreeAppListener::frameStarted(const FrameEvent& evt) { if(mWindow->isClosed()) return false; if (!mInputTypeSwitchingOn) { mInputDevice->capture(); } if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys) { // one of the input modes is immediate, so setup what is needed for immediate mouse/key movement if (mTimeUntilNextToggle >= 0) mTimeUntilNextToggle -= evt.timeSinceLastFrame; // If this is the first frame, pick a speed if (evt.timeSinceLastFrame == 0) { mMoveScale = 1; mRotScale = 0.1; } // Otherwise scale movement units by time passed since last frame else { // Move about 100 units per second, mMoveScale = mOptions.mMoveSpeed * evt.timeSinceLastFrame; // Take about 10 seconds for full rotation mRotScale = mOptions.mRotateSpeed * evt.timeSinceLastFrame; } mRotX = 0; mRotY = 0; mTranslateVector = Vector3::ZERO; mVizCamTransVect = Vector3::ZERO; } if (mUseBufferedInputKeys) { // no need to do any processing here, it is handled by event processor and // you get the results as KeyEvents } else { if (processUnbufferedKeyInput(evt) == false) { return false; } } if (mUseBufferedInputMouse) { // no need to do any processing here, it is handled by event processor and // you get the results as MouseEvents } else { if (processUnbufferedMouseInput(evt) == false) { return false; } } // do nothing until delay passes to stabilize frame rate mWaitBeforeDemoStart -= evt.timeSinceLastFrame; if (mWaitBeforeDemoStart > 0.0) { // do full turn to preload geometry static Real dps = (360 / DEMO_WAIT); mCamNode->yaw(Radian(Degree(dps * evt.timeSinceLastFrame)), Ogre::Node::TS_WORLD); return true; } // demo playback - replace position with stored one if (mAppState == AS_PLAYBACK) { // update time mTimeRemaining -= evt.timeSinceLastFrame; // update stats ++ mDemoStats.mNumFrames; ++ mDemoStats.mTotalNumFrames; mDemoStats.mEllapsedTime += evt.timeSinceLastFrame; mDemoStats.mTotalEllapsedTime += evt.timeSinceLastFrame; // set time display int m = (int)mDemoStats.mTotalEllapsedTime / 60; int s = (int)mDemoStats.mTotalEllapsedTime % 60; mDemoTime->setCaption( StringConverter::toString(m, 2, '0') + ":" + StringConverter::toString(s, 2, '0')); // set FPS display const RenderTarget::FrameStats& stats = mWindow->getStatistics(); mDemoFPSDisp->setCaption(StringConverter::toString((int)stats.lastFPS)); // store fps when in demo mode if (mOptions.mDemoMode) { // save FPS mTimeUntilNextLogWrite -= evt.timeSinceLastFrame; if (mTimeUntilNextLogWrite <= 0.0) { mTimeUntilNextLogWrite += mOptions.mDemoInterval; //const RenderTarget::FrameStats& stats = mWindow->getStatistics(); //mDemoFPS.push_back(stats.lastFPS); mDemoFPS.push_back(mDemoStats.mNumFrames / mDemoStats.mEllapsedTime); mDemoStats.mNumFrames = 0; mDemoStats.mEllapsedTime = 0.0f; } } static FrameList::iterator lastFrame; if (mCurrFrame == mFrameList.begin()) lastFrame = mCurrFrame; // advance to next stored frame while (mTimeRemaining <= 0.0 && mCurrFrame != mFrameList.end()) { lastFrame = mCurrFrame; ++ mCurrFrame; mTimeRemaining += mCurrFrame->mElapsedTime; } // when reached last frame, reset and stop playback if (mCurrFrame == mFrameList.end()) { togglePlayback(); // exit app when in demo mode if (mOptions.mDemoMode) { saveLog(); if (mOptions.mBurnIn) togglePlayback(); else return false; } } // interpolate position & orientation and modify move vectors else { // interpolation factor Real factor = 1.0 - mTimeRemaining / mCurrFrame->mElapsedTime; // interpolate position and orientation Vector3 pos = lastFrame->mPosition + factor * (mCurrFrame->mPosition - lastFrame->mPosition); Quaternion or = Quaternion::Slerp(factor, lastFrame->mOrientation, mCurrFrame->mOrientation); // update camera mCamNode->setPosition(pos); mCamNode->setOrientation(or); // update viz camera mTopCam->moveRelative(mVizCamTransVect); if (mTopCamFollow) { Vector3 toppos = mTopCam->getPosition(); Vector3 campos = mCamNode->getPosition(); mTopCam->setPosition(Vector3::ZERO); mTopCam->setOrientation(Quaternion::IDENTITY); mTopCam->setPosition(campos.x, toppos.y, campos.z); mTopCam->pitch(Radian(-Math::HALF_PI)); } } } else { if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys) { // one of the input modes is immediate, so update the movement vector moveCamera(); } } //saveFrameInfo(evt.timeSinceLastFrame); if (mAppState == AS_RECORD) { // update stats ++ mDemoStats.mTotalNumFrames; mDemoStats.mTotalEllapsedTime += evt.timeSinceLastFrame; // set time display int m = (int)mDemoStats.mTotalEllapsedTime / 60; int s = (int)mDemoStats.mTotalEllapsedTime % 60; mDemoTime->setCaption( StringConverter::toString(m, 2, '0') + ":" + StringConverter::toString(s, 2, '0')); // set FPS display const RenderTarget::FrameStats& stats = mWindow->getStatistics(); mDemoFPSDisp->setCaption(StringConverter::toString((int)stats.lastFPS)); // store frame mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), evt.timeSinceLastFrame)); } //Camera *followCam = mSceneMgr->getCamera("FollowCam"); //if (followCam->getAutoTrackTarget() != 0) //{ // // Move the death thingy & update lookat camera FOV // SceneNode *deathPivotNode = mSceneMgr->getSceneNode("deathPivotNode"); // SceneNode *deathNode = mSceneMgr->getSceneNode("movingNode"); // SceneNode *pivotNode = mSceneMgr->getSceneNode("pivotNode"); // Vector3 fcpos = followCam->getPosition(); // Vector3 oldpos = deathNode->getWorldPosition(); // Radian deltaAngle = Radian(evt.timeSinceLastFrame / mRotationPeriod * Math::TWO_PI); // deathPivotNode->rotate(Vector3::UNIT_Y, deltaAngle); // pivotNode->rotate(Vector3::UNIT_Y, deltaAngle * 4); // Vector3 pos = deathNode->getWorldPosition(); // Real olddist = (oldpos - fcpos).length(); // Real dist = (pos - fcpos).length(); // Radian oldfov = followCam->getFOVy(); // Radian fov = Radian(olddist / dist) * oldfov; // followCam->setFOVy(fov); //} return true; } bool KdTreeAppListener::frameEnded(const FrameEvent& evt) { if (!mOptions.mDemoMode) updateStats(); return true; } void KdTreeAppListener::switchMouseMode() { mUseBufferedInputMouse = !mUseBufferedInputMouse; mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse); } void KdTreeAppListener::switchKeyMode() { mUseBufferedInputKeys = !mUseBufferedInputKeys; mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse); } void KdTreeAppListener::keyClicked(KeyEvent* e) { if (e->getKeyChar() == 'm') { switchMouseMode(); } else if (e->getKeyChar() == 'k') { switchKeyMode(); } } /************************************************************************/ /* functions for recording & playback of demos */ /************************************************************************/ //----------------------------------------------------------------------------- void KdTreeAppListener::toggleRecord() { // start recording if (mAppState == AS_NORMAL) { // change state mAppState = AS_RECORD; // clear old recording mFrameList.clear(); // reset stats mDemoStats.mNumFrames = 0; mDemoStats.mTotalNumFrames = 0; mDemoStats.mEllapsedTime = 0.0f; mDemoStats.mTotalEllapsedTime = 0.0f; } // stop recording else if (mAppState == AS_RECORD) { // change state mAppState = AS_NORMAL; } // update display setDemoOverlay(); } //----------------------------------------------------------------------------- void KdTreeAppListener::togglePlayback() { static Vector3 pos; static Quaternion or; // start playback if (mAppState == AS_NORMAL && !mFrameList.empty()) { // change state mAppState = AS_PLAYBACK; // save old position pos = mCamNode->getPosition(); or = mCamNode->getOrientation(); // reset demo mCurrFrame = mFrameList.begin(); mTimeRemaining = mCurrFrame->mElapsedTime; // reset stats mDemoStats.mNumFrames = 0; mDemoStats.mTotalNumFrames = 0; mDemoStats.mEllapsedTime = 0.0f; mDemoStats.mTotalEllapsedTime = 0.0f; mDemoFPS.clear(); } // stop playback else if (mAppState == AS_PLAYBACK) { // change state mAppState = AS_NORMAL; // restore old position mCamNode->setPosition(pos); mCamNode->setOrientation(or); } // update display setDemoOverlay(); } //----------------------------------------------------------------------------- void KdTreeAppListener::saveFrames(const String& filename, FrameList& framelist) { size_t dot = filename.find_last_of("."); String ext = filename.substr(dot + 1, filename.length()); if (ext == "txt") saveFramesAscii(filename, framelist); else if (ext == "bin") saveFramesBinary(filename, framelist); else OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames"); } //----------------------------------------------------------------------------- void KdTreeAppListener::saveFramesAscii(const String& filename, FrameList& framelist) { // open file std::ofstream dest(filename.c_str()); if (dest.is_open()) { FrameList::iterator it = framelist.begin(); FrameList::iterator end = framelist.end(); // dump values while (it != end) { dest << StringConverter::toString(it->mPosition) << " " << StringConverter::toString(it->mOrientation) << " " << StringConverter::toString(it->mElapsedTime) << "\n"; ++ it; } dest.close(); } else { LogManager::getSingleton().logMessage("##Error##: Failed to open file for saving demo: " + filename); } } //----------------------------------------------------------------------------- void KdTreeAppListener::saveFramesBinary(const String& filename, FrameList& framelist) { std::ofstream dest(filename.c_str(), std::ios_base::out | std::ios_base::binary); if (dest.is_open()) { FrameList::iterator it = framelist.begin(); FrameList::iterator end = framelist.end(); int size = sizeof(Real); // dump values while (it != end) { dest.write((char *)&it->mPosition.x, size); dest.write((char *)&it->mPosition.y, size); dest.write((char *)&it->mPosition.z, size); dest.write((char *)&it->mOrientation.w, size); dest.write((char *)&it->mOrientation.x, size); dest.write((char *)&it->mOrientation.y, size); dest.write((char *)&it->mOrientation.z, size); dest.write((char *)&it->mElapsedTime, size); ++ it; } dest.close(); } else { LogManager::getSingleton().logMessage("##Error##: Failed to open file for saving demo: " + filename); } } //----------------------------------------------------------------------------- void KdTreeAppListener::loadFrames(const String& filename, FrameList& framelist) { size_t dot = filename.find_last_of("."); String ext = filename.substr(dot + 1, filename.length()); if (ext == "txt") loadFramesAscii(filename, framelist); else if (ext == "bin") loadFramesBinary(filename, framelist); else OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid extension for demo file: " + ext, "KdTreeApp::loadFrames"); } //----------------------------------------------------------------------------- void KdTreeAppListener::loadFramesAscii(const String& filename, FrameList& framelist) { // open file std::ifstream src(filename.c_str()); if (src.is_open()) { // clear the list framelist.clear(); Vector3 pos; Quaternion or; Real time; while (!src.eof()) { src >> pos.x; src >> pos.y; src >> pos.z; src >> or.w; src >> or.x; src >> or.y; src >> or.z; src >> time; framelist.push_back(FrameInfo(pos, or, time)); } // HACK pop last frame, was doubled while reading framelist.pop_back(); src.close(); } else { LogManager::getSingleton().logMessage("##Error##: Failed to open file for reading demo: " + filename); } } //----------------------------------------------------------------------------- void KdTreeAppListener::loadFramesBinary(const String& filename, FrameList& framelist) { // open file std::ifstream src(filename.c_str(), std::ios_base::out | std::ios_base::binary); if (src.is_open()) { // clear the list framelist.clear(); int size = sizeof(Real); Vector3 pos; Quaternion or; Real time; while (!src.eof()) { src.read((char *)&pos.x, size); src.read((char *)&pos.y, size); src.read((char *)&pos.z, size); src.read((char *)&or.w, size); src.read((char *)&or.x, size); src.read((char *)&or.y, size); src.read((char *)&or.z, size); src.read((char *)&time, size); framelist.push_back(FrameInfo(pos, or, time)); } // HACK pop last frame, was doubled while reading framelist.pop_back(); src.close(); } else { LogManager::getSingleton().logMessage("##Error##: Failed to open file for reading demo: " + filename); } } //----------------------------------------------------------------------------- void KdTreeAppListener::saveLog() { // field separator and record separator static const String fs = ",", rs ="\n", ds = ":"; // stats Real minFPS = Math::POS_INFINITY, maxFPS = 0.0, avgFPS = 0.0; String line, storedname; String demopath, demoname; StringUtil::splitFilename(mOptions.mDemoInfileName, demoname, demopath); // check if logfile exists std::ifstream logread(mOptions.mDemoLogfileName.c_str()); if (logread.is_open()) { // read first line, shuold start with the name of the demo // if matches, OK, otherwise do something logread >> line; storedname = line.substr(0,line.find_first_of(',')); if (storedname != demoname) { LogManager::getSingleton().logMessage( "##Error##: Saved demo stats do not match the current demo: " + storedname + " != " + demoname); logread.close(); return; } } // otherwise write header else { std::ofstream logheader(mOptions.mDemoLogfileName.c_str()); if (logheader.is_open()) { // demo title logheader << demoname << fs; // seconds for (size_t i = 0; i < mDemoFPS.size(); i ++) { logheader << (i+1) << fs; } // minFPS, avgFPS, maxFPS, comment, record separator logheader << "\"min FPS\"" << fs << "\"avg FPS\"" << fs << "\"max FPS\"" << fs << "\"# Frames \"" << fs << "\"Total Time\"" << fs << "\"Comment\"" << rs; logheader.close(); } else { LogManager::getSingleton().logMessage( "##Error##: Failed to write log demo header to " + mOptions.mDemoLogfileName); return; } } // append current stats std::ofstream logwrite(mOptions.mDemoLogfileName.c_str(), std::ios_base::app); if (logwrite.is_open()) { // demo settings logwrite << "\"" << SCENEMANAGER[mOptions.mSceneManager]; if (mOptions.mSceneManager == SM_KDT || mOptions.mSceneManager == SM_KTE) { // info about enhanced visibility if internal rendering String senhvis; if (mOptions.mRenderMethod == KdTree::KDRM_INTERNAL) { if (mOptions.mEnhancedVisibility) senhvis = "E" + ds; else senhvis = "S" + ds; } logwrite << ds << RENDERMETHOD[mOptions.mRenderMethod] << ds << senhvis << mOptions.mMaxDepth << ds << mOptions.mKT << ds << mOptions.mKI << ds << BUILDMETHOD[mOptions.mBuildMethod]; } else if (mOptions.mSceneManager == SM_OCM && mOptions.mRenderMethod != KdTree::KDRM_INTERNAL) { logwrite << ds << RENDERMETHOD[CONV_OCM_TO_KDT_ALG(mOptions.mRenderMethod)]; } logwrite << "\"" << fs; // per second stats for (std::list::iterator it = mDemoFPS.begin(); it != mDemoFPS.end(); it ++) { if (*it < minFPS) minFPS = *it; if (*it > maxFPS) maxFPS = *it; //avgFPS += *it; logwrite << (int)(*it) << fs; } //avgFPS /= mDemoFPS.size(); avgFPS = mDemoStats.mTotalNumFrames / mDemoStats.mTotalEllapsedTime; // minFPS, avgFPS, maxFPS, comment, record separator logwrite << (int)minFPS << fs << (int)avgFPS << fs << (int)maxFPS << fs << mDemoStats.mTotalNumFrames << fs << mDemoStats.mTotalEllapsedTime << fs << "\"" << mOptions.mComment << "\"" << rs; logwrite.close(); } else { LogManager::getSingleton().logMessage( "##Error##: Failed to write demo log to " + mOptions.mDemoLogfileName); } } //----------------------------------------------------------------------------- void KdTreeAppListener::saveFrameInfo(Real elapsedTime) { mFrameList.push_back(FrameInfo(mCamNode->getPosition(), mCamNode->getOrientation(), elapsedTime)); } //----------------------------------------------------------------------------- void KdTreeAppListener::setDemoOverlay() { // init overlay if not present if (!mDemoOverlay || !mDemoStatus || !mDemoTime) { OGRE_DELETE(mDemoOverlay); OGRE_DELETE(mDemoStatus); OGRE_DELETE(mDemoTime); mDemoStatus = OverlayManager::getSingleton().createOverlayElement("Panel", "KdTree/DemoStatus"); mDemoStatus->setMetricsMode(GMM_PIXELS); mDemoStatus->setDimensions(32, 32); mDemoStatus->setLeft(64); mDemoTime = static_cast (OverlayManager::getSingleton().createOverlayElement("TextArea", "KdTree/DemoTime")); mDemoTime->setMetricsMode(GMM_PIXELS); mDemoTime->setTop(6); mDemoTime->setLeft(104); mDemoTime->setFontName("TrebuchetMSBold"); mDemoTime->setCharHeight(24.0); mDemoTime->setCaption("00:00"); mDemoFPSDisp = static_cast (OverlayManager::getSingleton().createOverlayElement("TextArea", "KdTree/DemoFPS")); mDemoFPSDisp->setMetricsMode(GMM_PIXELS); mDemoFPSDisp->setAlignment(TextAreaOverlayElement::Right); mDemoFPSDisp->setTop(6); mDemoFPSDisp->setLeft(48); mDemoFPSDisp->setFontName("TrebuchetMSBold"); mDemoFPSDisp->setCharHeight(24.0); mDemoFPSDisp->setCaption("0"); PanelOverlayElement *demoCont = static_cast (OverlayManager::getSingleton().createOverlayElement("Panel", "KdTree/DemoTimePanel")); demoCont->setMetricsMode(GMM_PIXELS); demoCont->setHorizontalAlignment(GHA_CENTER); demoCont->setVerticalAlignment(GVA_TOP); demoCont->setTop(5); demoCont->setLeft(-80); demoCont->setDimensions(160, 32); demoCont->addChild(mDemoFPSDisp); demoCont->addChild(mDemoStatus); demoCont->addChild(mDemoTime); //demoCont->setMaterialName("Core/StatsBlockCenter"); mDemoOverlay = OverlayManager::getSingleton().create("KdTree/DemoOverlay"); mDemoOverlay->setZOrder(500); //mDemoOverlay->add2D(static_cast(mDemoStatus)); mDemoOverlay->add2D(demoCont); } switch(mAppState) { case AS_NORMAL: mDemoOverlay->hide(); break; case AS_PLAYBACK: mDemoStatus->setMaterialName("KdTree/DemoPlayButton"); mDemoTime->setColourTop(ColourValue(0.5, 0.7, 0.5)); mDemoTime->setColourBottom(ColourValue(0.3, 0.5, 0.3)); mDemoFPSDisp->setColourTop(ColourValue(0.5, 0.7, 0.5)); mDemoFPSDisp->setColourBottom(ColourValue(0.3, 0.5, 0.3)); mDemoOverlay->show(); break; case AS_RECORD: mDemoStatus->setMaterialName("KdTree/DemoRecordButton"); mDemoTime->setColourTop(ColourValue(0.7, 0.5, 0.5)); mDemoTime->setColourBottom(ColourValue(0.5, 0.3, 0.3)); mDemoFPSDisp->setColourTop(ColourValue(0.7, 0.5, 0.5)); mDemoFPSDisp->setColourBottom(ColourValue(0.5, 0.3, 0.3)); mDemoOverlay->show(); break; default: break; } }