// Called before every render. void update(DWORD milli) { if(displayError) return; static DWORD time = 0; if(numSpheres > 0) { // Manually set the velocity of the user sphere. sphereData[0].m_velocity = Vector3(0); // left arrow if(keysDown[37] || keysDown['A']) sphereData[0].m_velocity += Vector3(-USER_SPHERE_SPEED, 0.0, 0.0); // right arrow if(keysDown[39] || keysDown['D']) sphereData[0].m_velocity += Vector3(USER_SPHERE_SPEED, 0.0, 0.0); // up arrow if(keysDown[38] || keysDown['W']) sphereData[0].m_velocity += Vector3(0.0f, 0.0, -USER_SPHERE_SPEED); // down arrow if(keysDown[40] || keysDown['S']) sphereData[0].m_velocity += Vector3(0.0f, 0.0, USER_SPHERE_SPEED); // page up if(keysDown[33] || keysDown['Q']) sphereData[0].m_velocity += Vector3(0.0f, USER_SPHERE_SPEED, 0); // page down if(keysDown[34] || keysDown['E']) sphereData[0].m_velocity += Vector3(0.0f, -USER_SPHERE_SPEED, 0.0); } // Rough second counter by adding up all the previous dt times. time += milli; if(time > 1000) { framesPerSecond = renderFrameCounter; // Average the physics frame counter. physicsPerSecond = 0.0f; for(int i = 0; i < numPhysicsThreads; i++) { physicsPerSecond += physicsFrames[i]; physicsFrames[i] = 0; } renderFrameCounter = 0; physicsPerSecond /= numPhysicsThreads; time -= 1000; } #if _USE_MT != 1 // If we are not using multi threads. Then we need to call the physics // function here, after we're done the user input and before the scene // is rendered. physicsThread(0); #endif }
void Engine::Engine::mainLoop() { m_Factory.test_createObjects(); btPairCachingGhostObject *pGhostObject = new btPairCachingGhostObject(); pGhostObject->activate(); btConvexShape *pShape = new btSphereShape(1.0f); m_pCharacterController = new btKinematicCharacterController(pGhostObject, pShape, 1.0f); //m_PhysicsSystem.world()->addCharacter(m_pCharacterController); // Define the updaterate for the game-logic const float update_fps = 64; auto update_dt = std::chrono::duration<double>(1 / update_fps); auto max_dt_seconds = std::chrono::duration<double>(0.2f); std::chrono::duration<double> accumulator = std::chrono::duration<double>::zero(); std::chrono::duration<double> delta = std::chrono::duration<double>::zero(); // Start the timer m_MainLoopTimer.update(); bool isRunning = true; std::thread physicsThread([this, &isRunning]() { Utils::Timer<double> timer; std::chrono::duration<double> delta = std::chrono::duration<double>::zero(); double acc = 0.0; while(isRunning) { timer.update(); acc += timer.getAvgDelta().count(); if(acc < 1.0 / 60.0) { std::this_thread::sleep_for(std::chrono::nanoseconds(static_cast<long>((1.0 / 60.0) * 1000000000.0))); continue; } acc = 0.0; m_PhysicsSystem.updateRigidBodies(); // Let bullet do it's own fixed timestamp updatePhysics(delta); } }); while(isRunning) { delta = m_MainLoopTimer.update(); accumulator += delta; if(accumulator > max_dt_seconds) accumulator = max_dt_seconds; // Update the physics as often as we have to while(accumulator > update_dt) accumulator -= update_dt; //updatePhysics(accumulator); //accumulator = std::chrono::duration<double>::zero(); // Generate interpolation value for the renderer const float alpha = static_cast<float>(accumulator / update_dt); // Draw the current frame isRunning = render(alpha); } physicsThread.join(); }
void Driver::drive(int argc, char* argv[]) { // Make sure that this function is called just once SIM_ASSERT_RUNS_JUST_ONCE(); // Before anything else, create the Time object T(); // Then, determine the runId (just datetime for now) std::string runId = SimUtilities::timestampToDatetimeString( T()->startTimestamp() ); // Then, initiliaze logging (before calling P() or S()) Logging::initialize(runId); // Initialize the State object in order to: // 1) Set the runId // 2) Avoid a race condition (between threads) // 3) Initialize the Param object S()->setRunId(runId); // Remove any excessive archived runs SimUtilities::removeExcessArchivedRuns(); // Generate the glut functions in a static context GlutFunctions functions = { []() { m_view->refresh(); }, [](int width, int height) { m_view->updateWindowSize(width, height); }, [](unsigned char key, int x, int y) { m_view->keyPress(key, x, y); }, [](int key, int x, int y) { m_view->specialKeyPress(key, x, y); }, [](int key, int x, int y) { m_view->specialKeyRelease(key, x, y); } }; // Initialize the model, view, and controller m_model = new Model(); m_view = new View(m_model, argc, argv, functions); m_controller = new Controller(m_model, m_view); // Initialize mouse algorithm values in the model and view m_model->getWorld()->setOptions( m_controller->getOptions() ); m_view->setMouseAlgorithmAndOptions( m_controller->getMouseAlgorithm(), m_controller->getOptions() ); // Initialize the tile text, now that the options have been set m_view->initTileGraphicText(); // Lastly, we need to populate the graphics buffers with maze information, // but only after we've initialized the tile graphic text m_view->getMazeGraphic()->draw(); // Start the physics loop std::thread physicsThread([]() { m_model->getWorld()->simulate(); }); // Start the solving loop std::thread solvingThread([]() { // If the maze is invalid, don't let the algo do anything if (!m_model->getMaze()->isValidMaze()) { return; } // Wait for the window to appear SimUtilities::sleep(Seconds(P()->glutInitDuration())); // Begin execution of the mouse algorithm m_controller->getMouseAlgorithm()->solve( m_model->getMaze()->getWidth(), m_model->getMaze()->getHeight(), m_model->getMaze()->isOfficialMaze(), DIRECTION_TO_CHAR.at(m_model->getMouse()->getCurrentDiscretizedRotation()), m_controller->getMouseInterface()); }); // Start the graphics loop glutMainLoop(); }
int OgreOculus::go(void) { // Create Root object root = new Ogre::Root("plugin.cfg", "ogre.cfg"); // OpenGL root->loadPlugin("RenderSystem_GL_d"); root->setRenderSystem(root->getRenderSystemByName("OpenGL Rendering Subsystem")); // Initialize Root root->initialise(false); // Initialize Oculus ovrHmd hmd; ovrHmdDesc hmdDesc; ovrGraphicsLuid luid; ovr_Initialize(nullptr); if(ovr_Create(&hmd, &luid) != ovrSuccess) exit(-1); hmdDesc = ovr_GetHmdDesc(hmd); if(ovr_ConfigureTracking(hmd, ovrTrackingCap_Orientation |ovrTrackingCap_MagYawCorrection |ovrTrackingCap_Position, 0) != ovrSuccess) exit(-2); // Turn off HUD ovr_SetInt(hmd, "PerfHudMode", ovrPerfHud_Off); // Create a window window = root->createRenderWindow("Ogre + Oculus = <3", hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2, false); // Create scene manager and cameras smgr = root->createSceneManager(Ogre::ST_GENERIC); // Load Ogre resource paths from config file Ogre::ConfigFile cf; cf.load("resources_d.cfg"); // Go through all sections & settings in the file and add resources Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); Ogre::String secName, typeName, archName; while (seci.hasMoreElements()) { secName = seci.peekNextKey(); Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName); } } // Set resources Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5); Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // Create the model itself via OgreModel.cpp createOgreModel(smgr); // Create camera createCamera(); // Set viewport and background color Ogre::Viewport* vp = window->addViewport(mCamera); vp->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); // Yellow // Set aspect ratio mCamera->setAspectRatio( Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight())); // Initialize glew if(glewInit() != GLEW_OK) exit(-3); // Get texture sizes ovrSizei texSizeL, texSizeR; texSizeL = ovr_GetFovTextureSize(hmd, ovrEye_Left, hmdDesc.DefaultEyeFov[left], 1); texSizeR = ovr_GetFovTextureSize(hmd, ovrEye_Right, hmdDesc.DefaultEyeFov[right], 1); // Calculate render buffer size ovrSizei bufferSize; bufferSize.w = texSizeL.w + texSizeR.w; bufferSize.h = max(texSizeL.h, texSizeR.h); // Create render texture set ovrSwapTextureSet* textureSet; if(ovr_CreateSwapTextureSetGL(hmd, GL_RGB, bufferSize.w, bufferSize.h, &textureSet) != ovrSuccess) exit(-4); // Create Ogre render texture Ogre::GLTextureManager* textureManager = static_cast<Ogre::GLTextureManager*>(Ogre::GLTextureManager::getSingletonPtr()); Ogre::TexturePtr rtt_texture(textureManager->createManual("RttTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, bufferSize.w, bufferSize.h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET)); Ogre::RenderTexture* rttEyes = rtt_texture->getBuffer(0, 0)->getRenderTarget(); Ogre::GLTexture* gltex = static_cast<Ogre::GLTexture*>(Ogre::GLTextureManager::getSingleton().getByName("RttTex").getPointer()); GLuint renderTextureID = gltex->getGLID(); // Put camera viewport on the ogre render texture Ogre::Viewport* vpts[nbEyes]; vpts[left]=rttEyes->addViewport(cams[left], 0, 0, 0, 0.5f); vpts[right]=rttEyes->addViewport(cams[right], 1, 0.5f, 0, 0.5f); vpts[left]->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); // Black background vpts[right]->setBackgroundColour(Ogre::ColourValue(34, 89, 0)); ovrTexture* mirrorTexture; if(ovr_CreateMirrorTextureGL(hmd, GL_RGB, hmdDesc.Resolution.w, hmdDesc.Resolution.h, &mirrorTexture) != ovrSuccess) exit(-5); Ogre::TexturePtr mirror_texture(textureManager->createManual("MirrorTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, hmdDesc.Resolution.w, hmdDesc.Resolution.h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET)); // Get GLIDs GLuint ogreMirrorTextureID = static_cast<Ogre::GLTexture*>(Ogre::GLTextureManager::getSingleton().getByName("MirrorTex").getPointer())->getGLID(); GLuint oculusMirrorTextureID = ((ovrGLTexture*)mirrorTexture)->OGL.TexId; // Create EyeRenderDesc ovrEyeRenderDesc EyeRenderDesc[nbEyes]; EyeRenderDesc[left] = ovr_GetRenderDesc(hmd, ovrEye_Left, hmdDesc.DefaultEyeFov[left]); EyeRenderDesc[right] = ovr_GetRenderDesc(hmd, ovrEye_Right, hmdDesc.DefaultEyeFov[right]); // Get offsets ovrVector3f offset[nbEyes]; offset[left]=EyeRenderDesc[left].HmdToEyeViewOffset; offset[right]=EyeRenderDesc[right].HmdToEyeViewOffset; // Compositor layer ovrLayerEyeFov layer; layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = 0; layer.ColorTexture[left] = textureSet; layer.ColorTexture[right] = textureSet; layer.Fov[left] = EyeRenderDesc[left].Fov; layer.Fov[right] = EyeRenderDesc[right].Fov; layer.Viewport[left] = OVR::Recti(0, 0, bufferSize.w/2, bufferSize.h); layer.Viewport[right] = OVR::Recti(bufferSize.w/2, 0, bufferSize.w/2, bufferSize.h); // Get projection matrices for(size_t eyeIndex(0); eyeIndex < ovrEye_Count; eyeIndex++) { // Get the projection matrix OVR::Matrix4f proj = ovrMatrix4f_Projection(EyeRenderDesc[eyeIndex].Fov, static_cast<float>(0.01f), 4000, true); // Convert it to Ogre matrix Ogre::Matrix4 OgreProj; for(size_t x(0); x < 4; x++) for(size_t y(0); y < 4; y++) OgreProj[x][y] = proj.M[x][y]; // Set the matrix cams[eyeIndex]->setCustomProjectionMatrix(true, OgreProj); } // Variables for render loop bool render(true); ovrFrameTiming hmdFrameTiming; ovrTrackingState ts; OVR::Posef pose; ovrLayerHeader* layers; // Create event listener for handling user input createEventListener(); //Run physics loop in a new thread std::map<Ogre::Entity*, Ogre::Vector3> positionRequests; std::map<Ogre::Entity*, std::string> animationRequests; std::map<Ogre::Entity*, std::vector<int>> rotationRequests; std::map<std::string, std::string> message; std::thread physicsThread(physicsLoop, smgr, &message, &positionRequests, &animationRequests, &rotationRequests); // Render loop while(render) { // Suspend physics loop and perform requested movement/rotations/animations if(positionRequests.size() > 0 || animationRequests.size() > 0 || rotationRequests.size() > 0){ message.insert(std::pair<std::string, std::string>("", "")); for(auto const &request : positionRequests) { Ogre::Vector3 pos = request.second; Ogre::SceneNode* sceneNode = request.first->getParentSceneNode(); sceneNode->setPosition(pos); } for(auto const &request : animationRequests) { request.first->getAnimationState(request.second)->addTime(0.1); } for(auto const &request : rotationRequests) { Ogre::SceneNode* sceneNode = request.first->getParentSceneNode(); sceneNode->roll(Ogre::Degree(request.second[0])); sceneNode->pitch(Ogre::Degree(request.second[1])); sceneNode->yaw(Ogre::Degree(request.second[2])); } positionRequests.clear(); animationRequests.clear(); rotationRequests.clear(); // Resume physics loop message.clear(); } // Update Ogre window Ogre::WindowEventUtilities::messagePump(); // Advance textureset index textureSet->CurrentIndex = (textureSet->CurrentIndex + 1) % textureSet->TextureCount; // Capture user input mKeyboard->capture(); mMouse->capture(); // Movement calculations mPlayerNode->translate(mDirection, Ogre::Node::TS_LOCAL); hmdFrameTiming = ovr_GetFrameTiming(hmd, 0); ts = ovr_GetTrackingState(hmd, hmdFrameTiming.DisplayMidpointSeconds); pose = ts.HeadPose.ThePose; ovr_CalcEyePoses(pose, offset, layer.RenderPose); oculusOrient = pose.Rotation; oculusPos = pose.Translation; mHeadNode->setOrientation(Ogre::Quaternion(oculusOrient.w, oculusOrient.x, oculusOrient.y, oculusOrient.z) * initialOculusOrientation.Inverse()); // Apply head tracking mHeadNode->setPosition(headPositionTrackingSensitivity * Ogre::Vector3(oculusPos.x, oculusPos.y,oculusPos.z)); // Update Ogre viewports root->_fireFrameRenderingQueued(); vpts[left]->update(); vpts[right]->update(); // Copy the rendered image to the Oculus Swap Texture glCopyImageSubData(renderTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, ((ovrGLTexture*)(&textureSet->Textures[textureSet->CurrentIndex]))->OGL.TexId, GL_TEXTURE_2D, 0, 0, 0, 0, bufferSize.w,bufferSize.h, 1); layers = &layer.Header; // Submit new frame to the Oculus and update window ovr_SubmitFrame(hmd, 0, nullptr, &layers, 1); window->update(); // Exit loop when window is closed if(window->isClosed()) render = false; } // Shud down Oculus ovr_Destroy(hmd); ovr_Shutdown(); // Delete Ogre root and return delete root; return EXIT_SUCCESS; }