mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-08 20:50:19 -06:00
1460 lines
51 KiB
C++
1460 lines
51 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2017 *
|
|
* *
|
|
* 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 <openspace/rendering/renderengine.h>
|
|
|
|
#ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED
|
|
#include <modules/newhorizons/util/imagesequencer.h>
|
|
#endif
|
|
#include <openspace/util/syncdata.h>
|
|
|
|
#include <openspace/engine/configurationmanager.h>
|
|
#include <openspace/engine/openspaceengine.h>
|
|
#include <openspace/engine/wrapper/windowwrapper.h>
|
|
#include <openspace/interaction/navigationhandler.h>
|
|
#include <openspace/interaction/luaconsole.h>
|
|
#include <openspace/mission/missionmanager.h>
|
|
#include <openspace/performance/performancemanager.h>
|
|
#include <openspace/rendering/abufferrenderer.h>
|
|
#include <openspace/rendering/framebufferrenderer.h>
|
|
#include <openspace/rendering/deferredcastermanager.h>
|
|
#include <openspace/rendering/raycastermanager.h>
|
|
#include <openspace/rendering/renderer.h>
|
|
#include <openspace/rendering/screenspacerenderable.h>
|
|
#include <openspace/scene/scene.h>
|
|
#include <openspace/scripting/scriptengine.h>
|
|
#include <openspace/util/camera.h>
|
|
#include <openspace/util/time.h>
|
|
#include <openspace/util/timemanager.h>
|
|
#include <openspace/util/screenlog.h>
|
|
#include <openspace/util/spicemanager.h>
|
|
|
|
#include <ghoul/glm.h>
|
|
#include <ghoul/font/font.h>
|
|
#include <ghoul/font/fontmanager.h>
|
|
#include <ghoul/font/fontrenderer.h>
|
|
#include <ghoul/io/texture/texturereader.h>
|
|
#include <ghoul/io/texture/texturereadercmap.h>
|
|
#include <ghoul/opengl/programobject.h>
|
|
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
|
|
|
|
#ifdef GHOUL_USE_DEVIL
|
|
#include <ghoul/io/texture/texturereaderdevil.h>
|
|
#endif //GHOUL_USE_DEVIL
|
|
#ifdef GHOUL_USE_FREEIMAGE
|
|
#include <ghoul/io/texture/texturereaderfreeimage.h>
|
|
#endif // GHOUL_USE_FREEIMAGE
|
|
|
|
#ifdef GHOUL_USE_SOIL
|
|
#include <ghoul/io/texture/texturereadersoil.h>
|
|
#include <ghoul/io/texture/texturewriter.h>
|
|
#include <ghoul/io/texture/texturewritersoil.h>
|
|
#endif //GHOUL_USE_SOIL
|
|
|
|
#include <array>
|
|
#include <stack>
|
|
|
|
// ABuffer defines
|
|
#define RENDERER_FRAMEBUFFER 0
|
|
#define RENDERER_ABUFFER 1
|
|
|
|
#include "renderengine_lua.inl"
|
|
|
|
namespace {
|
|
const char* _loggerCat = "RenderEngine";
|
|
|
|
const char* KeyRenderingMethod = "RenderingMethod";
|
|
const std::chrono::seconds ScreenLogTimeToLive(15);
|
|
const char* DefaultRenderingMethod = "ABuffer";
|
|
const char* RenderFsPath = "${SHADERS}/render.frag";
|
|
|
|
const char* KeyFontMono = "Mono";
|
|
const char* KeyFontLight = "Light";
|
|
|
|
static const openspace::properties::Property::PropertyInfo PerformanceInfo = {
|
|
"PerformanceMeasurements",
|
|
"Performance Measurements",
|
|
"If this value is enabled, detailed performance measurements about the updates "
|
|
"and rendering of the scene graph nodes are collected each frame. These values "
|
|
"provide some information about the impact of individual nodes on the overall "
|
|
"performance."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo FrametimeInfo = {
|
|
"FrametimeType",
|
|
"Type of the frame time display",
|
|
"This value determines the units in which the frame time is displayed."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo ShowDateInfo = {
|
|
"ShowDate",
|
|
"Show Date Information",
|
|
"This values determines whether the date will be printed in the top left corner "
|
|
"of the rendering window if a regular rendering window is used (as opposed to a "
|
|
"fisheye rendering, for example)."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo ShowInfoInfo = {
|
|
"ShowInfo",
|
|
"Show Rendering Information",
|
|
"This value determines whether the rendering info, which is the delta time and "
|
|
"the frame time, is shown in the top left corner of the rendering window if a "
|
|
"regular rendering window is used (as opposed to a fisheye rendering, for "
|
|
"example)."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo ShowLogInfo = {
|
|
"ShowLog",
|
|
"Show the on-screen log",
|
|
"This value determines whether the on-screen log will be shown or hidden. Even "
|
|
"if it is shown, all 'Debug' and 'Trace' level messages are omitted from this "
|
|
"log."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo TakeScreenshotInfo = {
|
|
"TakeScreenshot",
|
|
"Take Screenshot",
|
|
"If this property is triggered, a screenshot is taken and stored in the current "
|
|
"working directory (which is the same directory where the OpenSpace.exe) is "
|
|
"located in most cases. The images are prefixed with 'SGCT' and postfixed with "
|
|
"the number of frames. This function will silently overwrite images that are "
|
|
"already present in the folder."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo ApplyWarpingInfo = {
|
|
"ApplyWarpingScreenshot",
|
|
"Apply Warping to Screenshots",
|
|
"This value determines whether a warping should be applied before taking a "
|
|
"screenshot. If it is enabled, all post processing is applied as well, which "
|
|
"includes everything rendered on top of the rendering, such as the user "
|
|
"interface."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo ShowFrameNumberInfo = {
|
|
"ShowFrameNumber",
|
|
"Show Frame Number",
|
|
"If this value is enabled, the current frame number is rendered into the window."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo DisableMasterInfo = {
|
|
"DisableMasterRendering",
|
|
"Disable Master Rendering",
|
|
"If this value is enabled, the rendering on the master node will be disabled. "
|
|
"Every other aspect of the application will be unaffected by this and it will "
|
|
"still respond to user input. This setting is reasonably only useful in the case "
|
|
"of multi-pipeline environments, such as planetariums, where the output of the "
|
|
"master node is not required and performance can be gained by disabling it."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo DisableTranslationInfo = {
|
|
"DisableSceneTranslationOnMaster",
|
|
"Disable Scene Translation on Master",
|
|
"If this value is enabled, any scene translations such as specified in, for "
|
|
"example an SGCT configuration, is disabled for the master node. This setting "
|
|
"can be useful if a planetarium environment requires a scene translation to be "
|
|
"applied, which would otherwise make interacting through the master node "
|
|
"difficult."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo AaSamplesInfo = {
|
|
"AaSamples",
|
|
"Number of Anti-aliasing samples",
|
|
"This value determines the number of anti-aliasing samples to be used in the "
|
|
"rendering for the MSAA method."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo HDRExposureInfo = {
|
|
"HDRExposure",
|
|
"HDR Exposure",
|
|
"This value determines the amount of light per unit area reaching the "
|
|
"equivalent of an electronic image sensor."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo BackgroundExposureInfo = {
|
|
"Background Exposure",
|
|
"BackgroundExposure",
|
|
"This value determines the amount of light per unit area reaching the "
|
|
"equivalent of an electronic image sensor for the background image."
|
|
};
|
|
|
|
static const openspace::properties::Property::PropertyInfo GammaInfo = {
|
|
"Gamma",
|
|
"Gamma Correction",
|
|
"Gamma, is the nonlinear operation used to encode and decode luminance or tristimulus values in the image."
|
|
};
|
|
} // namespace
|
|
|
|
|
|
namespace openspace {
|
|
|
|
RenderEngine::RenderEngine()
|
|
: properties::PropertyOwner("RenderEngine")
|
|
, _camera(nullptr)
|
|
, _scene(nullptr)
|
|
, _raycasterManager(nullptr)
|
|
, _deferredcasterManager(nullptr)
|
|
, _performanceMeasurements(PerformanceInfo)
|
|
, _performanceManager(nullptr)
|
|
, _renderer(nullptr)
|
|
, _rendererImplementation(RendererImplementation::Invalid)
|
|
, _log(nullptr)
|
|
, _frametimeType(FrametimeInfo, properties::OptionProperty::DisplayType::Dropdown)
|
|
, _showDate(ShowDateInfo, true)
|
|
, _showInfo(ShowInfoInfo, true)
|
|
, _showLog(ShowLogInfo, true)
|
|
, _takeScreenshot(TakeScreenshotInfo)
|
|
, _shouldTakeScreenshot(false)
|
|
, _applyWarping(ApplyWarpingInfo, false)
|
|
, _showFrameNumber(ShowFrameNumberInfo, false)
|
|
, _disableMasterRendering(DisableMasterInfo, false)
|
|
, _disableSceneTranslationOnMaster(DisableTranslationInfo, false)
|
|
, _globalBlackOutFactor(1.f)
|
|
, _fadeDuration(2.f)
|
|
, _currentFadeTime(0.f)
|
|
, _fadeDirection(0)
|
|
, _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f)
|
|
, _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f)
|
|
, _gamma(GammaInfo, 2.2f, 0.01f, 10.0f)
|
|
, _nAaSamples(AaSamplesInfo, 8, 1, 16)
|
|
, _frameNumber(0)
|
|
{
|
|
_performanceMeasurements.onChange([this]() {
|
|
if (_performanceMeasurements) {
|
|
if (!_performanceManager) {
|
|
_performanceManager = std::make_unique<performance::PerformanceManager>();
|
|
const std::string KeyLogDir = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogDir;
|
|
const std::string KeyPrefix = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogPerformancePrefix;
|
|
if (OsEng.configurationManager().hasKeyAndValue<std::string>(KeyLogDir)) {
|
|
_performanceManager->logDir(OsEng.configurationManager().value<std::string>(KeyLogDir));
|
|
}
|
|
if (OsEng.configurationManager().hasKeyAndValue<std::string>(KeyPrefix)) {
|
|
_performanceManager->prefix(OsEng.configurationManager().value<std::string>(KeyPrefix));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
addProperty(_performanceMeasurements);
|
|
|
|
_frametimeType.addOption(
|
|
static_cast<int>(FrametimeType::DtTimeAvg),
|
|
"Average Deltatime"
|
|
);
|
|
_frametimeType.addOption(
|
|
static_cast<int>(FrametimeType::FPS),
|
|
"Frames per second"
|
|
);
|
|
_frametimeType.addOption(
|
|
static_cast<int>(FrametimeType::FPSAvg),
|
|
"Average frames per second"
|
|
);
|
|
addProperty(_frametimeType);
|
|
|
|
addProperty(_showDate);
|
|
addProperty(_showInfo);
|
|
addProperty(_showLog);
|
|
|
|
_nAaSamples.onChange([this](){
|
|
if (_renderer) {
|
|
_renderer->setNAaSamples(_nAaSamples);
|
|
}
|
|
});
|
|
_hdrExposure.onChange([this]() {
|
|
if (_renderer) {
|
|
_renderer->setHDRExposure(_hdrExposure);
|
|
}
|
|
});
|
|
_hdrBackground.onChange([this]() {
|
|
if (_renderer) {
|
|
_renderer->setHDRBackground(_hdrBackground);
|
|
}
|
|
});
|
|
_gamma.onChange([this]() {
|
|
if (_renderer) {
|
|
_renderer->setGamma(_gamma);
|
|
}
|
|
});
|
|
|
|
addProperty(_nAaSamples);
|
|
addProperty(_hdrExposure);
|
|
addProperty(_hdrBackground);
|
|
addProperty(_gamma);
|
|
addProperty(_applyWarping);
|
|
|
|
_takeScreenshot.onChange([this](){
|
|
_shouldTakeScreenshot = true;
|
|
});
|
|
addProperty(_takeScreenshot);
|
|
|
|
addProperty(_showFrameNumber);
|
|
|
|
addProperty(_disableSceneTranslationOnMaster);
|
|
addProperty(_disableMasterRendering);
|
|
}
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
RenderEngine::~RenderEngine() {}
|
|
|
|
void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
|
|
_rendererImplementation = rendererFromString(renderingMethod);
|
|
|
|
std::unique_ptr<Renderer> newRenderer = nullptr;
|
|
switch (_rendererImplementation) {
|
|
case RendererImplementation::Framebuffer:
|
|
newRenderer = std::make_unique<FramebufferRenderer>();
|
|
break;
|
|
case RendererImplementation::ABuffer:
|
|
newRenderer = std::make_unique<ABufferRenderer>();
|
|
break;
|
|
case RendererImplementation::Invalid:
|
|
LFATAL("Rendering method '" << renderingMethod << "' not among the available "
|
|
<< "rendering methods");
|
|
}
|
|
|
|
setRenderer(std::move(newRenderer));
|
|
}
|
|
|
|
void RenderEngine::initialize() {
|
|
_frameNumber = 0;
|
|
std::string renderingMethod = DefaultRenderingMethod;
|
|
|
|
// If the user specified a rendering method that he would like to use, use that
|
|
auto& confManager = OsEng.configurationManager();
|
|
if (confManager.hasKeyAndValue<std::string>(KeyRenderingMethod)) {
|
|
renderingMethod = confManager.value<std::string>(KeyRenderingMethod);
|
|
}
|
|
else {
|
|
using Version = ghoul::systemcapabilities::Version;
|
|
|
|
// The default rendering method has a requirement of OpenGL 4.3, so if we are
|
|
// below that, we will fall back to frame buffer operation
|
|
if (OpenGLCap.openGLVersion() < Version{ 4,3,0 }) {
|
|
LINFO("Falling back to framebuffer implementation due to OpenGL limitations");
|
|
renderingMethod = "Framebuffer";
|
|
}
|
|
}
|
|
|
|
if (confManager.hasKey(ConfigurationManager::KeyDisableMasterRendering)) {
|
|
_disableMasterRendering = confManager.value<bool>(
|
|
ConfigurationManager::KeyDisableMasterRendering
|
|
);
|
|
}
|
|
|
|
if (confManager.hasKey(ConfigurationManager::KeyDisableSceneOnMaster)) {
|
|
_disableSceneTranslationOnMaster = confManager.value<bool>(
|
|
ConfigurationManager::KeyDisableSceneOnMaster
|
|
);
|
|
}
|
|
|
|
_raycasterManager = std::make_unique<RaycasterManager>();
|
|
_deferredcasterManager = std::make_unique<DeferredcasterManager>();
|
|
_nAaSamples = OsEng.windowWrapper().currentNumberOfAaSamples();
|
|
|
|
LINFO("Setting renderer from string: " << renderingMethod);
|
|
setRendererFromString(renderingMethod);
|
|
|
|
#ifdef GHOUL_USE_DEVIL
|
|
ghoul::io::TextureReader::ref().addReader(
|
|
std::make_shared<ghoul::io::TextureReaderDevIL>()
|
|
);
|
|
#endif // GHOUL_USE_DEVIL
|
|
#ifdef GHOUL_USE_FREEIMAGE
|
|
ghoul::io::TextureReader::ref().addReader(
|
|
std::make_shared<ghoul::io::TextureReaderFreeImage>()
|
|
);
|
|
#endif // GHOUL_USE_FREEIMAGE
|
|
#ifdef GHOUL_USE_SOIL
|
|
ghoul::io::TextureReader::ref().addReader(
|
|
std::make_shared<ghoul::io::TextureReaderSOIL>()
|
|
);
|
|
ghoul::io::TextureWriter::ref().addWriter(
|
|
std::make_shared<ghoul::io::TextureWriterSOIL>()
|
|
);
|
|
#endif // GHOUL_USE_SOIL
|
|
|
|
ghoul::io::TextureReader::ref().addReader(
|
|
std::make_shared<ghoul::io::TextureReaderCMAP>()
|
|
);
|
|
|
|
MissionManager::initialize();
|
|
}
|
|
|
|
void RenderEngine::initializeGL() {
|
|
LTRACE("RenderEngine::initializeGL(begin)");
|
|
// 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
|
|
OsEng.windowWrapper().setNearFarClippingPlane(0.001f, 1000.f);
|
|
|
|
try {
|
|
const float fontSizeBig = 50.f;
|
|
_fontBig = OsEng.fontManager().font(KeyFontMono, fontSizeBig);
|
|
const float fontSizeTime = 15.f;
|
|
_fontDate = OsEng.fontManager().font(KeyFontMono, fontSizeTime);
|
|
const float fontSizeMono = 10.f;
|
|
_fontInfo = OsEng.fontManager().font(KeyFontMono, fontSizeMono);
|
|
const float fontSizeLight = 8.f;
|
|
_fontLog = OsEng.fontManager().font(KeyFontLight, fontSizeLight);
|
|
} catch (const ghoul::fontrendering::Font::FreeTypeException& e) {
|
|
LERROR(e.what());
|
|
throw;
|
|
}
|
|
|
|
LINFO("Initializing Log");
|
|
std::unique_ptr<ScreenLog> log = std::make_unique<ScreenLog>(ScreenLogTimeToLive);
|
|
_log = log.get();
|
|
ghoul::logging::LogManager::ref().addLog(std::move(log));
|
|
|
|
LINFO("Finished initializing GL");
|
|
LTRACE("RenderEngine::initializeGL(end)");
|
|
}
|
|
|
|
void RenderEngine::deinitialize() {
|
|
for (std::shared_ptr<ScreenSpaceRenderable> ssr : _screenSpaceRenderables) {
|
|
ssr->deinitialize();
|
|
}
|
|
|
|
MissionManager::deinitialize();
|
|
}
|
|
|
|
void RenderEngine::updateScene() {
|
|
const Time& currentTime = OsEng.timeManager().time();
|
|
_scene->update({
|
|
{ glm::dvec3(0), glm::dmat3(1), 1.0 },
|
|
currentTime,
|
|
_performanceManager != nullptr
|
|
});
|
|
|
|
LTRACE("RenderEngine::updateSceneGraph(end)");
|
|
}
|
|
|
|
void RenderEngine::updateShaderPrograms() {
|
|
for (ghoul::opengl::ProgramObject* program : _programs) {
|
|
try {
|
|
if (program->isDirty()) {
|
|
program->rebuildFromFile();
|
|
}
|
|
}
|
|
catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) {
|
|
LERRORC(e.component, e.what());
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderEngine::updateRenderer() {
|
|
bool windowResized = OsEng.windowWrapper().windowHasResized();
|
|
|
|
if (windowResized) {
|
|
_renderer->setResolution(renderingResolution());
|
|
|
|
ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize(
|
|
fontResolution()
|
|
);
|
|
}
|
|
|
|
_renderer->update();
|
|
}
|
|
|
|
void RenderEngine::updateScreenSpaceRenderables() {
|
|
for (std::shared_ptr<ScreenSpaceRenderable>& ssr : _screenSpaceRenderables) {
|
|
ssr->update();
|
|
}
|
|
}
|
|
|
|
glm::ivec2 RenderEngine::renderingResolution() const {
|
|
if (OsEng.windowWrapper().isRegularRendering()) {
|
|
return OsEng.windowWrapper().currentWindowResolution();
|
|
}
|
|
else {
|
|
return OsEng.windowWrapper().currentDrawBufferResolution();
|
|
}
|
|
}
|
|
|
|
glm::ivec2 RenderEngine::fontResolution() const {
|
|
std::string value;
|
|
bool hasValue = OsEng.configurationManager().getValue(
|
|
ConfigurationManager::KeyOnScreenTextScaling,
|
|
value
|
|
);
|
|
if (hasValue && value == "framebuffer") {
|
|
return OsEng.windowWrapper().currentWindowResolution();
|
|
}
|
|
else {
|
|
// The default is to use the window size
|
|
return OsEng.windowWrapper().currentWindowSize();
|
|
}
|
|
}
|
|
|
|
void RenderEngine::updateFade() {
|
|
// Temporary fade funtionality
|
|
const float fadedIn = 1.0;
|
|
const float fadedOut = 0.0;
|
|
// Don't restart the fade if you've already done it in that direction
|
|
const bool isFadedIn = (_fadeDirection > 0 && _globalBlackOutFactor == fadedIn);
|
|
const bool isFadedOut = (_fadeDirection < 0 && _globalBlackOutFactor == fadedOut);
|
|
if (isFadedIn || isFadedOut) {
|
|
_fadeDirection = 0;
|
|
}
|
|
|
|
if (_fadeDirection != 0) {
|
|
if (_currentFadeTime > _fadeDuration) {
|
|
_globalBlackOutFactor = _fadeDirection > 0 ? fadedIn : fadedOut;
|
|
_fadeDirection = 0;
|
|
}
|
|
else {
|
|
if (_fadeDirection < 0) {
|
|
_globalBlackOutFactor = glm::smoothstep(
|
|
1.f,
|
|
0.f,
|
|
_currentFadeTime / _fadeDuration
|
|
);
|
|
}
|
|
else {
|
|
_globalBlackOutFactor = glm::smoothstep(
|
|
0.f,
|
|
1.f,
|
|
_currentFadeTime / _fadeDuration
|
|
);
|
|
}
|
|
_currentFadeTime += static_cast<float>(
|
|
OsEng.windowWrapper().averageDeltaTime()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,
|
|
const glm::mat4& projectionMatrix)
|
|
{
|
|
LTRACE("RenderEngine::render(begin)");
|
|
WindowWrapper& wrapper = OsEng.windowWrapper();
|
|
|
|
if (_disableSceneTranslationOnMaster && wrapper.isMaster()) {
|
|
_camera->sgctInternal.setViewMatrix(viewMatrix);
|
|
}
|
|
else {
|
|
_camera->sgctInternal.setViewMatrix(viewMatrix * sceneMatrix);
|
|
}
|
|
_camera->sgctInternal.setProjectionMatrix(projectionMatrix);
|
|
|
|
|
|
if (!(wrapper.isMaster() && _disableMasterRendering) && !wrapper.isGuiWindow()) {
|
|
_renderer->render(_globalBlackOutFactor, _performanceManager != nullptr);
|
|
}
|
|
|
|
// Print some useful information on the master viewport
|
|
if (wrapper.isMaster() && wrapper.isSimpleRendering()) {
|
|
renderInformation();
|
|
}
|
|
|
|
if (_showFrameNumber) {
|
|
const glm::vec2 penPosition = glm::vec2(
|
|
fontResolution().x / 2 - 50,
|
|
fontResolution().y / 3
|
|
);
|
|
|
|
RenderFont(*_fontBig, penPosition, "%i", _frameNumber);
|
|
}
|
|
|
|
_frameNumber++;
|
|
|
|
for (std::shared_ptr<ScreenSpaceRenderable>& ssr : _screenSpaceRenderables) {
|
|
if (ssr->isEnabled() && ssr->isReady()) {
|
|
ssr->render();
|
|
}
|
|
}
|
|
LTRACE("RenderEngine::render(end)");
|
|
}
|
|
|
|
void RenderEngine::renderShutdownInformation(float timer, float fullTime) {
|
|
timer = timer < 0.f ? 0.f : timer;
|
|
|
|
auto size = ghoul::fontrendering::FontRenderer::defaultRenderer().boundingBox(
|
|
*_fontDate,
|
|
"Shutdown in: %.2fs/%.2fs",
|
|
timer,
|
|
fullTime
|
|
);
|
|
|
|
glm::vec2 penPosition = glm::vec2(
|
|
fontResolution().x - size.boundingBox.x - 10,
|
|
fontResolution().y - size.boundingBox.y
|
|
);
|
|
penPosition.y -= _fontDate->height();
|
|
|
|
RenderFontCr(
|
|
*_fontDate,
|
|
penPosition,
|
|
"Shutdown in: %.2fs/%.2fs",
|
|
timer,
|
|
fullTime
|
|
);
|
|
}
|
|
|
|
void RenderEngine::postDraw() {
|
|
Time& currentTime = OsEng.timeManager().time();
|
|
if (currentTime.timeJumped()) {
|
|
currentTime.setTimeJumped(false);
|
|
}
|
|
|
|
if (_shouldTakeScreenshot) {
|
|
OsEng.windowWrapper().takeScreenshot(_applyWarping);
|
|
_shouldTakeScreenshot = false;
|
|
}
|
|
|
|
if (_performanceManager) {
|
|
_performanceManager->storeScenePerformanceMeasurements(
|
|
scene()->allSceneGraphNodes()
|
|
);
|
|
}
|
|
}
|
|
|
|
Scene* RenderEngine::scene() {
|
|
return _scene;
|
|
}
|
|
|
|
RaycasterManager& RenderEngine::raycasterManager() {
|
|
return *_raycasterManager;
|
|
}
|
|
|
|
DeferredcasterManager& RenderEngine::deferredcasterManager() {
|
|
return *_deferredcasterManager;
|
|
}
|
|
|
|
void RenderEngine::setScene(Scene* scene) {
|
|
_scene = scene;
|
|
if (_renderer) {
|
|
_renderer->setScene(scene);
|
|
}
|
|
}
|
|
|
|
void RenderEngine::setCamera(Camera* camera) {
|
|
_camera = camera;
|
|
if (_renderer) {
|
|
_renderer->setCamera(camera);
|
|
}
|
|
}
|
|
|
|
Camera* RenderEngine::camera() const {
|
|
return _camera;
|
|
}
|
|
|
|
Renderer* RenderEngine::renderer() const {
|
|
return _renderer.get();
|
|
}
|
|
|
|
RenderEngine::RendererImplementation RenderEngine::rendererImplementation() const {
|
|
return _rendererImplementation;
|
|
}
|
|
|
|
float RenderEngine::globalBlackOutFactor() {
|
|
return _globalBlackOutFactor;
|
|
}
|
|
|
|
void RenderEngine::setGlobalBlackOutFactor(float opacity) {
|
|
_globalBlackOutFactor = opacity;
|
|
}
|
|
|
|
void RenderEngine::startFading(int direction, float fadeDuration) {
|
|
_fadeDirection = direction;
|
|
_fadeDuration = fadeDuration;
|
|
_currentFadeTime = 0.f;
|
|
}
|
|
|
|
/**
|
|
* Build a program object for rendering with the used renderer
|
|
*/
|
|
std::unique_ptr<ghoul::opengl::ProgramObject> RenderEngine::buildRenderProgram(
|
|
std::string name, std::string vsPath,
|
|
std::string fsPath, const ghoul::Dictionary& data)
|
|
{
|
|
|
|
ghoul::Dictionary dict = data;
|
|
|
|
// set path to the current renderer's main fragment shader
|
|
dict.setValue("rendererData", _rendererData);
|
|
// parameterize the main fragment shader program with specific contents.
|
|
// fsPath should point to a shader file defining a Fragment getFragment() function
|
|
// instead of a void main() setting glFragColor, glFragDepth, etc.
|
|
dict.setValue("fragmentPath", fsPath);
|
|
|
|
using namespace ghoul::opengl;
|
|
std::unique_ptr<ProgramObject> program = ProgramObject::Build(
|
|
name,
|
|
vsPath,
|
|
RenderFsPath,
|
|
dict
|
|
);
|
|
|
|
if (program) {
|
|
_programs.push_back(program.get());
|
|
}
|
|
return program;
|
|
}
|
|
|
|
/**
|
|
* Build a program object for rendering with the used renderer
|
|
*/
|
|
std::unique_ptr<ghoul::opengl::ProgramObject> RenderEngine::buildRenderProgram(
|
|
std::string name, std::string vsPath,
|
|
std::string fsPath, std::string csPath,
|
|
const ghoul::Dictionary& data)
|
|
{
|
|
ghoul::Dictionary dict = data;
|
|
dict.setValue("rendererData", _rendererData);
|
|
|
|
// parameterize the main fragment shader program with specific contents.
|
|
// fsPath should point to a shader file defining a Fragment getFragment() function
|
|
// instead of a void main() setting glFragColor, glFragDepth, etc.
|
|
dict.setValue("fragmentPath", fsPath);
|
|
|
|
using namespace ghoul::opengl;
|
|
std::unique_ptr<ProgramObject> program = ProgramObject::Build(
|
|
name,
|
|
vsPath,
|
|
RenderFsPath,
|
|
csPath,
|
|
dict
|
|
);
|
|
|
|
if (program) {
|
|
_programs.push_back(program.get());
|
|
}
|
|
return program;
|
|
}
|
|
|
|
void RenderEngine::removeRenderProgram(
|
|
const std::unique_ptr<ghoul::opengl::ProgramObject>& program)
|
|
{
|
|
if (!program) {
|
|
return;
|
|
}
|
|
|
|
auto it = std::find(
|
|
_programs.begin(),
|
|
_programs.end(),
|
|
program.get()
|
|
);
|
|
|
|
if (it != _programs.end()) {
|
|
_programs.erase(it);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set renderer data
|
|
* Called from the renderer, whenever it needs to update
|
|
* the dictionary of all rendering programs.
|
|
*/
|
|
void RenderEngine::setRendererData(const ghoul::Dictionary& data) {
|
|
_rendererData = data;
|
|
for (ghoul::opengl::ProgramObject* program : _programs) {
|
|
ghoul::Dictionary dict = program->dictionary();
|
|
dict.setValue("rendererData", _rendererData);
|
|
program->setDictionary(dict);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Set resolve data
|
|
* Called from the renderer, whenever it needs to update
|
|
* the dictionary of all post rendering programs.
|
|
*/
|
|
void RenderEngine::setResolveData(const ghoul::Dictionary& data) {
|
|
_resolveData = data;
|
|
for (ghoul::opengl::ProgramObject* program : _programs) {
|
|
ghoul::Dictionary dict = program->dictionary();
|
|
dict.setValue("resolveData", _resolveData);
|
|
program->setDictionary(dict);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set raycasting uniforms on the program object, and setup raycasting.
|
|
*/
|
|
void RenderEngine::preRaycast(ghoul::opengl::ProgramObject& programObject) {
|
|
_renderer->preRaycast(programObject);
|
|
}
|
|
|
|
/**
|
|
* Tear down raycasting for the specified program object.
|
|
*/
|
|
void RenderEngine::postRaycast(ghoul::opengl::ProgramObject& programObject) {
|
|
_renderer->postRaycast(programObject);
|
|
}
|
|
|
|
/**
|
|
* Set renderer
|
|
*/
|
|
void RenderEngine::setRenderer(std::unique_ptr<Renderer> renderer) {
|
|
if (_renderer) {
|
|
_renderer->deinitialize();
|
|
}
|
|
|
|
_renderer = std::move(renderer);
|
|
_renderer->setResolution(renderingResolution());
|
|
_renderer->setNAaSamples(_nAaSamples);
|
|
_renderer->setHDRExposure(_hdrExposure);
|
|
_renderer->initialize();
|
|
_renderer->setCamera(_camera);
|
|
_renderer->setScene(_scene);
|
|
}
|
|
|
|
scripting::LuaLibrary RenderEngine::luaLibrary() {
|
|
return{
|
|
"",
|
|
{
|
|
{
|
|
"setRenderer",
|
|
&luascriptfunctions::setRenderer,
|
|
"string",
|
|
"Sets the renderer (ABuffer or FrameBuffer)"
|
|
},
|
|
{
|
|
"toggleFade",
|
|
&luascriptfunctions::toggleFade,
|
|
"number",
|
|
"Toggles fading in or out"
|
|
},
|
|
{
|
|
"fadeIn",
|
|
&luascriptfunctions::fadeIn,
|
|
"number",
|
|
""
|
|
},
|
|
//also temporary @JK
|
|
{
|
|
"fadeOut",
|
|
&luascriptfunctions::fadeOut,
|
|
"number",
|
|
""
|
|
},
|
|
{
|
|
"registerScreenSpaceRenderable",
|
|
&luascriptfunctions::registerScreenSpaceRenderable,
|
|
"table",
|
|
"Will create a ScreenSpaceRenderable from a lua Table and register it in the RenderEngine"
|
|
},
|
|
{
|
|
"unregisterScreenSpaceRenderable",
|
|
&luascriptfunctions::unregisterScreenSpaceRenderable,
|
|
"string",
|
|
"Given a ScreenSpaceRenderable name this script will remove it from the renderengine"
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
bool RenderEngine::doesPerformanceMeasurements() const {
|
|
return _performanceManager != nullptr;
|
|
}
|
|
|
|
performance::PerformanceManager* RenderEngine::performanceManager() {
|
|
return _performanceManager.get();
|
|
}
|
|
|
|
void RenderEngine::registerScreenSpaceRenderable(std::shared_ptr<ScreenSpaceRenderable> s)
|
|
{
|
|
s->initialize();
|
|
_screenSpaceRenderables.push_back(s);
|
|
}
|
|
|
|
void RenderEngine::unregisterScreenSpaceRenderable(
|
|
std::shared_ptr<ScreenSpaceRenderable> s)
|
|
{
|
|
auto it = std::find(
|
|
_screenSpaceRenderables.begin(),
|
|
_screenSpaceRenderables.end(),
|
|
s
|
|
);
|
|
|
|
if (it != _screenSpaceRenderables.end()) {
|
|
s->deinitialize();
|
|
_screenSpaceRenderables.erase(it);
|
|
}
|
|
}
|
|
|
|
void RenderEngine::unregisterScreenSpaceRenderable(std::string name) {
|
|
std::shared_ptr<ScreenSpaceRenderable> s = screenSpaceRenderable(name);
|
|
if (s) {
|
|
unregisterScreenSpaceRenderable(s);
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<ScreenSpaceRenderable> RenderEngine::screenSpaceRenderable(
|
|
std::string name)
|
|
{
|
|
for (auto s : _screenSpaceRenderables) {
|
|
if (s->name() == name) {
|
|
return s;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
std::vector<ScreenSpaceRenderable*> RenderEngine::screenSpaceRenderables() const {
|
|
std::vector<ScreenSpaceRenderable*> res(_screenSpaceRenderables.size());
|
|
std::transform(
|
|
_screenSpaceRenderables.begin(),
|
|
_screenSpaceRenderables.end(),
|
|
res.begin(),
|
|
[](std::shared_ptr<ScreenSpaceRenderable> p) { return p.get(); }
|
|
);
|
|
return res;
|
|
}
|
|
|
|
RenderEngine::RendererImplementation RenderEngine::rendererFromString(
|
|
const std::string& impl)
|
|
{
|
|
const std::map<std::string, RenderEngine::RendererImplementation> RenderingMethods = {
|
|
{ "ABuffer", RendererImplementation::ABuffer },
|
|
{ "Framebuffer", RendererImplementation::Framebuffer }
|
|
};
|
|
|
|
if (RenderingMethods.find(impl) != RenderingMethods.end()) {
|
|
return RenderingMethods.at(impl);
|
|
}
|
|
else {
|
|
return RendererImplementation::Invalid;
|
|
}
|
|
}
|
|
|
|
std::string RenderEngine::progressToStr(int size, double t) {
|
|
std::string progress = "|";
|
|
int g = static_cast<int>((t * (size - 1)) + 1);
|
|
g = std::max(g, 0);
|
|
for (int i = 0; i < g; i++) {
|
|
progress.append("-");
|
|
}
|
|
progress.append(">");
|
|
for (int i = 0; i < size - g; i++) {
|
|
progress.append(" ");
|
|
}
|
|
progress.append("|");
|
|
return progress;
|
|
}
|
|
|
|
void RenderEngine::renderInformation() {
|
|
// TODO: Adjust font_size properly when using retina screen
|
|
using ghoul::fontrendering::RenderFont;
|
|
|
|
if (_fontDate) {
|
|
glm::vec2 penPosition = glm::vec2(
|
|
10.f,
|
|
fontResolution().y
|
|
//OsEng.windowWrapper().viewportPixelCoordinates().w
|
|
);
|
|
|
|
penPosition.y -= OsEng.console().currentHeight();
|
|
|
|
if (_showDate && _fontDate) {
|
|
penPosition.y -= _fontDate->height();
|
|
RenderFontCr(
|
|
*_fontDate,
|
|
penPosition,
|
|
"Date: %s",
|
|
OsEng.timeManager().time().UTC().c_str()
|
|
);
|
|
}
|
|
else {
|
|
penPosition.y -= _fontInfo->height();
|
|
}
|
|
if (_showInfo && _fontInfo) {
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
"Simulation increment (s): %.3f",
|
|
OsEng.timeManager().time().deltaTime()
|
|
);
|
|
|
|
FrametimeType frametimeType = FrametimeType(_frametimeType.value());
|
|
switch (frametimeType) {
|
|
case FrametimeType::DtTimeAvg:
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
"Avg. Frametime: %.5f",
|
|
OsEng.windowWrapper().averageDeltaTime()
|
|
);
|
|
break;
|
|
case FrametimeType::FPS:
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
"FPS: %3.2f",
|
|
1.0 / OsEng.windowWrapper().deltaTime()
|
|
);
|
|
break;
|
|
case FrametimeType::FPSAvg:
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
"Avg. FPS: %3.2f",
|
|
1.0 / OsEng.windowWrapper().averageDeltaTime()
|
|
);
|
|
break;
|
|
default:
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
"Avg. Frametime: %.5f",
|
|
OsEng.windowWrapper().averageDeltaTime()
|
|
);
|
|
break;
|
|
}
|
|
|
|
ParallelConnection::Status status = OsEng.parallelConnection().status();
|
|
size_t nConnections = OsEng.parallelConnection().nConnections();
|
|
const std::string& hostName = OsEng.parallelConnection().hostName();
|
|
|
|
std::string connectionInfo = "";
|
|
int nClients = static_cast<int>(nConnections);
|
|
if (status == ParallelConnection::Status::Host) {
|
|
nClients--;
|
|
if (nClients == 1) {
|
|
connectionInfo = "Hosting session with 1 client";
|
|
}
|
|
else {
|
|
connectionInfo =
|
|
"Hosting session with " + std::to_string(nClients) + " clients";
|
|
}
|
|
}
|
|
else if (status == ParallelConnection::Status::ClientWithHost) {
|
|
nClients--;
|
|
connectionInfo = "Session hosted by '" + hostName + "'";
|
|
}
|
|
else if (status == ParallelConnection::Status::ClientWithoutHost) {
|
|
connectionInfo = "Host is disconnected";
|
|
}
|
|
|
|
if (status == ParallelConnection::Status::ClientWithHost ||
|
|
status == ParallelConnection::Status::ClientWithoutHost) {
|
|
connectionInfo += "\n";
|
|
if (nClients > 2) {
|
|
std::string c = std::to_string(nClients - 1);
|
|
connectionInfo += "You and " + c + " more clients are tuned in";
|
|
}
|
|
else if (nClients == 2) {
|
|
std::string c = std::to_string(nClients - 1);
|
|
connectionInfo += "You and " + c + " more client are tuned in";
|
|
}
|
|
else if (nClients == 1) {
|
|
connectionInfo += "You are the only client";
|
|
}
|
|
}
|
|
|
|
if (connectionInfo != "") {
|
|
RenderFontCr(
|
|
*_fontInfo,
|
|
penPosition,
|
|
connectionInfo.c_str()
|
|
);
|
|
}
|
|
|
|
|
|
#ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED
|
|
bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
|
|
double currentTime = OsEng.timeManager().time().j2000Seconds();
|
|
|
|
if (MissionManager::ref().hasCurrentMission()) {
|
|
|
|
const Mission& mission = MissionManager::ref().currentMission();
|
|
|
|
if (mission.phases().size() > 0) {
|
|
static const glm::vec4 nextMissionColor(0.7, 0.3, 0.3, 1);
|
|
//static const glm::vec4 missionProgressColor(0.4, 1.0, 1.0, 1);
|
|
static const glm::vec4 currentMissionColor(0.0, 0.5, 0.5, 1);
|
|
static const glm::vec4 missionProgressColor = currentMissionColor;// (0.4, 1.0, 1.0, 1);
|
|
static const glm::vec4 currentLeafMissionColor = missionProgressColor;
|
|
static const glm::vec4 nonCurrentMissionColor(0.3, 0.3, 0.3, 1);
|
|
|
|
// Add spacing
|
|
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, " ");
|
|
|
|
auto phaseTrace = mission.phaseTrace(currentTime);
|
|
|
|
if (phaseTrace.size()) {
|
|
const MissionPhase& phase = phaseTrace.back().get();
|
|
std::string title = "Current Mission Phase: " + phase.name();
|
|
RenderFontCr(*_fontInfo, penPosition, missionProgressColor, title.c_str());
|
|
double remaining = phase.timeRange().end - currentTime;
|
|
float t = static_cast<float>(1.0 - remaining / phase.timeRange().duration());
|
|
std::string progress = progressToStr(25, t);
|
|
//RenderFontCr(*_fontInfo, penPosition, missionProgressColor,
|
|
// "%.0f s %s %.1f %%", remaining, progress.c_str(), t * 100);
|
|
}
|
|
else {
|
|
RenderFontCr(*_fontInfo, penPosition, nextMissionColor, "Next Mission:");
|
|
double remaining = mission.timeRange().start - currentTime;
|
|
RenderFontCr(*_fontInfo, penPosition, nextMissionColor,
|
|
"%.0f s", remaining);
|
|
}
|
|
|
|
bool showAllPhases = false;
|
|
|
|
typedef std::pair<const MissionPhase*, int> PhaseWithDepth;
|
|
std::stack<PhaseWithDepth> S;
|
|
int pixelIndentation = 20;
|
|
S.push({ &mission, 0 });
|
|
while (!S.empty()) {
|
|
const MissionPhase* phase = S.top().first;
|
|
int depth = S.top().second;
|
|
S.pop();
|
|
|
|
bool isCurrentPhase = phase->timeRange().includes(currentTime);
|
|
|
|
penPosition.x += depth * pixelIndentation;
|
|
if (isCurrentPhase) {
|
|
double remaining = phase->timeRange().end - currentTime;
|
|
float t = static_cast<float>(1.0 - remaining / phase->timeRange().duration());
|
|
std::string progress = progressToStr(25, t);
|
|
RenderFontCr(*_fontInfo, penPosition, currentMissionColor,
|
|
"%s %s %.1f %%",
|
|
phase->name().c_str(),
|
|
progress.c_str(),
|
|
t * 100
|
|
);
|
|
}
|
|
else {
|
|
RenderFontCr(*_fontInfo, penPosition, nonCurrentMissionColor, phase->name().c_str());
|
|
}
|
|
penPosition.x -= depth * pixelIndentation;
|
|
|
|
if (isCurrentPhase || showAllPhases) {
|
|
// phases are sorted increasingly by start time, and will be popped
|
|
// last-in-first-out from the stack, so add them in reversed order.
|
|
int indexLastPhase = static_cast<int>(phase->phases().size()) - 1;
|
|
for (int i = indexLastPhase; 0 <= i; --i) {
|
|
S.push({ &phase->phases()[i], depth + 1 });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (openspace::ImageSequencer::ref().isReady()) {
|
|
penPosition.y -= 25.f;
|
|
|
|
glm::vec4 targetColor(0.00, 0.75, 1.00, 1);
|
|
|
|
if (hasNewHorizons) {
|
|
try {
|
|
double lt;
|
|
glm::dvec3 p =
|
|
SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt);
|
|
psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z);
|
|
float a, b;
|
|
glm::dvec3 radii;
|
|
SpiceManager::ref().getValue("PLUTO", "RADII", radii);
|
|
a = static_cast<float>(radii.x);
|
|
b = static_cast<float>(radii.y);
|
|
float radius = (a + b) / 2.f;
|
|
float distToSurf = glm::length(nhPos.vec3()) - radius;
|
|
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
"Distance to Pluto: % .1f (KM)",
|
|
distToSurf
|
|
);
|
|
penPosition.y -= _fontInfo->height();
|
|
}
|
|
catch (...) {
|
|
// @CLEANUP: This is bad as it will discard all exceptions
|
|
// without telling us about it! ---abock
|
|
}
|
|
}
|
|
|
|
double remaining = openspace::ImageSequencer::ref().getNextCaptureTime() - currentTime;
|
|
float t = static_cast<float>(1.0 - remaining / openspace::ImageSequencer::ref().getIntervalLength());
|
|
|
|
std::string str = SpiceManager::ref().dateFromEphemerisTime(
|
|
ImageSequencer::ref().getNextCaptureTime(),
|
|
"YYYY MON DD HR:MN:SC"
|
|
);
|
|
|
|
glm::vec4 active(0.6, 1, 0.00, 1);
|
|
glm::vec4 brigther_active(0.9, 1, 0.75, 1);
|
|
|
|
if (remaining > 0) {
|
|
|
|
std::string progress = progressToStr(25, t);
|
|
brigther_active *= (1 - t);
|
|
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
active * t + brigther_active,
|
|
"Next instrument activity:"
|
|
);
|
|
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
active * t + brigther_active,
|
|
"%.0f s %s %.1f %%",
|
|
remaining, progress.c_str(), t * 100
|
|
);
|
|
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
active,
|
|
"Data acquisition time: %s",
|
|
str.c_str()
|
|
);
|
|
}
|
|
std::pair<double, std::string> nextTarget = ImageSequencer::ref().getNextTarget();
|
|
std::pair<double, std::string> currentTarget = ImageSequencer::ref().getCurrentTarget();
|
|
|
|
if (currentTarget.first > 0.0) {
|
|
int timeleft = static_cast<int>(nextTarget.first - currentTime);
|
|
|
|
int hour = timeleft / 3600;
|
|
int second = timeleft % 3600;
|
|
int minute = second / 60;
|
|
second = second % 60;
|
|
|
|
std::string hh, mm, ss;
|
|
|
|
if (hour < 10)
|
|
hh.append("0");
|
|
if (minute < 10)
|
|
mm.append("0");
|
|
if (second < 10)
|
|
ss.append("0");
|
|
|
|
hh.append(std::to_string(hour));
|
|
mm.append(std::to_string(minute));
|
|
ss.append(std::to_string(second));
|
|
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
targetColor,
|
|
"Data acquisition adjacency: [%s:%s:%s]",
|
|
hh.c_str(), mm.c_str(), ss.c_str()
|
|
);
|
|
|
|
#if 0
|
|
// Why is it (2) in the original? ---abock
|
|
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(0);
|
|
//std::pair<double, std::vector<std::string>> incidentTargets = ImageSequencer::ref().getIncidentTargetList(2);
|
|
std::string space;
|
|
glm::vec4 color;
|
|
size_t isize = incidentTargets.second.size();
|
|
for (size_t p = 0; p < isize; p++) {
|
|
double t = static_cast<double>(p + 1) / static_cast<double>(isize + 1);
|
|
t = (p > isize / 2) ? 1 - t : t;
|
|
t += 0.3;
|
|
color = (p == isize / 2) ? targetColor : glm::vec4(t, t, t, 1);
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
color,
|
|
"%s%s",
|
|
space.c_str(), incidentTargets.second[p].c_str()
|
|
);
|
|
for (int k = 0; k < incidentTargets.second[p].size() + 2; k++)
|
|
space += " ";
|
|
}
|
|
#endif
|
|
penPosition.y -= _fontInfo->height();
|
|
|
|
std::map<std::string, bool> activeMap = ImageSequencer::ref().getActiveInstruments();
|
|
glm::vec4 firing(0.58 - t, 1 - t, 1 - t, 1);
|
|
glm::vec4 notFiring(0.5, 0.5, 0.5, 1);
|
|
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
active,
|
|
"Active Instruments:"
|
|
);
|
|
|
|
for (auto ac : activeMap) {
|
|
if (ac.second == false) {
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
glm::vec4(0.3, 0.3, 0.3, 1),
|
|
"| |"
|
|
);
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
glm::vec4(0.3, 0.3, 0.3, 1),
|
|
" %5s",
|
|
ac.first.c_str()
|
|
);
|
|
|
|
}
|
|
else {
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
glm::vec4(0.3, 0.3, 0.3, 1),
|
|
"|"
|
|
);
|
|
if (ac.first == "NH_LORRI") {
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
firing,
|
|
" + "
|
|
);
|
|
}
|
|
RenderFont(*_fontInfo,
|
|
penPosition,
|
|
glm::vec4(0.3, 0.3, 0.3, 1),
|
|
" |"
|
|
);
|
|
RenderFontCr(*_fontInfo,
|
|
penPosition,
|
|
active,
|
|
" %5s",
|
|
ac.first.c_str()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void RenderEngine::renderScreenLog() {
|
|
if (!_showLog) {
|
|
return;
|
|
}
|
|
|
|
_log->removeExpiredEntries();
|
|
|
|
const int max = 10;
|
|
const int category_length = 20;
|
|
const int msg_length = 140;
|
|
std::chrono::seconds fade(5);
|
|
|
|
auto entries = _log->entries();
|
|
auto lastEntries =
|
|
entries.size() > max ?
|
|
std::make_pair(entries.rbegin(), entries.rbegin() + max) :
|
|
std::make_pair(entries.rbegin(), entries.rend());
|
|
|
|
|
|
size_t nr = 1;
|
|
auto now = std::chrono::steady_clock::now();
|
|
for (auto& it = lastEntries.first; it != lastEntries.second; ++it) {
|
|
const ScreenLog::LogEntry* e = &(*it);
|
|
|
|
std::chrono::duration<double> diff = now - e->timeStamp;
|
|
|
|
float alpha = 1;
|
|
std::chrono::duration<double> ttf = ScreenLogTimeToLive - fade;
|
|
if (diff > ttf) {
|
|
auto d = (diff - ttf).count();
|
|
auto t = static_cast<float>(d) / static_cast<float>(fade.count());
|
|
float p = 0.8f - t;
|
|
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::stringFromLevel(e->level) + ")";
|
|
const std::string& message = e->message.substr(0, msg_length);
|
|
nr += std::count(message.begin(), message.end(), '\n');
|
|
|
|
const glm::vec4 White(0.9f, 0.9f, 0.9f, 1.0f);
|
|
|
|
RenderFont(
|
|
*_fontLog,
|
|
glm::vec2(10.f, _fontLog->pointSize() * nr * 2),
|
|
White * alpha,
|
|
"%-14s %s%s", // Format
|
|
e->timeString.c_str(), // Time string
|
|
e->category.substr(0, category_length).c_str(), // Category string
|
|
e->category.length() > 20 ? "..." : ""); // Pad category with "..."
|
|
|
|
const glm::vec4 Red(1.f, 0.f, 0.f, 1.f);
|
|
const glm::vec4 Yellow(1.f, 1.f, 0.f, 1.f);
|
|
const glm::vec4 Green(0.f, 1.f, 0.f, 1.f);
|
|
const glm::vec4 Blue(0.f, 0.f, 1.f, 1.f);
|
|
|
|
glm::vec4 color(glm::uninitialize);
|
|
switch (e->level) {
|
|
case ghoul::logging::LogLevel::Debug:
|
|
color = Green;
|
|
break;
|
|
case ghoul::logging::LogLevel::Warning:
|
|
color = Yellow;
|
|
break;
|
|
case ghoul::logging::LogLevel::Error:
|
|
color = Red;
|
|
break;
|
|
case ghoul::logging::LogLevel::Fatal:
|
|
color = Blue;
|
|
break;
|
|
default:
|
|
color = White;
|
|
break;
|
|
}
|
|
|
|
// const float font_with_light = 5;
|
|
RenderFont(
|
|
*_fontLog,
|
|
glm::vec2(static_cast<float>(10 + 39 * _fontLog->pointSize()), _fontLog->pointSize() * nr * 2),
|
|
color * alpha,
|
|
"%s", // Format
|
|
lvl.c_str()); // Pad category with "..." if exceeds category_length
|
|
|
|
RenderFont(*_fontLog,
|
|
glm::vec2(static_cast<float>(10 + 53 * _fontLog->pointSize()), _fontLog->pointSize() * nr * 2),
|
|
White * alpha,
|
|
"%s", // Format
|
|
message.c_str()); // Pad category with "..." if exceeds category_length
|
|
++nr;
|
|
}
|
|
}
|
|
|
|
std::vector<Syncable*> RenderEngine::getSyncables() {
|
|
if (_camera) {
|
|
return _camera->getSyncables();
|
|
}
|
|
else {
|
|
return std::vector<Syncable*>();
|
|
}
|
|
}
|
|
|
|
void RenderEngine::sortScreenspaceRenderables() {
|
|
std::sort(
|
|
_screenSpaceRenderables.begin(),
|
|
_screenSpaceRenderables.end(),
|
|
[](const std::shared_ptr<ScreenSpaceRenderable>& j,
|
|
const std::shared_ptr<ScreenSpaceRenderable>& i)
|
|
{
|
|
return i->depth() > j->depth();
|
|
}
|
|
);
|
|
}
|
|
|
|
}// namespace openspace
|