/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2015 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef GHOUL_USE_DEVIL #include #endif //GHOUL_USE_DEVIL #ifdef GHOUL_USE_FREEIMAGE #include #endif // GHOUL_USE_FREEIMAGE #include #include #include #include // These are temporary ---abock #include #include // ABuffer defines #define ABUFFER_FRAMEBUFFER 0 #define ABUFFER_SINGLE_LINKED 1 #define ABUFFER_FIXED 2 #define ABUFFER_DYNAMIC 3 #ifdef __APPLE__ #define ABUFFER_IMPLEMENTATION ABUFFER_FRAMEBUFFER #else #define ABUFFER_IMPLEMENTATION ABUFFER_SINGLE_LINKED #endif namespace { const std::string _loggerCat = "RenderEngine"; } namespace openspace { const std::string RenderEngine::PerformanceMeasurementSharedData = "OpenSpacePerformanceMeasurementSharedData"; namespace luascriptfunctions { int changeToPlutoViewPoint(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 0) return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); OsEng.renderEngine()->changeViewPoint("Pluto"); return 0; } int changeToSunViewPoint(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 0) return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); OsEng.renderEngine()->changeViewPoint("Sun"); return 0; } /** * \ingroup LuaScripts * takeScreenshot(): * Save the rendering to an image file */ int takeScreenshot(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 0) return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); OsEng.renderEngine()->takeScreenshot(); return 0; } /** * \ingroup LuaScripts * visualizeABuffer(bool): * Toggle the visualization of the ABuffer */ int visualizeABuffer(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 1) return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); const int type = lua_type(L, -1); bool b = lua_toboolean(L, -1) != 0; OsEng.renderEngine()->toggleVisualizeABuffer(b); return 0; } /** * \ingroup LuaScripts * visualizeABuffer(bool): * Toggle the visualization of the ABuffer */ int showRenderInformation(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 1) return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); const int type = lua_type(L, -1); bool b = lua_toboolean(L, -1) != 0; OsEng.renderEngine()->toggleInfoText(b); return 0; } /** * \ingroup LuaScripts * visualizeABuffer(bool): * Toggle the visualization of the ABuffer */ int setPerformanceMeasurement(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 1) return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); bool b = lua_toboolean(L, -1) != 0; OsEng.renderEngine()->setPerformanceMeasurements(b); return 0; } /** * \ingroup LuaScripts * fadeIn(float): * start a global fadein over (float) seconds */ int fadeIn(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 1) return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); double t = luaL_checknumber(L, -1); OsEng.renderEngine()->startFading(1, t); return 0; } /** * \ingroup LuaScripts * fadeIn(float): * start a global fadeout over (float) seconds */ int fadeOut(lua_State* L) { int nArguments = lua_gettop(L); if (nArguments != 1) return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); double t = luaL_checknumber(L, -1); OsEng.renderEngine()->startFading(-1, t); return 0; } } // namespace luascriptfunctions RenderEngine::RenderEngine() : _mainCamera(nullptr) , _sceneGraph(nullptr) , _abuffer(nullptr) , _log(nullptr) , _showInfo(true) , _showScreenLog(true) , _takeScreenshot(false) , _doPerformanceMeasurements(false) , _performanceMemory(nullptr) , _visualizeABuffer(false) , _visualizer(nullptr) , _globalOpactity(1.f) , _fadeDuration(2.f) , _currentFadeTime(0.f) , _fadeDirection(0) { } RenderEngine::~RenderEngine() { if (_abuffer) delete _abuffer; _abuffer = nullptr; if (_sceneGraph) delete _sceneGraph; _sceneGraph = nullptr; delete _mainCamera; if (_visualizer) delete _visualizer; delete _performanceMemory; if (ghoul::SharedMemory::exists(PerformanceMeasurementSharedData)) ghoul::SharedMemory::remove(PerformanceMeasurementSharedData); } bool RenderEngine::initialize() { generateGlslConfig(); // init camera and set temporary position and scaling _mainCamera = new Camera(); _mainCamera->setScaling(glm::vec2(1.0, -8.0)); _mainCamera->setPosition(psc(0.f, 0.f, 1.499823f, 11.f)); OsEng.interactionHandler()->setCamera(_mainCamera); #ifdef GHOUL_USE_DEVIL ghoul::io::TextureReader::ref().addReader(new ghoul::io::impl::TextureReaderDevIL); #endif // GHOUL_USE_DEVIL #ifdef GHOUL_USE_FREEIMAGE ghoul::io::TextureReader::ref().addReader(new ghoul::io::impl::TextureReaderFreeImage); #endif // GHOUL_USE_FREEIMAGE ghoul::io::TextureReader::ref().addReader(new ghoul::io::impl::TextureReaderCMAP); #if ABUFFER_IMPLEMENTATION == ABUFFER_FRAMEBUFFER _abuffer = new ABufferFramebuffer(); #elif ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED _abuffer = new ABufferSingleLinked(); #elif ABUFFER_IMPLEMENTATION == ABUFFER_FIXED _abuffer = new ABufferFixed(); #elif ABUFFER_IMPLEMENTATION == ABUFFER_DYNAMIC _abuffer = new ABufferDynamic(); #endif return true; } bool RenderEngine::initializeGL() { // LDEBUG("RenderEngine::initializeGL()"); sgct::SGCTWindow* wPtr = sgct::Engine::instance()->getActiveWindowPtr(); // TODO: Fix the power scaled coordinates in such a way that these // values can be set to more realistic values // set the close clip plane and the far clip plane to extreme values while in // development sgct::Engine::instance()->setNearAndFarClippingPlanes(0.01f, 10000.0f); // sgct::Engine::instance()->setNearAndFarClippingPlanes(0.1f, 30.0f); // calculating the maximum field of view for the camera, used to // determine visibility of objects in the scene graph if (wPtr->isUsingFisheyeRendering()) { // fisheye mode, looking upwards to the "dome" glm::vec4 upDirection(0, 1, 0, 0); // get the tilt and rotate the view const float tilt = wPtr->getFisheyeTilt(); glm::mat4 tiltMatrix = glm::rotate(glm::mat4(1.0f), tilt, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::vec4 viewdir = tiltMatrix * upDirection; // set the tilted view and the FOV _mainCamera->setCameraDirection(glm::vec3(viewdir[0], viewdir[1], viewdir[2])); _mainCamera->setMaxFov(wPtr->getFisheyeFOV()); _mainCamera->setLookUpVector(glm::vec3(0.0, 1.0, 0.0)); } else { // get corner positions, calculating the forth to easily calculate center glm::vec3 corners[4]; corners[0] = wPtr->getCurrentViewport()->getViewPlaneCoords( sgct_core::Viewport::LowerLeft); corners[1] = wPtr->getCurrentViewport()->getViewPlaneCoords( sgct_core::Viewport::UpperLeft); corners[2] = wPtr->getCurrentViewport()->getViewPlaneCoords( sgct_core::Viewport::UpperRight); corners[3] = glm::vec3(corners[2][0], corners[0][1], corners[2][2]); const glm::vec3 center = (corners[0] + corners[1] + corners[2] + corners[3]) / 4.0f; //#if 0 // // @TODO Remove the ifdef when the next SGCT version is released that requests the // // getUserPtr to get a name parameter ---abock // // // set the eye position, useful during rendering // const glm::vec3 eyePosition // = sgct_core::ClusterManager::instance()->getUserPtr("")->getPos(); //#else // const glm::vec3 eyePosition // = sgct_core::ClusterManager::instance()->getUserPtr()->getPos(); //#endif const glm::vec3 eyePosition = sgct_core::ClusterManager::instance()->getDefaultUserPtr()->getPos(); // get viewdirection, stores the direction in the camera, used for culling const glm::vec3 viewdir = glm::normalize(eyePosition - center); _mainCamera->setCameraDirection(-viewdir); _mainCamera->setLookUpVector(glm::vec3(0.0, 1.0, 0.0)); // set the initial fov to be 0.0 which means everything will be culled float maxFov = 0.0f; // for each corner for (int i = 0; i < 4; ++i) { // calculate radians to corner glm::vec3 dir = glm::normalize(eyePosition - corners[i]); float radsbetween = acos(glm::dot(viewdir, dir)) / (glm::length(viewdir) * glm::length(dir)); // the angle to a corner is larger than the current maxima if (radsbetween > maxFov) { maxFov = radsbetween; } } _mainCamera->setMaxFov(maxFov); } _abuffer->initialize(); _log = new ScreenLog(); ghoul::logging::LogManager::ref().addLog(_log); _visualizer = new ABufferVisualizer(); // successful init return true; } void RenderEngine::preSynchronization(){ if (_mainCamera){ _mainCamera->preSynchronization(); } } void RenderEngine::postSynchronizationPreDraw() { //temporary fade funtionality if (_fadeDirection != 0){ if (_currentFadeTime > _fadeDuration){ _fadeDirection = 0; _globalOpactity = fminf(1.f, fmaxf(0.f, _globalOpactity)); } else{ if (_fadeDirection < 0){ _globalOpactity = glm::smoothstep(1.f, 0.f, _currentFadeTime / _fadeDuration); } else{ _globalOpactity = glm::smoothstep(0.f, 1.f, _currentFadeTime / _fadeDuration); } _currentFadeTime += static_cast(sgct::Engine::instance()->getAvgDt()); } } if (_mainCamera){ _mainCamera->postSynchronizationPreDraw(); } sgct_core::SGCTNode * thisNode = sgct_core::ClusterManager::instance()->getThisNodePtr(); bool updateAbuffer = false; for (unsigned int i = 0; i < thisNode->getNumberOfWindows(); i++) { if (sgct::Engine::instance()->getWindowPtr(i)->isWindowResized()) { updateAbuffer = true; break; } } if (updateAbuffer) { generateGlslConfig(); _abuffer->reinitialize(); } // converts the quaternion used to rotation matrices _mainCamera->compileViewRotationMatrix(); UpdateData a = { Time::ref().currentTime(), Time::ref().deltaTime() }; // update and evaluate the scene starting from the root node _sceneGraph->update({ Time::ref().currentTime(), Time::ref().deltaTime(), _doPerformanceMeasurements }); _sceneGraph->evaluate(_mainCamera); // clear the abuffer before rendering the scene _abuffer->clear(); //Allow focus node to update camera (enables camera-following) //FIX LATER: THIS CAUSES MASTER NODE TO BE ONE FRAME AHEAD OF SLAVES //if (const SceneGraphNode* node = OsEng.ref().interactionHandler().focusNode()){ //node->updateCamera(_mainCamera); //} } void RenderEngine::render(const glm::mat4 &projectionMatrix, const glm::mat4 &viewMatrix) { // We need the window pointer sgct::SGCTWindow* w = sgct::Engine::instance()->getActiveWindowPtr(); if (w->isUsingFisheyeRendering()) _abuffer->clear(); // SGCT resets certain settings #ifndef __APPLE__ glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_BLEND); #else glEnable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_BLEND); #endif // setup the camera for the current frame _mainCamera->setViewMatrix( viewMatrix ); _mainCamera->setProjectionMatrix( projectionMatrix); //Is this really necessary to store? @JK _mainCamera->setViewProjectionMatrix(projectionMatrix * viewMatrix); // render the scene starting from the root node if (!_visualizeABuffer) { _abuffer->preRender(); _sceneGraph->render({ *_mainCamera, psc(), _doPerformanceMeasurements }); _abuffer->postRender(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); _abuffer->resolve(); glDisable(GL_BLEND); } else { _visualizer->render(); } #if 1 // Print some useful information on the master viewport if (OsEng.ref().isMaster() && !w->isUsingFisheyeRendering()) { // TODO: Adjust font_size properly when using retina screen const int font_size_mono = 10; const int font_size_light = 8; const int font_with_light = static_cast(font_size_light*0.7); const sgct_text::Font* fontLight = sgct_text::FontManager::instance()->getFont(constants::fonts::keyLight, font_size_light); const sgct_text::Font* fontMono = sgct_text::FontManager::instance()->getFont(constants::fonts::keyMono, font_size_mono); if (_showInfo) { const sgct_text::Font* font = fontMono; int x1, xSize, y1, ySize; sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); int startY = ySize - 2 * font_size_mono; const glm::vec2 scaling = _mainCamera->scaling(); const glm::vec3 viewdirection = _mainCamera->viewDirection(); const psc position = _mainCamera->position(); const psc origin = OsEng.interactionHandler()->focusNode()->worldPosition(); const PowerScaledScalar pssl = (position - origin).length(); // GUI PRINT // Using a macro to shorten line length and increase readability #define PrintText(i, format, ...) Freetype::print(font, 10.f, static_cast(startY - font_size_mono * i * 2), format, __VA_ARGS__); #define PrintColorText(i, format, size, color, ...) Freetype::print(font, size, static_cast(startY - font_size_mono * i * 2), color, format, __VA_ARGS__); int i = 0; PrintText(i++, "Date: %s", Time::ref().currentTimeUTC().c_str()); PrintText(i++, "Avg. Frametime: %.5f", sgct::Engine::instance()->getAvgDt()); PrintText(i++, "Drawtime: %.5f", sgct::Engine::instance()->getDrawTime()); PrintText(i++, "Frametime: %.5f", sgct::Engine::instance()->getDt()); PrintText(i++, "Origin: (% .5f, % .5f, % .5f, % .5f)", origin[0], origin[1], origin[2], origin[3]); PrintText(i++, "Cam pos: (% .5f, % .5f, % .5f, % .5f)", position[0], position[1], position[2], position[3]); PrintText(i++, "View dir: (% .5f, % .5f, % .5f)", viewdirection[0], viewdirection[1], viewdirection[2]); PrintText(i++, "Cam->origin: (% .15f, % .4f)", pssl[0], pssl[1]); PrintText(i++, "Scaling: (% .5f, % .5f)", scaling[0], scaling[1]); double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - Time::ref().currentTime(); double t = 0.0; t = 1.f - remaining / openspace::ImageSequencer::ref().getIntervalLength(); std::string progress = "|"; int g = ((t)* 20) + 1; for (int i = 0; i < g; i++) progress.append("-"); progress.append(">"); for (int i = 0; i < 21 - g; i++) progress.append(" "); std::string str = ""; openspace::SpiceManager::ref().getDateFromET(openspace::ImageSequencer::ref().getNextCaptureTime(), str); progress.append("|"); if (remaining > 0){ glm::vec4 g1(0, t, 0, 1); glm::vec4 g2(1 - t); PrintColorText(i++, "Next projection in | %.0f seconds", 10, g1 + g2, remaining); PrintColorText(i++, "%s %.1f %%", 10, g1 + g2, progress.c_str(), t * 100); } glm::vec4 w(1); PrintColorText(i++, "Ucoming : %s", 10, w, str.c_str()); #undef PrintText } if (_showScreenLog) { const sgct_text::Font* font = fontLight; const int max = 10; const int category_length = 20; const int msg_length = 140; const float ttl = 15.f; const float fade = 5.f; auto entries = _log->last(max); const glm::vec4 white(0.9, 0.9, 0.9, 1); const glm::vec4 red(1, 0, 0, 1); const glm::vec4 yellow(1, 1, 0, 1); const glm::vec4 green(0, 1, 0, 1); const glm::vec4 blue(0, 0, 1, 1); size_t nr = 1; for (auto& it = entries.first; it != entries.second; ++it) { const ScreenLog::LogEntry* e = &(*it); const double t = sgct::Engine::instance()->getTime(); float diff = static_cast(t - e->timeStamp); // Since all log entries are ordered, once one is exceeding TTL, all have if (diff > ttl) break; float alpha = 1; float ttf = ttl - fade; if (diff > ttf) { diff = diff - ttf; float p = 0.8f - diff / fade; alpha = (p <= 0.f) ? 0.f : pow(p, 0.3f); } // Since all log entries are ordered, once one exceeds alpha, all have if (alpha <= 0.0) break; const std::string lvl = "(" + ghoul::logging::LogManager::stringFromLevel(e->level) + ")"; const std::string& message = e->message.substr(0, msg_length); nr += std::count(message.begin(), message.end(), '\n'); Freetype::print(font, 10.f, static_cast(font_size_light * nr * 2), white*alpha, "%-14s %s%s", // Format e->timeString.c_str(), // Time string e->category.substr(0, category_length).c_str(), // Category string (up to category_length) e->category.length() > 20 ? "..." : ""); // Pad category with "..." if exceeds category_length glm::vec4 color = white; if (e->level == ghoul::logging::LogManager::LogLevel::Debug) color = green; if (e->level == ghoul::logging::LogManager::LogLevel::Warning) color = yellow; if (e->level == ghoul::logging::LogManager::LogLevel::Error) color = red; if (e->level == ghoul::logging::LogManager::LogLevel::Fatal) color = blue; Freetype::print(font, static_cast(10 + 39 * font_with_light), static_cast(font_size_light * nr * 2), color*alpha, "%s", lvl.c_str()); Freetype::print(font, static_cast(10 + 53 * font_with_light), static_cast(font_size_light * nr * 2), white*alpha, "%s", message.c_str()); ++nr; } } } #endif } void RenderEngine::postDraw() { if (_takeScreenshot) { sgct::Engine::instance()->takeScreenshot(); _takeScreenshot = false; } if (_doPerformanceMeasurements) storePerformanceMeasurements(); } void RenderEngine::takeScreenshot() { _takeScreenshot = true; } void RenderEngine::toggleVisualizeABuffer(bool b) { _visualizeABuffer = b; if (!_visualizeABuffer) return; std::vector _d = _abuffer->pixelData(); _visualizer->updateData(_d); } void RenderEngine::toggleInfoText(bool b) { _showInfo = b; } SceneGraph* RenderEngine::sceneGraph() { // TODO custom assert (ticket #5) assert(_sceneGraph); return _sceneGraph; } void RenderEngine::setSceneGraph(SceneGraph* sceneGraph) { _sceneGraph = sceneGraph; } void RenderEngine::serialize(SyncBuffer* syncBuffer) { if (_mainCamera){ _mainCamera->serialize(syncBuffer); } } void RenderEngine::deserialize(SyncBuffer* syncBuffer) { if (_mainCamera){ _mainCamera->deserialize(syncBuffer); } } Camera* RenderEngine::camera() const { return _mainCamera; } ABuffer* RenderEngine::abuffer() const { return _abuffer; } float RenderEngine::globalOpacity(){ return _globalOpactity; } void RenderEngine::setGlobalOpacity(float opacity){ _globalOpactity = opacity; } void RenderEngine::startFading(int direction, float fadeDuration){ _fadeDirection = direction; _fadeDuration = fadeDuration; _currentFadeTime = 0.f; } void RenderEngine::generateGlslConfig() { LDEBUG("Generating GLSLS config, expect shader recompilation"); int xSize = sgct::Engine::instance()->getActiveWindowPtr()->getXFramebufferResolution();; int ySize = sgct::Engine::instance()->getActiveWindowPtr()->getYFramebufferResolution();; // TODO: Make this file creation dynamic and better in every way // TODO: If the screen size changes it is enough if this file is regenerated to // recompile all necessary files std::ofstream os(absPath("${SHADERS_GENERATED}/constants.hglsl")); os << "#ifndef CONSTANTS_HGLSL\n" << "#define CONSTANTS_HGLSL\n" << "#define SCREEN_WIDTH " << xSize << "\n" << "#define SCREEN_HEIGHT " << ySize << "\n" << "#define MAX_LAYERS " << ABuffer::MAX_LAYERS << "\n" << "#define ABUFFER_FRAMEBUFFER " << ABUFFER_FRAMEBUFFER << "\n" << "#define ABUFFER_SINGLE_LINKED " << ABUFFER_SINGLE_LINKED << "\n" << "#define ABUFFER_FIXED " << ABUFFER_FIXED << "\n" << "#define ABUFFER_DYNAMIC " << ABUFFER_DYNAMIC << "\n" << "#define ABUFFER_IMPLEMENTATION " << ABUFFER_IMPLEMENTATION << "\n"; // System specific #ifdef WIN32 os << "#define WIN32\n"; #endif #ifdef __APPLE__ os << "#define APPLE\n"; #endif #ifdef __linux__ os << "#define linux\n"; #endif os << "#endif\n"; os.close(); } scripting::ScriptEngine::LuaLibrary RenderEngine::luaLibrary() { return{ "", { { "takeScreenshot", &luascriptfunctions::takeScreenshot, "", "Renders the current image to a file on disk" }, { "visualizeABuffer", &luascriptfunctions::visualizeABuffer, "bool", "Toggles the visualization of the ABuffer" }, { "showRenderInformation", &luascriptfunctions::showRenderInformation, "bool", "Toggles the showing of render information on-screen text" }, { "setPerformanceMeasurement", &luascriptfunctions::setPerformanceMeasurement, "bool", "Sets the performance measurements" }, // These are temporary ---abock { "changeViewPointToPluto", &luascriptfunctions::changeToPlutoViewPoint, "", "" }, { "changeViewPointToSun", &luascriptfunctions::changeToSunViewPoint, "", "" }, //also temporary @JK { "fadeIn", &luascriptfunctions::fadeIn, "number", "" }, //also temporary @JK { "fadeOut", &luascriptfunctions::fadeOut, "number", "" }, }, }; } void RenderEngine::setPerformanceMeasurements(bool performanceMeasurements) { _doPerformanceMeasurements = performanceMeasurements; } bool RenderEngine::doesPerformanceMeasurements() const { return _doPerformanceMeasurements; } void RenderEngine::storePerformanceMeasurements() { const int8_t Version = 0; const int nValues = 250; const int lengthName = 256; const int maxValues = 50; struct PerformanceLayout { int8_t version; int32_t nValuesPerEntry; int32_t nEntries; int32_t maxNameLength; int32_t maxEntries; struct PerformanceLayoutEntry { char name[lengthName]; float renderTime[nValues]; float updateRenderable[nValues]; float updateEphemeris[nValues]; int32_t currentRenderTime; int32_t currentUpdateRenderable; int32_t currentUpdateEphemeris; }; PerformanceLayoutEntry entries[maxValues]; }; const int nNodes = static_cast(sceneGraph()->allSceneGraphNodes().size()); if (!_performanceMemory) { // Compute the total size const int totalSize = sizeof(int8_t) + 4 * sizeof(int32_t) + maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry); LINFO("Create shared memory of " << totalSize << " bytes"); ghoul::SharedMemory::create(PerformanceMeasurementSharedData, totalSize); _performanceMemory = new ghoul::SharedMemory(PerformanceMeasurementSharedData); PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); layout->version = Version; layout->nValuesPerEntry = nValues; layout->nEntries = nNodes; layout->maxNameLength = lengthName; layout->maxEntries = maxValues; memset(layout->entries, 0, maxValues * sizeof(PerformanceLayout::PerformanceLayoutEntry)); for (int i = 0; i < nNodes; ++i) { SceneGraphNode* node = sceneGraph()->allSceneGraphNodes()[i]; memset(layout->entries[i].name, 0, lengthName); strcpy(layout->entries[i].name, node->name().c_str()); layout->entries[i].currentRenderTime = 0; layout->entries[i].currentUpdateRenderable = 0; layout->entries[i].currentUpdateEphemeris = 0; } } PerformanceLayout* layout = reinterpret_cast(_performanceMemory->pointer()); _performanceMemory->acquireLock(); for (int i = 0; i < nNodes; ++i) { SceneGraphNode* node = sceneGraph()->allSceneGraphNodes()[i]; SceneGraphNode::PerformanceRecord r = node->performanceRecord(); PerformanceLayout::PerformanceLayoutEntry& entry = layout->entries[i]; entry.renderTime[entry.currentRenderTime] = r.renderTime / 1000.f; entry.updateEphemeris[entry.currentUpdateEphemeris] = r.updateTimeEphemeris / 1000.f; entry.updateRenderable[entry.currentUpdateRenderable] = r.updateTimeRenderable / 1000.f; entry.currentRenderTime = (entry.currentRenderTime + 1) % nValues; entry.currentUpdateEphemeris = (entry.currentUpdateEphemeris + 1) % nValues; entry.currentUpdateRenderable = (entry.currentUpdateRenderable + 1) % nValues; } _performanceMemory->releaseLock(); } // This method is temporary and will be removed once the scalegraph is in effect ---abock void RenderEngine::changeViewPoint(std::string origin) { SceneGraphNode* solarSystemBarycenterNode = sceneGraph()->sceneGraphNode("SolarSystemBarycenter"); SceneGraphNode* plutoBarycenterNode = sceneGraph()->sceneGraphNode("PlutoBarycenter"); if (origin == "Pluto") { ghoul::Dictionary solarDictionary = { { std::string("Type"), std::string("Spice") }, { std::string("Body") , std::string("PLUTO BARYCENTER") }, { std::string("Reference"), std::string("ECLIPJ2000") }, { std::string("Observer") , std::string("SUN") }, { std::string("Kernels") , ghoul::Dictionary() } }; ghoul::Dictionary t; t.setValue("Position", glm::vec4(1.f, 0.f, 0.f, 12.f)); solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary)); plutoBarycenterNode->setEphemeris(new StaticEphemeris); return; } if (origin == "Sun") { ghoul::Dictionary plutoDictionary = { { std::string("Type"), std::string("Spice") }, { std::string("Body"), std::string("PLUTO BARYCENTER") }, { std::string("Reference"), std::string("ECLIPJ2000") }, { std::string("Observer"), std::string("SUN") }, { std::string("Kernels"), ghoul::Dictionary() } }; solarSystemBarycenterNode->setEphemeris(new StaticEphemeris); plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary)); return; } ghoul_assert(false, "??"); } }// namespace openspace