void VAppBase::Execute(VAppImpl* pImpl) { // Early out in case one of the startup modules triggered a quit if (WantsToQuit()) return; if(pImpl == NULL) { hkvLog::FatalError("No implmentation found!"); return; } m_pAppImpl = pImpl; Vision::SetApplication(this); // On callback based platforms the remaining code of the execute function // is triggered via the corresponding platform specific functions if (IsCallbackBased()) return; AppInit(); { // Main application loop (non callback based platforms only) bool bRun = true; while (bRun) { bRun = AppRun(); } } AppDeInit(); }
//Update, render and display the scene bool VisionApp_cl::Run() { static bool bInsideGameLoop = false; // Make sure the game loop isn't executed recursively. In Windows builds, this could for example happen if a shown message box triggers // a repaint message. This case needs to be handled by the code calling the game loop. if(bInsideGameLoop) { // We can't report this error in a form that could trigger a message box, so reporting a warning and breaking the debugger is the best we can do. Vision::Error.Warning("VisionApp_cl::Run called recursively! This is usually caused by triggering a repaint from inside the game loop."); #if defined(HK_DEBUG) VDBGBREAK; #endif // Just skip the game loop - this may invoke weird behavior if the calling code expects the game loop to complete, but is better // than recursing return true; } bInsideGameLoop = true; //Update the scene m_iUpdateSceneTickCount = 1; // by default one simulation tick per loop if (m_spUpdateSceneController!=NULL) m_iUpdateSceneTickCount = m_spUpdateSceneController->GetUpdateTickCount(); for (int i=0;i<m_iUpdateSceneTickCount;i++) { OnUpdateScene(); if (i<m_iUpdateSceneTickCount-1) // the last one is performed after rendering { OnFinishScene(); UpdateTimer(); } } // update everything that has to be done once per loop rather than per simulation steps OnFrameUpdatePreRender(); Vision::Profiling.Update(); VASSERT_MSG(Vision::Renderer.GetRendererNode(0) != NULL, "No renderer node is set. This isn't supported anymore. Use a VSimpleRendererNode instead of registering the main context globally."); // If in debug build, perform a sanity check - no context registered with the main context should also be registered // with a renderer node! #ifdef HK_DEBUG_SLOW static bool bContextErrorShown = false; if (!bContextErrorShown) { int iContextCount = Vision::Contexts.GetContextCount(); for (int iContext = 0; iContext < iContextCount; iContext++) { for (int iRendererNode=0; iRendererNode<V_MAX_RENDERER_NODES; iRendererNode++) { IVRendererNode *pNode = Vision::Renderer.GetRendererNode(iRendererNode); VisRenderContext_cl* pContext = Vision::Contexts.GetContext(iContext); if (pNode != NULL && pNode->IsContextRegistered(Vision::Contexts.GetContext(iContext))) { Vision::Error.Warning("Context %s (%p) is registered globally AND in renderer node %s (%p). This may be intended, but it is most likely a porting issue introduced by porting from a pre-8.0 version of the Vision Engine.", pContext->GetName(), pContext, pNode->GetTypeId()->m_lpszClassName, pNode); bContextErrorShown = true; } } } } #endif { INSERT_PERF_MARKER_SCOPE("BeginRendering"); // Inform the renderer that we are now going to start rendering Vision::Renderer.BeginRendering(); Vision::Callbacks.BeginRendering.TriggerCallbacks(); } Vision::Renderer.SetCurrentRendererNode(NULL); VisRendererNodeDataObject_cl data(&Vision::Callbacks.OnRendererNodeSwitching, NULL); Vision::Callbacks.OnRendererNodeSwitching.TriggerCallbacks(&data); { INSERT_PERF_MARKER_SCOPE("PreRendererNodeContexts"); Vision::Contexts.PerformVisibilityTests(); Vision::Contexts.RenderContexts(-FLT_MAX, VIS_RENDERCONTEXTPRIORITY_SCENE); } { for (int iRendererNode=0; iRendererNode<V_MAX_RENDERER_NODES; iRendererNode++) { IVRendererNode *pNode = Vision::Renderer.GetRendererNode(iRendererNode); if (pNode != NULL && pNode->GetRenderingEnabled()) { char buffer[192]; sprintf(buffer, "RendererNode %d (%s)", iRendererNode, pNode->GetTypeId()->m_lpszClassName); INSERT_PERF_MARKER_SCOPE(buffer); VASSERT_MSG(pNode->IsInitialized(), "Renderer Node is registered and enabled, but not initialized"); pNode->Execute(); } } } { INSERT_PERF_MARKER_SCOPE("PostRendererNodeContexts"); Vision::Renderer.SetCurrentRendererNode(NULL); Vision::Contexts.RenderContexts(VIS_RENDERCONTEXTPRIORITY_SCENE, FLT_MAX); } { INSERT_PERF_MARKER_SCOPE("EndRendering"); // Tell the renderer that we have finished rendering Vision::Callbacks.EndRendering.TriggerCallbacks(); Vision::Renderer.EndRendering(); } //Finish the scene - the last tick is performed here if (m_iUpdateSceneTickCount>0) OnFinishScene(); // update everything that has to be done once per loop rather than per simulation steps OnFrameUpdatePostRender(); //Display the scene Vision::Callbacks.OnBeforeSwapBuffers.TriggerCallbacks(); #ifdef WIN32 if (m_bUpdateScreen) // only supported on win32 #endif Vision::Video.UpdateScreen(); if (m_iUpdateSceneTickCount>0) // same as for OnFinishScene UpdateTimer(); bInsideGameLoop = false; return !WantsToQuit(); }