Merge remote-tracking branch 'origin/master' into feature/openglstatecache

# Conflicts:
#	ext/ghoul
#	modules/digitaluniverse/rendering/renderablebillboardscloud.cpp
#	modules/digitaluniverse/rendering/renderableplanescloud.cpp
#	src/util/screenlog.cpp
This commit is contained in:
Alexander Bock
2020-09-04 14:02:17 +02:00
199 changed files with 2985 additions and 1664 deletions
+2
View File
@@ -433,6 +433,8 @@ target_include_directories(openspace-core PUBLIC
${OPENSPACE_BASE_DIR}/include
# In order to be able to include module files
${OPENSPACE_BASE_DIR}
# In order to use the date library
${OPENSPACE_BASE_DIR}/ext/date/include
# In order to be able to include the module_registration file
${CMAKE_BINARY_DIR}/_generated/include
)
@@ -29,6 +29,7 @@
#include <openspace/documentation/verifier.h>
#include <ghoul/fmt.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/profiling.h>
#include <fstream>
@@ -194,6 +195,8 @@ std::vector<Documentation> DocumentationEngine::documentations() const {
void DocumentationEngine::writeDocumentationHtml(const std::string& path,
std::string data)
{
ZoneScoped
std::ifstream handlebarsInput;
handlebarsInput.exceptions(~std::ofstream::goodbit);
handlebarsInput.open(absPath(HandlebarsFilename));
+46 -14
View File
@@ -62,6 +62,7 @@
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/camera.h>
#include <openspace/util/factorymanager.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/task.h>
#include <openspace/util/timemanager.h>
@@ -82,6 +83,7 @@
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
#include <glbinding/glbinding.h>
#include <glbinding-aux/types_to_string.h>
#include <future>
#include <numeric>
#include <sstream>
@@ -257,11 +259,9 @@ void OpenSpaceEngine::initialize() {
#endif // WIN32
#ifndef GHOUL_LOGGING_ENABLE_TRACE
LogLevel level = ghoul::logging::levelFromString(_configuration->logging.level);
if (level == ghoul::logging::LogLevel::Trace) {
LWARNING(
"Desired logging level is set to 'Trace' but application was " <<
"Desired logging level is set to 'Trace' but application was "
"compiled without Trace support"
);
}
@@ -707,8 +707,11 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
std::unique_ptr<SceneInitializer> sceneInitializer;
if (global::configuration.useMultithreadedInitialization) {
unsigned int nAvailableThreads = std::thread::hardware_concurrency();
unsigned int nThreads = nAvailableThreads == 0 ? 2 : nAvailableThreads - 1;
unsigned int nAvailableThreads = std::min(
std::thread::hardware_concurrency() - 1,
4u
);
unsigned int nThreads = nAvailableThreads == 0 ? 2 : nAvailableThreads;
sceneInitializer = std::make_unique<MultiThreadedSceneInitializer>(nThreads);
}
else {
@@ -850,7 +853,7 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
runGlobalCustomizationScripts();
writeSceneDocumentation();
_writeDocumentationTask = std::async(&OpenSpaceEngine::writeSceneDocumentation, this);
LTRACE("OpenSpaceEngine::loadSingleAsset(end)");
}
@@ -994,10 +997,7 @@ void OpenSpaceEngine::loadFonts() {
}
try {
bool initSuccess = ghoul::fontrendering::FontRenderer::initialize();
if (!initSuccess) {
LERROR("Error initializing default font renderer");
}
ghoul::fontrendering::FontRenderer::initialize();
}
catch (const ghoul::RuntimeError& err) {
LERRORC(err.component, err.message);
@@ -1011,6 +1011,18 @@ void OpenSpaceEngine::writeSceneDocumentation() {
std::string path = global::configuration.documentation.path;
if (!path.empty()) {
std::future<std::string> root = std::async(
&properties::PropertyOwner::generateJson,
&global::rootPropertyOwner
);
std::future<std::string> scene = std::async(
&properties::PropertyOwner::generateJson,
_scene.get()
);
path = absPath(path) + "/";
_documentationJson += "{\"name\":\"Keybindings\",\"identifier\":\"";
_documentationJson += global::keybindingManager.jsonName() + "\",";
@@ -1024,11 +1036,11 @@ void OpenSpaceEngine::writeSceneDocumentation() {
_documentationJson += "},";
_documentationJson += "{\"name\":\"Scene Properties\",";
_documentationJson += "\"identifier\":\"propertylist";// + _scene->jsonName();
_documentationJson += "\",\"data\":" + global::rootPropertyOwner.generateJson();
_documentationJson += "\",\"data\":" + root.get();
_documentationJson += "},";
_documentationJson += "{\"name\":\"Scene Graph Information\",";
_documentationJson += "\"identifier\":\"propertylist";
_documentationJson += "\",\"data\":" + _scene->generateJson();
_documentationJson += "\",\"data\":" + scene.get();
_documentationJson += "}";
//add templates for the jsons we just registered
@@ -1051,10 +1063,15 @@ void OpenSpaceEngine::writeSceneDocumentation() {
void OpenSpaceEngine::preSynchronization() {
ZoneScoped
TracyGpuZone("preSynchronization")
LTRACE("OpenSpaceEngine::preSynchronization(begin)");
FileSys.triggerFilesystemEvents();
// Reset the temporary, frame-based storage
global::memoryManager.TemporaryMemory.reset();
if (_hasScheduledAssetLoading) {
LINFO(fmt::format("Loading asset: {}", _scheduledAssetPathToLoad));
global::profile.setIgnoreUpdates(true);
@@ -1116,6 +1133,7 @@ void OpenSpaceEngine::preSynchronization() {
void OpenSpaceEngine::postSynchronizationPreDraw() {
ZoneScoped
TracyGpuZone("postSynchronizationPreDraw")
LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(begin)");
bool master = global::windowDelegate.isMaster();
@@ -1141,10 +1159,19 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
const bool updated = _assetManager->update();
if (updated) {
writeSceneDocumentation();
if (_writeDocumentationTask.valid()) {
// If there still is a documentation creation task the previous frame, we need
// to wait for it to finish first, or else we might write to the same file
_writeDocumentationTask.wait();
}
_writeDocumentationTask = std::async(
&OpenSpaceEngine::writeSceneDocumentation, this
);
}
global::renderEngine.updateScene();
if (!global::windowDelegate.isMaster()) {
global::renderEngine.updateScene();
}
global::renderEngine.updateRenderer();
global::renderEngine.updateScreenSpaceRenderables();
global::renderEngine.updateShaderPrograms();
@@ -1185,6 +1212,7 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& view
const glm::mat4& projectionMatrix)
{
ZoneScoped
TracyGpuZone("Render")
LTRACE("OpenSpaceEngine::render(begin)");
const bool isGuiWindow =
@@ -1209,6 +1237,7 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& view
void OpenSpaceEngine::drawOverlays() {
ZoneScoped
TracyGpuZone("Draw2D")
LTRACE("OpenSpaceEngine::drawOverlays(begin)");
const bool isGuiWindow =
@@ -1233,6 +1262,7 @@ void OpenSpaceEngine::drawOverlays() {
void OpenSpaceEngine::postDraw() {
ZoneScoped
TracyGpuZone("postDraw")
LTRACE("OpenSpaceEngine::postDraw(begin)");
global::renderEngine.postDraw();
@@ -1249,6 +1279,8 @@ void OpenSpaceEngine::postDraw() {
_isFirstRenderingFirstFrame = false;
}
global::memoryManager.PersistentMemory.housekeeping();
LTRACE("OpenSpaceEngine::postDraw(end)");
}
+3
View File
@@ -27,6 +27,7 @@
#include <openspace/engine/globals.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/misc/profiling.h>
#include <ghoul/glm.h>
#include <sstream>
@@ -170,6 +171,8 @@ KeybindingManager::keyBindings() const
}
std::string KeybindingManager::generateJson() const {
ZoneScoped
std::stringstream json;
json << "[";
bool first = true;
+3 -3
View File
@@ -793,7 +793,7 @@ bool OrbitalNavigator::shouldFollowAnchorRotation(const glm::dvec3& cameraPositi
}
const glm::dmat4 modelTransform = _anchorNode->modelTransform();
const glm::dmat4 inverseModelTransform = _anchorNode->inverseModelTransform();
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
const glm::dvec3 cameraPositionModelSpace = glm::dvec3(inverseModelTransform *
glm::dvec4(cameraPosition, 1.0));
@@ -847,8 +847,8 @@ OrbitalNavigator::CameraRotationDecomposition
const glm::dvec3 cameraViewDirection =
cameraPose.rotation * glm::dvec3(0.0, 0.0, -1.0);
const glm::dmat4 inverseModelTransform = reference.inverseModelTransform();
const glm::dmat4 modelTransform = reference.modelTransform();
const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform);
const glm::dvec3 cameraPositionModelSpace = glm::dvec3(inverseModelTransform *
glm::dvec4(cameraPose.position, 1));
@@ -1411,7 +1411,7 @@ SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle(
const SceneGraphNode& node,
const glm::dvec3 cameraPositionWorldSpace)
{
const glm::dmat4 inverseModelTransform = node.inverseModelTransform();
const glm::dmat4 inverseModelTransform = glm::inverse(node.modelTransform());
const glm::dvec3 cameraPositionModelSpace =
glm::dvec3(inverseModelTransform * glm::dvec4(cameraPositionWorldSpace, 1));
const SurfacePositionHandle posHandle =
+114 -57
View File
@@ -35,6 +35,111 @@
namespace {
constexpr const char* _loggerCat = "PropertyOwner";
std::string escapedJson(const std::string& text) {
std::string jsonString;
for (const char& c : text) {
switch (c) {
case '\t':
jsonString += "\\t"; // Replace tab with \t.
break;
case '"':
jsonString += "\\\""; // Replace " with \".
break;
case '\\':
jsonString += "\\\\"; // Replace \ with \\.
break;
case '\n':
jsonString += "\\\\n"; // Replace newline with \n.
break;
case '\r':
jsonString += "\\r"; // Replace carriage return with \r.
break;
default:
jsonString += c;
}
}
return jsonString;
}
void createJson(openspace::properties::PropertyOwner* owner, std::vector<char>& buf) {
ZoneScoped
using namespace openspace;
constexpr const char* replStr = R"("{}": "{}")";
//std::stringstream json;
//json << "{";
buf.push_back('{');
//json << fmt::format(replStr, "name", owner->identifier()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "name", owner->identifier());
buf.push_back(',');
constexpr const char propertiesText[] = "\"properties\": [";
//constexpr const std::array<char, 16> propertiesText = { "\"properties\": [" };
buf.insert(buf.end(), std::begin(propertiesText), std::end(propertiesText) - 1);
//json << "\"properties\": [";
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
//json << "{";
buf.push_back('{');
//json << fmt::format(replStr, "id", p->identifier()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "id", p->identifier());
buf.push_back(',');
//json << fmt::format(replStr, "type", p->className()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "type", p->className());
buf.push_back(',');
//json << fmt::format(
// replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
//) << ",";
fmt::format_to(
std::back_inserter(buf),
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
);
buf.push_back(',');
//json << fmt::format(replStr, "guiName", p->guiName()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "guiName", p->guiName());
buf.push_back(',');
//json << fmt::format(replStr, "description", escapedJson(p->description()));
fmt::format_to(
std::back_inserter(buf),
replStr, "description", escapedJson(p->description())
);
//json << "}";
buf.push_back('}');
if (p != properties.back()) {
//json << ",";
buf.push_back(',');
}
}
//json << "],";
buf.push_back(']');
buf.push_back(',');
constexpr const char propertyOwnersText[] = "\"propertyOwners\": [";
//constexpr const std::array<char, 20> propertyOwnersText = { "\"propertyOwners\": [" };
//json << "\"propertyOwners\": [";
buf.insert(buf.end(), std::begin(propertyOwnersText), std::end(propertyOwnersText) - 1);
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
createJson(o, buf);
//json << createJson(o);
if (o != propertyOwners.back()) {
//json << ",";
buf.push_back(',');
}
}
//json << "]";
buf.push_back(']');
//json << "}";
buf.push_back('}');
//return json.str();
};
} // namespace
namespace openspace::properties {
@@ -356,67 +461,19 @@ void PropertyOwner::removeTag(const std::string& tag) {
}
std::string PropertyOwner::generateJson() const {
std::function<std::string(properties::PropertyOwner*)> createJson =
[&createJson](properties::PropertyOwner* owner) -> std::string
{
constexpr const char* replStr = R"("{}": "{}")";
ZoneScoped
std::stringstream json;
json << "{";
json << fmt::format(replStr, "name", owner->identifier()) << ",";
json << "\"properties\": [";
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
json << "{";
json << fmt::format(replStr, "id", p->identifier()) << ",";
json << fmt::format(replStr, "type", p->className()) << ",";
json << fmt::format(
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
) << ",";
json << fmt::format(replStr, "guiName", p->guiName()) << ",";
json << fmt::format(replStr, "description", escapedJson(p->description()));
json << "}";
if (p != properties.back()) {
json << ",";
}
}
json << "],";
json << "\"propertyOwners\": [";
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
json << createJson(o);
if (o != propertyOwners.back()) {
json << ",";
}
}
json << "]";
json << "}";
return json.str();
};
std::stringstream json;
json << "[";
std::vector<char> res;
res.reserve(5 * 51024 * 1024); // 5 MB
res.push_back('[');
std::vector<PropertyOwner*> subOwners = propertySubOwners();
if (!subOwners.empty()) {
json << std::accumulate(
std::next(subOwners.begin()),
subOwners.end(),
createJson(*subOwners.begin()),
[createJson](std::string a, PropertyOwner* n) {
//TODO figure out how to ignore scene when its not the root
//right now will be done on client side
return a + "," + createJson(n);
}
);
for (PropertyOwner* owner : subOwners) {
createJson(owner, res);
res.push_back(',');
}
res.back() = ']';
json << "]";
return json.str();
return std::string(res.begin(), res.end());
}
} // namespace openspace::properties
+3
View File
@@ -27,6 +27,7 @@
#include <openspace/rendering/dashboarditem.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/profiling.h>
#include "dashboard_lua.inl"
@@ -127,6 +128,8 @@ void Dashboard::clearDashboardItems() {
}
void Dashboard::render(glm::vec2& penPosition) {
ZoneScoped
if (!_isEnabled) {
return;
}
+45 -3
View File
@@ -138,6 +138,9 @@ namespace {
namespace openspace {
void FramebufferRenderer::initialize() {
ZoneScoped
TracyGpuZone("Rendering initialize");
LDEBUG("Initializing FramebufferRenderer");
HasGLDebugInfo = glbinding::Binding::ObjectLabel.isResolved() &&
@@ -467,6 +470,9 @@ void FramebufferRenderer::initialize() {
}
void FramebufferRenderer::deinitialize() {
ZoneScoped
TracyGpuZone("Renderer deinitialize")
LINFO("Deinitializing FramebufferRenderer");
glDeleteFramebuffers(1, &_gBuffers.framebuffer);
@@ -511,6 +517,9 @@ void FramebufferRenderer::deferredcastersChanged(Deferredcaster&,
}
void FramebufferRenderer::applyTMO(float blackoutFactor) {
ZoneScoped
TracyGpuZone("applyTMO")
_hdrFilteringProgram->activate();
ghoul::opengl::TextureUnit hdrFeedingTextureUnit;
@@ -785,6 +794,9 @@ void FramebufferRenderer::update() {
}
void FramebufferRenderer::updateResolution() {
ZoneScoped
TracyGpuZone("Renderer updateResolution")
glBindTexture(GL_TEXTURE_2D, _gBuffers.colorTexture);
glTexImage2D(
GL_TEXTURE_2D,
@@ -971,6 +983,8 @@ void FramebufferRenderer::updateResolution() {
}
void FramebufferRenderer::updateRaycastData() {
ZoneScoped
_raycastData.clear();
_exitPrograms.clear();
_raycastPrograms.clear();
@@ -981,6 +995,8 @@ void FramebufferRenderer::updateRaycastData() {
int nextId = 0;
for (VolumeRaycaster* raycaster : raycasters) {
ZoneScopedN("raycaster")
RaycastData data = { nextId++, "Helper" };
const std::string& vsPath = raycaster->boundsVertexShaderPath();
@@ -1095,6 +1111,8 @@ void FramebufferRenderer::updateDeferredcastData() {
void FramebufferRenderer::updateHDRAndFiltering() {
ZoneScoped
_hdrFilteringProgram = ghoul::opengl::ProgramObject::Build(
"HDR and Filtering Program",
absPath("${SHADERS}/framebuffer/hdrAndFiltering.vert"),
@@ -1103,6 +1121,8 @@ void FramebufferRenderer::updateHDRAndFiltering() {
}
void FramebufferRenderer::updateFXAA() {
ZoneScoped
_fxaaProgram = ghoul::opengl::ProgramObject::Build(
"FXAA Program",
absPath("${SHADERS}/framebuffer/fxaa.vert"),
@@ -1111,7 +1131,9 @@ void FramebufferRenderer::updateFXAA() {
}
void FramebufferRenderer::updateDownscaledVolume() {
_downscaledVolumeProgram = ghoul::opengl::ProgramObject::Build(
ZoneScoped
_downscaledVolumeProgram = ghoul::opengl::ProgramObject::Build(
"Write Downscaled Volume Program",
absPath("${SHADERS}/framebuffer/mergeDownscaledVolume.vert"),
absPath("${SHADERS}/framebuffer/mergeDownscaledVolume.frag")
@@ -1120,6 +1142,7 @@ void FramebufferRenderer::updateDownscaledVolume() {
void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFactor) {
ZoneScoped
TracyGpuZone("FramebufferRenderer")
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO);
@@ -1158,25 +1181,31 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
RendererTasks tasks;
{
TracyGpuZone("Background")
GLDebugGroup group("Background");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Background);
scene->render(data, tasks);
}
{
TracyGpuZone("Opaque")
GLDebugGroup group("Opaque");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Opaque);
scene->render(data, tasks);
}
{
TracyGpuZone("PreDeferredTransparent")
GLDebugGroup group("PreDeferredTransparent");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::PreDeferredTransparent);
data.renderBinMask = static_cast<int>(
Renderable::RenderBin::PreDeferredTransparent
);
scene->render(data, tasks);
}
// Run Volume Tasks
{
TracyGpuZone("Raycaster Tasks")
GLDebugGroup group("Raycaster Tasks");
performRaycasterTasks(tasks.raycasterTasks);
@@ -1186,6 +1215,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
}
if (!tasks.deferredcasterTasks.empty()) {
TracyGpuZone("Deferred Caster Tasks")
GLDebugGroup group("Deferred Caster Tasks");
// We use ping pong rendering in order to be able to
@@ -1201,12 +1231,16 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
glEnablei(GL_BLEND, 0);
{
TracyGpuZone("PostDeferredTransparent")
GLDebugGroup group("PostDeferredTransparent");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::PostDeferredTransparent);
data.renderBinMask = static_cast<int>(
Renderable::RenderBin::PostDeferredTransparent
);
scene->render(data, tasks);
}
{
TracyGpuZone("Overlay")
GLDebugGroup group("Overlay");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Overlay);
scene->render(data, tasks);
@@ -1231,12 +1265,14 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
{
// Apply the selected TMO on the results and resolve the result to the default FBO
TracyGpuZone("Apply TMO")
GLDebugGroup group("Apply TMO");
applyTMO(blackoutFactor);
}
if (_enableFXAA) {
TracyGpuZone("Apply FXAA")
GLDebugGroup group("Apply FXAA");
glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO);
applyFXAA();
@@ -1247,6 +1283,8 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector<RaycasterTask>
ZoneScoped
for (const RaycasterTask& raycasterTask : tasks) {
TracyGpuZone("Raycaster")
VolumeRaycaster* raycaster = raycasterTask.raycaster;
glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer);
@@ -1380,6 +1418,8 @@ void FramebufferRenderer::performDeferredTasks(
ZoneScoped
for (const DeferredcasterTask& deferredcasterTask : tasks) {
TracyGpuZone("Deferredcaster")
Deferredcaster* deferredcaster = deferredcasterTask.deferredcaster;
ghoul::opengl::ProgramObject* deferredcastProgram = nullptr;
@@ -1496,6 +1536,8 @@ void FramebufferRenderer::enableFXAA(bool enable) {
}
void FramebufferRenderer::updateRendererData() {
ZoneScoped
ghoul::Dictionary dict;
dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath));
dict.setValue("hdrExposure", std::to_string(_hdrExposure));
+1 -1
View File
@@ -687,7 +687,7 @@ void LuaConsole::render() {
// Since the overflow is positive, at least one character needs to be removed.
const size_t nCharsOverflow = static_cast<size_t>(std::min(
std::max(1.f, overflow / _font->glyph('m')->width()),
std::max(1.f, overflow / _font->glyph('m')->width),
static_cast<float>(currentCommand.size())
));
+4
View File
@@ -235,6 +235,10 @@ bool Renderable::isEnabled() const {
return _enabled;
}
bool Renderable::shouldUpdateIfDisabled() const {
return _shouldUpdateIfDisabled;
}
void Renderable::onEnabledChange(std::function<void(bool)> callback) {
_enabled.onChange([this, c = std::move(callback)]() {
c(isEnabled());
+131 -85
View File
@@ -42,6 +42,7 @@
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scene/scene.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/screenlog.h>
#include <openspace/util/updatestructures.h>
@@ -389,6 +390,8 @@ RenderEngine::RenderEngine()
RenderEngine::~RenderEngine() {} // NOLINT
void RenderEngine::setRendererFromString(const std::string& renderingMethod) {
ZoneScoped
_rendererImplementation = rendererFromString(renderingMethod);
std::unique_ptr<Renderer> newRenderer = nullptr;
@@ -447,6 +450,22 @@ void RenderEngine::initialize() {
ghoul::io::TextureReader::ref().addReader(
std::make_unique<ghoul::io::TextureReaderCMAP>()
);
_versionString = OPENSPACE_VERSION_STRING_FULL;
if (global::versionChecker.hasLatestVersionInfo()) {
VersionChecker::SemanticVersion latest = global::versionChecker.latestVersion();
VersionChecker::SemanticVersion current{
OPENSPACE_VERSION_MAJOR,
OPENSPACE_VERSION_MINOR,
OPENSPACE_VERSION_PATCH
};
if (current < latest) {
_versionString += fmt::format(
" [Available: {}.{}.{}]", latest.major, latest.minor, latest.patch
);
}
}
}
void RenderEngine::initializeGL() {
@@ -470,10 +489,6 @@ void RenderEngine::initializeGL() {
setRendererFromString(renderingMethod);
// 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
global::windowDelegate.setNearFarClippingPlane(0.001f, 1000.f);
@@ -482,19 +497,38 @@ void RenderEngine::initializeGL() {
// initialized window
_horizFieldOfView = static_cast<float>(global::windowDelegate.getHorizFieldOfView());
constexpr const float FontSizeFrameinfo = 32.f;
_fontFrameInfo = global::fontManager.font(KeyFontMono, FontSizeFrameinfo);
constexpr const float FontSizeTime = 15.f;
_fontDate = global::fontManager.font(KeyFontMono, FontSizeTime);
constexpr const float FontSizeMono = 10.f;
_fontInfo = global::fontManager.font(KeyFontMono, FontSizeMono);
constexpr const float FontSizeLight = 8.f;
_fontLog = global::fontManager.font(KeyFontLight, FontSizeLight);
{
ZoneScopedN("Font: Mono")
TracyGpuZone("Font: Mono")
constexpr const float FontSizeFrameinfo = 32.f;
_fontFrameInfo = global::fontManager.font(KeyFontMono, FontSizeFrameinfo);
}
{
ZoneScopedN("Font: Date")
TracyGpuZone("Font: Date")
constexpr const float FontSizeTime = 15.f;
_fontDate = global::fontManager.font(KeyFontMono, FontSizeTime);
}
{
ZoneScopedN("Font: Info")
TracyGpuZone("Font: Info")
constexpr const float FontSizeMono = 10.f;
_fontInfo = global::fontManager.font(KeyFontMono, FontSizeMono);
}
{
ZoneScopedN("Font: Log")
TracyGpuZone("Font: Log")
constexpr const float FontSizeLight = 8.f;
_fontLog = global::fontManager.font(KeyFontLight, FontSizeLight);
}
LINFO("Initializing Log");
std::unique_ptr<ScreenLog> log = std::make_unique<ScreenLog>(ScreenLogTimeToLive);
_log = log.get();
ghoul::logging::LogManager::ref().addLog(std::move(log));
{
ZoneScopedN("Log")
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)");
@@ -1092,6 +1126,8 @@ void RenderEngine::postRaycast(ghoul::opengl::ProgramObject& programObject) {
* Set renderer
*/
void RenderEngine::setRenderer(std::unique_ptr<Renderer> renderer) {
ZoneScoped
if (_renderer) {
_renderer->deinitialize();
}
@@ -1313,31 +1349,9 @@ void RenderEngine::renderVersionInformation() {
return;
}
std::string versionString = OPENSPACE_VERSION_STRING_FULL;
if (global::versionChecker.hasLatestVersionInfo()) {
VersionChecker::SemanticVersion latestVersion =
global::versionChecker.latestVersion();
VersionChecker::SemanticVersion currentVersion {
OPENSPACE_VERSION_MAJOR,
OPENSPACE_VERSION_MINOR,
OPENSPACE_VERSION_PATCH
};
if (currentVersion < latestVersion) {
versionString += fmt::format(
" [Available: {}.{}.{}]",
latestVersion.major, latestVersion.minor, latestVersion.patch
);
}
}
using FR = ghoul::fontrendering::FontRenderer;
const glm::vec2 versionBox = _fontInfo->boundingBox(versionString);
const glm::vec2 commitBox = _fontInfo->boundingBox(
fmt::format("{}@{}", OPENSPACE_GIT_BRANCH, OPENSPACE_GIT_COMMIT)
);
const glm::vec2 versionBox = _fontInfo->boundingBox(_versionString);
const glm::vec2 commitBox = _fontInfo->boundingBox(OPENSPACE_GIT_FULL);
FR::defaultRenderer().render(
*_fontInfo,
@@ -1345,13 +1359,13 @@ void RenderEngine::renderVersionInformation() {
fontResolution().x - versionBox.x - 10.f,
5.f
),
versionString,
_versionString,
glm::vec4(0.5, 0.5, 0.5, 1.f)
);
// If a developer hasn't placed the Git command in the path, this variable will be
// empty
if (!std::string(OPENSPACE_GIT_COMMIT).empty()) {
if (!std::string_view(OPENSPACE_GIT_COMMIT).empty()) {
// We check OPENSPACE_GIT_COMMIT but puse OPENSPACE_GIT_FULL on purpose since
// OPENSPACE_GIT_FULL will never be empty (always will contain at least @, but
// checking for that is a bit brittle)
@@ -1362,6 +1376,28 @@ void RenderEngine::renderVersionInformation() {
glm::vec4(0.5, 0.5, 0.5, 1.f)
);
}
#ifdef TRACY_ENABLE
{
// If we have Tracy enabled, we should inform the user about it that the
// application will crash after a while if no profiler is attached
ZoneScopedN("Tracy Information")
const glm::vec2 tracyBox = _fontInfo->boundingBox("TRACY PROFILING ENABLED");
const glm::vec2 penPosition = glm::vec2(
fontResolution().x - tracyBox.x - 10.f,
versionBox.y + commitBox.y + 5.f
);
FR::defaultRenderer().render(
*_fontInfo,
penPosition,
"TRACY PROFILING ENABLED",
glm::vec4(0.8f, 0.2f, 0.15f, 1.f)
);
}
#endif // TRACY_ENABLE
}
void RenderEngine::renderScreenLog() {
@@ -1389,9 +1425,9 @@ void RenderEngine::renderScreenLog() {
size_t nr = 1;
const auto now = std::chrono::steady_clock::now();
for (auto& it = lastEntries.first; it != lastEntries.second; ++it) {
const ScreenLog::LogEntry* e = &(*it);
ZoneScopedN("Entry")
std::chrono::duration<double> diff = now - e->timeStamp;
std::chrono::duration<double> diff = now - it->timeStamp;
float alpha = 1.f;
std::chrono::duration<double> ttf = ScreenLogTimeToLive - FadeTime;
@@ -1406,54 +1442,64 @@ void RenderEngine::renderScreenLog() {
if (alpha <= 0.f) {
break;
}
const std::string_view lvl = ghoul::to_string(e->level);
const std::string_view message =
std::string_view(e->message).substr(0, MessageLength);
std::string_view message = std::string_view(it->message).substr(0, MessageLength);
nr += std::count(message.begin(), message.end(), '\n');
const glm::vec4 white(0.9f, 0.9f, 0.9f, alpha);
std::string str = fmt::format(
"{:<15} {}{}",
e->timeString,
e->category.substr(0, CategoryLength),
e->category.length() > CategoryLength ? "..." : ""
);
std::array<char, 15 + CategoryLength + 3> buf;
{
std::fill(buf.begin(), buf.end(), char(0));
char* end = fmt::format_to(
buf.data(),
"{:<15} {}{}",
it->timeString,
std::string_view(it->category).substr(0, CategoryLength),
it->category.length() > CategoryLength ? "..." : ""
);
std::string_view text = std::string_view(buf.data(), end - buf.data());
RenderFont(
*_fontLog,
glm::vec2(
10.f,
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
str,
white
);
RenderFont(
*_fontLog,
glm::vec2(
10.f,
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
text,
white
);
}
const glm::vec4 color = [alpha, white](ScreenLog::LogLevel level) {
switch (level) {
case ghoul::logging::LogLevel::Debug:
return glm::vec4(0.f, 1.f, 0.f, alpha);
case ghoul::logging::LogLevel::Warning:
return glm::vec4(1.f, 1.f, 0.f, alpha);
case ghoul::logging::LogLevel::Error:
return glm::vec4(1.f, 0.f, 0.f, alpha);
case ghoul::logging::LogLevel::Fatal:
return glm::vec4(0.3f, 0.3f, 0.85f, alpha);
default:
return white;
}
}(e->level);
{
const glm::vec4 color = [alpha, white](ScreenLog::LogLevel level) {
switch (level) {
case ghoul::logging::LogLevel::Debug:
return glm::vec4(0.f, 1.f, 0.f, alpha);
case ghoul::logging::LogLevel::Warning:
return glm::vec4(1.f, 1.f, 0.f, alpha);
case ghoul::logging::LogLevel::Error:
return glm::vec4(1.f, 0.f, 0.f, alpha);
case ghoul::logging::LogLevel::Fatal:
return glm::vec4(0.3f, 0.3f, 0.85f, alpha);
default:
return white;
}
}(it->level);
RenderFont(
*_fontLog,
glm::vec2(
10 + 30 * _fontLog->pointSize(),
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
fmt::format("({})", lvl),
color
);
const std::string_view lvl = ghoul::to_string(it->level);
std::fill(buf.begin(), buf.end(), char(0));
char* end = fmt::format_to(buf.data(), "({})", lvl);
std::string_view levelText = std::string_view(buf.data(), end - buf.data());
RenderFont(
*_fontLog,
glm::vec2(
10 + 30 * _fontLog->pointSize(),
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
levelText,
color
);
}
RenderFont(
*_fontLog,
+6
View File
@@ -30,6 +30,7 @@
#include <ghoul/filesystem/file.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/lua/ghoul_lua.h>
#include <ghoul/misc/profiling.h>
#include <algorithm>
#include <unordered_set>
@@ -94,6 +95,8 @@ Asset::State Asset::state() const {
}
void Asset::setState(Asset::State state) {
ZoneScoped
if (_state == state) {
return;
}
@@ -188,6 +191,7 @@ void Asset::clearSynchronizations() {
void Asset::syncStateChanged(ResourceSynchronization* sync,
ResourceSynchronization::State state)
{
ZoneScoped
if (state == ResourceSynchronization::State::Resolved) {
if (!isSynchronized() && isSyncResolveReady()) {
@@ -488,6 +492,8 @@ void Asset::unloadIfUnwanted() {
}
bool Asset::initialize() {
ZoneScoped
if (isInitialized()) {
return true;
}
+25 -42
View File
@@ -35,6 +35,7 @@
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/defer.h>
#include <ghoul/misc/profiling.h>
#include "assetloader_lua.inl"
@@ -190,12 +191,6 @@ void AssetLoader::setUpAssetLuaTable(Asset* asset) {
lua_pushcclosure(*_luaState, &assetloader::require, 1);
lua_setfield(*_luaState, assetTableIndex, RequireFunctionName);
// Register request function
// Dependency request(string path)
lua_pushlightuserdata(*_luaState, asset);
lua_pushcclosure(*_luaState, &assetloader::request, 1);
lua_setfield(*_luaState, assetTableIndex, RequestFunctionName);
// Register exists function
// bool exists(string path)
lua_pushlightuserdata(*_luaState, asset);
@@ -472,14 +467,6 @@ int AssetLoader::onDeinitializeDependencyLua(Asset* dependant, Asset* dependency
return 0;
}
std::shared_ptr<Asset> AssetLoader::request(const std::string& identifier) {
std::shared_ptr<Asset> asset = getAsset(identifier);
Asset* parent = _currentAsset;
parent->request(asset);
assetRequested(parent, asset);
return asset;
}
void AssetLoader::unrequest(const std::string& identifier) {
std::shared_ptr<Asset> asset = has(identifier);
Asset* parent = _currentAsset;
@@ -497,11 +484,19 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const {
}
std::shared_ptr<Asset> AssetLoader::add(const std::string& identifier) {
ZoneScoped
setCurrentAsset(_rootAsset.get());
return request(identifier);
std::shared_ptr<Asset> asset = getAsset(identifier);
Asset* parent = _currentAsset;
parent->request(asset);
assetRequested(parent, asset);
return asset;
}
void AssetLoader::remove(const std::string& identifier) {
ZoneScoped
setCurrentAsset(_rootAsset.get());
unrequest(identifier);
}
@@ -530,6 +525,8 @@ const std::string& AssetLoader::assetRootDirectory() const {
}
void AssetLoader::callOnInitialize(Asset* asset) {
ZoneScoped
for (int init : _onInitializationFunctionRefs[asset]) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, init);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
@@ -543,7 +540,9 @@ void AssetLoader::callOnInitialize(Asset* asset) {
}
}
void AssetLoader::callOnDeinitialize(Asset * asset) {
void AssetLoader::callOnDeinitialize(Asset* asset) {
ZoneScoped
const std::vector<int>& funs = _onDeinitializationFunctionRefs[asset];
for (auto it = funs.rbegin(); it != funs.rend(); it++) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, *it);
@@ -559,6 +558,8 @@ void AssetLoader::callOnDeinitialize(Asset * asset) {
}
void AssetLoader::callOnDependencyInitialize(Asset* asset, Asset* dependant) {
ZoneScoped
for (int init : _onDependencyInitializationFunctionRefs[dependant][asset]) {
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, init);
if (lua_pcall(*_luaState, 0, 0, 0) != LUA_OK) {
@@ -577,6 +578,8 @@ void AssetLoader::callOnDependencyInitialize(Asset* asset, Asset* dependant) {
}
void AssetLoader::callOnDependencyDeinitialize(Asset* asset, Asset* dependant) {
ZoneScoped
const std::vector<int>& funs =
_onDependencyDeinitializationFunctionRefs[dependant][asset];
@@ -595,6 +598,8 @@ void AssetLoader::callOnDependencyDeinitialize(Asset* asset, Asset* dependant) {
}
int AssetLoader::localResourceLua(Asset* asset) {
ZoneScoped
ghoul::lua::checkArgumentsAndThrow(*_luaState, 1, "lua::localResourceLua");
std::string name = ghoul::lua::value<std::string>(
@@ -613,6 +618,8 @@ int AssetLoader::localResourceLua(Asset* asset) {
}
int AssetLoader::syncedResourceLua(Asset* asset) {
ZoneScoped
ghoul::lua::checkArgumentsAndThrow(*_luaState, 1, "lua::syncedResourceLua");
ghoul::Dictionary d;
@@ -633,6 +640,8 @@ int AssetLoader::syncedResourceLua(Asset* asset) {
}
void AssetLoader::setCurrentAsset(Asset* asset) {
ZoneScoped
const int top = lua_gettop(*_luaState);
_currentAsset = asset;
@@ -695,32 +704,6 @@ int AssetLoader::requireLua(Asset* dependant) {
return 2;
}
int AssetLoader::requestLua(Asset* parent) {
ghoul::lua::checkArgumentsAndThrow(*_luaState, 1, "lua::request");
const std::string assetName = luaL_checkstring(*_luaState, 1);
lua_settop(*_luaState, 0);
std::shared_ptr<Asset> child = request(assetName);
addLuaDependencyTable(parent, child.get());
// Get the dependency table
lua_rawgeti(*_luaState, LUA_REGISTRYINDEX, _assetsTableRef);
lua_getfield(*_luaState, -1, child->id().c_str());
lua_getfield(*_luaState, -1, DependantsTableName);
lua_getfield(*_luaState, -1, parent->id().c_str());
const int dependencyTableIndex = lua_gettop(*_luaState);
lua_pushvalue(*_luaState, dependencyTableIndex);
lua_replace(*_luaState, 1);
lua_settop(*_luaState, 1);
ghoul_assert(lua_gettop(*_luaState) == 1, "Incorrect number of items left on stack");
return 1;
}
int AssetLoader::existsLua(Asset*) {
ghoul::lua::checkArgumentsAndThrow(*_luaState, 1, "lua::exists");
+1 -12
View File
@@ -71,7 +71,7 @@ int onDeinitializeDependency(lua_State* state) {
}
/**
* Requires rependency
* Requires dependency
* Gives access to
* AssetTable: Exported lua values
* Dependency: ...
@@ -82,17 +82,6 @@ int require(lua_State* state) {
return asset->loader()->requireLua(asset);
}
/**
* Requests rependency
* Gives access to
* Dependency: ...
* Usage: Dependency = asset.import(string assetIdentifier)
*/
int request(lua_State* state) {
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
return asset->loader()->requestLua(asset);
}
int exists(lua_State* state) {
Asset* asset = reinterpret_cast<Asset*>(lua_touserdata(state, lua_upvalueindex(1)));
return asset->loader()->existsLua(asset);
+4
View File
@@ -43,6 +43,8 @@ AssetManager::AssetManager(ghoul::lua::LuaState* state, std::string assetRootDir
{}
void AssetManager::initialize() {
ZoneScoped
_assetLoader.addAssetListener(this);
_assetLoader.rootAsset().initialize();
}
@@ -58,6 +60,7 @@ bool AssetManager::update() {
// Add assets
for (const std::pair<const std::string, bool>& c : _pendingStateChangeCommands) {
ZoneScopedN("(add) Pending State Change")
const std::string& path = c.first;
const bool add = c.second;
if (add) {
@@ -67,6 +70,7 @@ bool AssetManager::update() {
}
// Remove assets
for (const std::pair<const std::string, bool>& c : _pendingStateChangeCommands) {
ZoneScopedN("(remove) Pending State change")
const std::string& path = c.first;
const bool remove = !c.second;
if (remove && _assetLoader.has(path)) {
+49 -4
View File
@@ -45,6 +45,7 @@ namespace {
constexpr const char* headerProperty = "#Property";
constexpr const char* headerKeybinding = "#Keybinding";
constexpr const char* headerTime = "#Time";
constexpr const char* headerDeltaTimes = "#DeltaTimes";
constexpr const char* headerCamera = "#Camera";
constexpr const char* headerMarkNodes = "#MarkNodes";
constexpr const char* headerAdditionalScripts = "#AdditionalScripts";
@@ -91,6 +92,7 @@ namespace {
Property,
Keybinding,
Time,
DeltaTimes,
Camera,
MarkNodes,
AdditionalScripts
@@ -104,6 +106,7 @@ namespace {
if (line == headerProperty) { return Section::Property; }
if (line == headerKeybinding) { return Section::Keybinding; }
if (line == headerTime) { return Section::Time; }
if (line == headerDeltaTimes) { return Section::DeltaTimes; }
if (line == headerCamera) { return Section::Camera; }
if (line == headerMarkNodes) { return Section::MarkNodes; }
if (line == headerAdditionalScripts) { return Section::AdditionalScripts; }
@@ -318,6 +321,18 @@ namespace {
return time;
}
[[ nodiscard ]] double parseDeltaTime(const std::string& line, int lineNumber) {
try {
return std::stod(line);
}
catch (const std::invalid_argument&) {
throw ProfileParsingError(
lineNumber,
fmt::format("Expected a number for delta time entry, got '{}'", line)
);
}
}
[[ nodiscard ]] Profile::CameraType parseCamera(const std::string& line, int lineNumber) {
std::vector<std::string> fields = ghoul::tokenizeString(line, '\t');
Profile::CameraType camera = [&](const std::string& type) ->
@@ -454,7 +469,7 @@ namespace {
} // namespace
void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& rootOwner,
const std::string& currentTime,
std::string currentTime,
interaction::NavigationHandler::NavigationState navState)
{
version = Profile::CurrentVersion;
@@ -476,10 +491,14 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
// add current time to profile file
//
Time t;
t.time = currentTime;
t.time = std::move(currentTime);
t.type = Time::Type::Absolute;
time = std::move(t);
// Delta times
std::vector<double> dts = global::timeManager.deltaTimeSteps();
deltaTimes = std::move(dts);
// Camera
CameraNavState c;
@@ -498,6 +517,8 @@ void Profile::setIgnoreUpdates(bool ignoreUpdates) {
}
void Profile::addAsset(const std::string& path) {
ZoneScoped
if (_ignoreUpdates) {
return;
}
@@ -519,13 +540,15 @@ void Profile::addAsset(const std::string& path) {
}
void Profile::removeAsset(const std::string& path) {
ZoneScoped
if (_ignoreUpdates) {
return;
}
const auto it = std::find_if(
assets.begin(),
assets.end(),
assets.cbegin(),
assets.cend(),
[path](const Asset& a) { return a.path == path; }
);
@@ -648,6 +671,13 @@ std::string Profile::serialize() const {
}
}
if (!deltaTimes.empty()) {
output += fmt::format("\n{}\n", headerDeltaTimes);
for (const double d : deltaTimes) {
output += fmt::format("{}\n", d);
}
}
if (camera.has_value()) {
output += fmt::format("\n{}\n", headerCamera);
output += std::visit(
@@ -870,6 +900,12 @@ Profile::Profile(const std::vector<std::string>& content) {
time = parseTime(line, lineNum);
foundTime = true;
break;
case Section::DeltaTimes:
{
const double d = parseDeltaTime(line, lineNum);
deltaTimes.push_back(d);
break;
}
case Section::Camera:
if (foundCamera) {
throw ProfileParsingError(
@@ -981,6 +1017,15 @@ std::string Profile::convertToScene() const {
throw ghoul::MissingCaseException();
}
// Delta Times
{
std::string times;
for (const double d : deltaTimes) {
times += fmt::format("{} ,", d);
}
output += fmt::format("openspace.time.setDeltaTimeSteps({{ {} }});\n", times);
}
// Mark Nodes
{
std::string nodes;
+1 -1
View File
@@ -80,7 +80,7 @@ int saveSettingsToProfile(lua_State* L) {
}
const properties::PropertyOwner& root = global::rootPropertyOwner;
std::string currentTime = global::timeManager.time().ISO8601();
std::string currentTime = std::string(global::timeManager.time().ISO8601());
interaction::NavigationHandler::NavigationState navState =
global::navigationHandler.navigationState();
global::profile.saveCurrentSettingsToProfile(root, currentTime, navState);
+18 -18
View File
@@ -467,12 +467,16 @@ void SceneGraphNode::update(const UpdateData& data) {
newUpdateData.modelTransform.translation
);
glm::dmat4 rotation = glm::dmat4(newUpdateData.modelTransform.rotation);
glm::dmat4 scaling = glm::scale(glm::dmat4(1.0), newUpdateData.modelTransform.scale);
glm::dmat4 scaling = glm::scale(
glm::dmat4(1.0),
newUpdateData.modelTransform.scale
);
_modelTransformCached = translation * rotation * scaling;
_inverseModelTransformCached = glm::inverse(_modelTransformCached);
if (_renderable && _renderable->isReady()) {
if (_renderable && _renderable->isReady() &&
(_renderable->isEnabled() || _renderable->shouldUpdateIfDisabled()))
{
_renderable->update(newUpdateData);
}
}
@@ -485,17 +489,6 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
return;
}
RenderData newData = {
data.camera,
data.time,
data.renderBinMask,
{ _worldPositionCached, _worldRotationCached, _worldScaleCached }
};
if (!isTimeFrameActive(data.time)) {
return;
}
const bool visible = _renderable && _renderable->isVisible() &&
_renderable->isReady() && _renderable->isEnabled() &&
_renderable->matchesRenderBinMask(data.renderBinMask);
@@ -504,9 +497,20 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) {
return;
}
if (!isTimeFrameActive(data.time)) {
return;
}
{
TracyGpuZone("Render")
RenderData newData = {
data.camera,
data.time,
data.renderBinMask,
{ _worldPositionCached, _worldRotationCached, _worldScaleCached }
};
_renderable->render(newData, tasks);
if (_computeScreenSpaceValues) {
computeScreenSpaceData(newData);
@@ -767,10 +771,6 @@ glm::dmat4 SceneGraphNode::modelTransform() const {
return _modelTransformCached;
}
glm::dmat4 SceneGraphNode::inverseModelTransform() const {
return _inverseModelTransformCached;
}
glm::dvec3 SceneGraphNode::worldScale() const {
return _worldScaleCached;
}
+3 -1
View File
@@ -28,8 +28,8 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/scene/asset.h>
#include <openspace/scene/assetmanager.h>
#include <ghoul/fmt.h>
#include <ghoul/misc/profiling.h>
#include <sstream>
namespace openspace {
@@ -45,6 +45,8 @@ SceneLicenseWriter::SceneLicenseWriter()
{}
std::string SceneLicenseWriter::generateJson() const {
ZoneScoped
std::stringstream json;
json << "[";
+5 -5
View File
@@ -26,14 +26,14 @@
#include <algorithm>
using std::string;
namespace openspace {
ScreenLog::ScreenLog(std::chrono::seconds timeToLive, LogLevel logLevel)
: _timeToLive(std::move(timeToLive))
, _logLevel(logLevel)
{}
{
_entries.reserve(64);
}
void ScreenLog::removeExpiredEntries() {
std::lock_guard<std::mutex> guard(_mutex);
@@ -55,8 +55,8 @@ void ScreenLog::log(LogLevel level, std::string_view category, std::string_view
level,
std::chrono::steady_clock::now(),
Log::timeString(),
static_cast<std::string>(category),
static_cast<std::string>(message)
std::string(category),
std::string(message)
});
}
}
+17 -32
View File
@@ -43,18 +43,6 @@ namespace {
// as the maximum message length
constexpr const unsigned SpiceErrorBufferSize = 1841;
// This method checks if one of the previous SPICE methods has failed. If it has, an
// exception with the SPICE error message is thrown
// If an error occurred, true is returned, otherwise, false
void throwSpiceError(const std::string& errorMessage) {
if (openspace::SpiceManager::ref().exceptionHandling()) {
char buffer[SpiceErrorBufferSize];
getmsg_c("LONG", SpiceErrorBufferSize, buffer);
reset_c();
throw openspace::SpiceManager::SpiceException(errorMessage + ": " + buffer);
}
}
const char* toString(openspace::SpiceManager::FieldOfViewMethod m) {
using SM = openspace::SpiceManager;
switch (m) {
@@ -196,6 +184,18 @@ SpiceManager& SpiceManager::ref() {
return *_instance;
}
// This method checks if one of the previous SPICE methods has failed. If it has, an
// exception with the SPICE error message is thrown
// If an error occurred, true is returned, otherwise, false
void throwSpiceError(const std::string& errorMessage) {
if (openspace::SpiceManager::ref().exceptionHandling()) {
char buffer[SpiceErrorBufferSize];
getmsg_c("LONG", SpiceErrorBufferSize, buffer);
reset_c();
throw openspace::SpiceManager::SpiceException(errorMessage + ": " + buffer);
}
}
SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
ghoul_assert(!filePath.empty(), "Empty file path");
ghoul_assert(
@@ -474,33 +474,18 @@ double SpiceManager::spacecraftClockToET(const std::string& craft, double craftT
double SpiceManager::ephemerisTimeFromDate(const std::string& timeString) const {
ghoul_assert(!timeString.empty(), "Empty timeString");
return ephemerisTimeFromDate(timeString.c_str());
}
double SpiceManager::ephemerisTimeFromDate(const char* timeString) const {
double et;
str2et_c(timeString.c_str(), &et);
str2et_c(timeString, &et);
if (failed_c()) {
throwSpiceError(fmt::format("Error converting date '{}'", timeString));
}
return et;
}
std::string SpiceManager::dateFromEphemerisTime(double ephemerisTime,
const std::string& formatString) const
{
ghoul_assert(!formatString.empty(), "Format is empty");
constexpr const int BufferSize = 256;
SpiceChar buffer[BufferSize];
timout_c(ephemerisTime, formatString.c_str(), BufferSize - 1, buffer);
if (failed_c()) {
throwSpiceError(
fmt::format("Error converting ephemeris time '{}' to date with format '{}'",
ephemerisTime, formatString
)
);
}
return std::string(buffer);
}
glm::dvec3 SpiceManager::targetPosition(const std::string& target,
const std::string& observer,
const std::string& referenceFrame,
+4 -1
View File
@@ -24,6 +24,7 @@
#include <openspace/util/synchronizationwatcher.h>
#include <ghoul/misc/profiling.h>
#include <algorithm>
namespace openspace {
@@ -75,8 +76,9 @@ void SynchronizationWatcher::unwatchSynchronization(WatchHandle watchHandle) {
), _pendingNotifications.end());
}
void SynchronizationWatcher::notify() {
ZoneScoped
std::vector<NotificationData> notifications;
{
std::lock_guard guard(_mutex);
@@ -85,6 +87,7 @@ void SynchronizationWatcher::notify() {
}
for (const NotificationData& n : notifications) {
ZoneScopedN("Notification")
std::shared_ptr<ResourceSynchronization> sync = n.synchronization.lock();
if (!sync) {
continue;
+103 -33
View File
@@ -24,12 +24,15 @@
#include <openspace/util/time.h>
#include <openspace/engine/globals.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/memorymanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/syncbuffer.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/profiling.h>
#include <mutex>
#include <string_view>
@@ -42,8 +45,16 @@ double Time::convertTime(const std::string& time) {
return SpiceManager::ref().ephemerisTimeFromDate(time);
}
double Time::convertTime(const char* time) {
return SpiceManager::ref().ephemerisTimeFromDate(time);
}
Time::Time(double secondsJ2000) : _time(secondsJ2000) {}
Time::Time(const std::string& time) :
_time(SpiceManager::ref().ephemerisTimeFromDate(time))
{}
Time Time::now() {
Time now;
time_t secondsSince1970;
@@ -70,36 +81,42 @@ double Time::advanceTime(double delta) {
return _time;
}
void Time::setTime(std::string time) {
_time = SpiceManager::ref().ephemerisTimeFromDate(std::move(time));
void Time::setTime(const std::string& time) {
_time = SpiceManager::ref().ephemerisTimeFromDate(time);
}
std::string Time::UTC() const {
return SpiceManager::ref().dateFromEphemerisTime(_time);
void Time::setTime(const char* time) {
_time = SpiceManager::ref().ephemerisTimeFromDate(time);
}
std::string Time::ISO8601() const {
std::string datetime = SpiceManager::ref().dateFromEphemerisTime(_time);
std::string_view month = std::string_view(datetime).substr(5, 3);
std::string_view Time::UTC() const {
constexpr const char Format[] = "YYYY MON DDTHR:MN:SC.### ::RND";
char* b = reinterpret_cast<char*>(global::memoryManager.TemporaryMemory.allocate(32));
std::memset(b, 0, 32);
std::string_view mm = [](std::string_view month) {
if (month == "JAN") { return "-01-"; }
else if (month == "FEB") { return "-02-"; }
else if (month == "MAR") { return "-03-"; }
else if (month == "APR") { return "-04-"; }
else if (month == "MAY") { return "-05-"; }
else if (month == "JUN") { return "-06-"; }
else if (month == "JUL") { return "-07-"; }
else if (month == "AUG") { return "-08-"; }
else if (month == "SEP") { return "-09-"; }
else if (month == "OCT") { return "-10-"; }
else if (month == "NOV") { return "-11-"; }
else if (month == "DEC") { return "-12-"; }
else { throw ghoul::MissingCaseException(); }
}(month);
SpiceManager::ref().dateFromEphemerisTime(_time, b, 32, Format);
datetime.replace(4, 5, mm);
return datetime;
return std::string_view(b, 32);
}
std::string_view Time::ISO8601() const {
ZoneScoped
constexpr const char Format[] = "YYYY-MM-DDTHR:MN:SC.###";
constexpr const int S = sizeof(Format);
char* b = reinterpret_cast<char*>(global::memoryManager.TemporaryMemory.allocate(S));
std::memset(b, 0, S);
SpiceManager::ref().dateFromEphemerisTime(_time, b, S, Format);
return std::string_view(b, S);
}
void Time::ISO8601(char* buffer) const {
constexpr const char Format[] = "YYYY-MM-DDTHR:MN:SC.###";
constexpr const int S = sizeof(Format) + 1;
std::memset(buffer, 0, S);
SpiceManager::ref().dateFromEphemerisTime(_time, buffer, S, Format);
}
scripting::LuaLibrary Time::luaLibrary() {
@@ -126,6 +143,16 @@ scripting::LuaLibrary Time::luaLibrary() {
"Sets the amount of simulation time that happens "
"in one second of real time"
},
{
"setDeltaTimeSteps",
&luascriptfunctions::time_setDeltaTimeSteps,
{},
"List of numbers",
"Sets the list of discrete delta time steps for the simulation speed "
"that can be quickly jumped between. The list will be sorted to be in "
"increasing order. A negative verison of each specified time step will "
"be added per default as well."
},
{
"deltaTime",
&luascriptfunctions::time_deltaTime,
@@ -166,31 +193,74 @@ scripting::LuaLibrary Time::luaLibrary() {
&luascriptfunctions::time_interpolateTimeRelative,
{},
"number [, number]",
"Increments the current simulation time "
"by the specified number of seconds."
"Increments the current simulation time by the specified number of "
"seconds. If a second input value is given, the interpolation is done "
"over the specified number of seconds."
},
{
"interpolateDeltaTime",
&luascriptfunctions::time_interpolateDeltaTime,
{},
"number",
"Sets the amount of simulation time that happens "
"in one second of real time"
"number [, number]",
"Sets the amount of simulation time that happens in one second of real "
"time. If a second input value is given, the interpolation is done "
"over the specified number of seconds."
},
{
"setNextDeltaTimeStep",
&luascriptfunctions::time_setNextDeltaTimeStep,
{},
"",
"Immediately set the simulation speed to the first delta time step in "
"the list that is larger than the current choice of simulation speed, "
"if any."
},
{
"setPreviousDeltaTimeStep",
&luascriptfunctions::time_setPreviousDeltaTimeStep,
{},
"",
"Immediately set the simulation speed to the first delta time step in "
"the list that is smaller than the current choice of simulation speed. "
"if any."
},
{
"interpolateNextDeltaTimeStep",
&luascriptfunctions::time_interpolateNextDeltaTimeStep,
{},
"[number]",
"Interpolate the simulation speed to the first delta time step in the "
"list that is larger than the current simulation speed, if any. If an "
"input value is given, the interpolation is done over the specified "
"number of seconds."
},
{
"interpolatePreviousDeltaTimeStep",
&luascriptfunctions::time_interpolatePreviousDeltaTimeStep,
{},
"[number]",
"Interpolate the simulation speed to the first delta time step in the "
"list that is smaller than the current simulation speed, if any. If an "
"input value is given, the interpolation is done over the specified "
"number of seconds."
},
{
"interpolatePause",
&luascriptfunctions::time_interpolatePause,
{},
"bool",
"Pauses the simulation time or restores the delta time"
"bool [, number]",
"Pauses the simulation time or restores the delta time. If a second "
"input value is given, the interpolation is done over the specified "
"number of seconds."
},
{
"interpolateTogglePause",
&luascriptfunctions::time_interpolateTogglePause,
{},
"",
"[number]",
"Toggles the pause function, i.e. temporarily setting the delta time to 0"
" and restoring it afterwards"
" and restoring it afterwards. If an input value is given, the "
"interpolation is done over the specified number of seconds."
},
{
"currentTime",
+152 -2
View File
@@ -69,6 +69,156 @@ int time_setDeltaTime(lua_State* L) {
return 0;
}
/**
* \ingroup LuaScripts
* interpolateNextDeltaTimeStep(list of numbers):
* Sets the list of discrete delta time steps for the simulation speed.
*/
int time_setDeltaTimeSteps(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::time_setDeltaTimeSteps");
ghoul::Dictionary dict;
ghoul::lua::luaDictionaryFromState(L, dict);
const size_t nItems = dict.size();
std::vector<double> inputDeltaTimes;
inputDeltaTimes.reserve(nItems);
for (size_t i = 1; i <= nItems; ++i) {
std::string key = std::to_string(i);
if (dict.hasKeyAndValue<double>(key)) {
const double time = dict.value<double>(key);
inputDeltaTimes.push_back(time);
}
else {
const char* msg = lua_pushfstring(L,
"Error setting delta times. Expected list of numbers.");
return ghoul::lua::luaError(L, fmt::format("bad argument ({})", msg));
}
}
lua_pop(L, 1);
global::timeManager.setDeltaTimeSteps(inputDeltaTimes);
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* setNextDeltaTimeStep():
* Immediately set the simulation speed to the first delta time step in the list that is
* larger than the current choice of simulation speed, if any.
*/
int time_setNextDeltaTimeStep(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_setNextDeltaTimeStep");
global::timeManager.setNextDeltaTimeStep();
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* setPreviousDeltaTimeStep():
* Immediately set the simulation speed to the first delta time step in the list that is
* smaller than the current choice of simulation speed, if any.
*/
int time_setPreviousDeltaTimeStep(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_setPreviousDeltaTimeStep");
global::timeManager.setPreviousDeltaTimeStep();
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* interpolateNextDeltaTimeStep([interpolationDuration]):
* Interpolate the simulation speed to the next delta time step in the list. If an input
* value is given, the interpolation is done over the specified number of seconds.
* If interpolationDuration is not provided, the interpolation time will be based on the
* `defaultDeltaTimeInterpolationDuration` property of the TimeManager.
*/
int time_interpolateNextDeltaTimeStep(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(
L,
{ 0, 1 },
"lua::time_interpolateNextDeltaTimeStep"
);
double interpolationDuration =
global::timeManager.defaultDeltaTimeInterpolationDuration();
const int nArguments = lua_gettop(L);
if (nArguments == 1) {
const bool durationIsNumber = (lua_isnumber(L, 1) != 0);
if (!durationIsNumber) {
lua_settop(L, 0);
const char* msg = lua_pushfstring(
L,
"%s expected, got %s",
lua_typename(L, LUA_TNUMBER),
luaL_typename(L, -1)
);
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
interpolationDuration = lua_tonumber(L, 1);
}
global::timeManager.interpolateNextDeltaTimeStep(interpolationDuration);
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* interpolatePreviousDeltaTimeStep([interpolationDuration]):
* Interpolate the simulation speed to the previous delta time step in the list. If an
* input value is given, the interpolation is done over the specified number of seconds.
* If interpolationDuration is not provided, the interpolation time will be based on the
* `defaultDeltaTimeInterpolationDuration` property of the TimeManager.
*/
int time_interpolatePreviousDeltaTimeStep(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(
L,
{ 0, 1 },
"lua::time_interpolatePreviousDeltaTimeStep"
);
double interpolationDuration =
global::timeManager.defaultDeltaTimeInterpolationDuration();
const int nArguments = lua_gettop(L);
if (nArguments == 1) {
const bool durationIsNumber = (lua_isnumber(L, 1) != 0);
if (!durationIsNumber) {
lua_settop(L, 0);
const char* msg = lua_pushfstring(
L,
"%s expected, got %s",
lua_typename(L, LUA_TNUMBER),
luaL_typename(L, -1)
);
return luaL_error(L, "bad argument #%d (%s)", 1, msg);
}
interpolationDuration = lua_tonumber(L, 1);
}
global::timeManager.interpolatePreviousDeltaTimeStep(interpolationDuration);
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* time_interpolateDeltaTime(number [, number]):
@@ -506,7 +656,7 @@ int time_interpolateTimeRelative(lua_State* L) {
* It is returned by calling the Time::currentTime method.
*/
int time_currentTime(lua_State* L) {
lua_pushnumber(L, global::timeManager.time().j2000Seconds());
ghoul::lua::push(L, global::timeManager.time().j2000Seconds());
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
@@ -518,7 +668,7 @@ int time_currentTime(lua_State* L) {
* timezone by calling the Time::UTC method
*/
int time_currentTimeUTC(lua_State* L) {
lua_pushstring(L, global::timeManager.time().UTC().c_str());
ghoul::lua::push(L, global::timeManager.time().UTC());
ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
return 1;
}
+136
View File
@@ -139,9 +139,11 @@ void TimeManager::preSynchronization(double dt) {
const double newTime = time().j2000Seconds();
if (newTime != _lastTime) {
ZoneScopedN("newTime != _lastTime")
using K = const CallbackHandle;
using V = TimeChangeCallback;
for (const std::pair<K, V>& it : _timeChangeCallbacks) {
ZoneScopedN("tcc")
it.second();
}
}
@@ -149,16 +151,27 @@ void TimeManager::preSynchronization(double dt) {
_timePaused != _lastTimePaused ||
_targetDeltaTime != _lastTargetDeltaTime)
{
ZoneScopedN("delta time changed")
using K = const CallbackHandle;
using V = TimeChangeCallback;
for (const std::pair<K, V>& it : _deltaTimeChangeCallbacks) {
ZoneScopedN("dtcc")
it.second();
}
}
if (_deltaTimeStepsChanged) {
using K = const CallbackHandle;
using V = TimeChangeCallback;
for (const std::pair<K, V>& it : _deltaTimeStepsChangeCallbacks) {
it.second();
}
}
if (_timelineChanged) {
ZoneScopedN("timeline changed")
using K = const CallbackHandle;
using V = TimeChangeCallback;
for (const std::pair<K, V>& it : _timelineChangeCallbacks) {
ZoneScopedN("tlcc")
it.second();
}
}
@@ -167,6 +180,7 @@ void TimeManager::preSynchronization(double dt) {
_lastDeltaTime = _deltaTime;
_lastTargetDeltaTime = _targetDeltaTime;
_lastTimePaused = _timePaused;
_deltaTimeStepsChanged = false;
_timelineChanged = false;
}
@@ -380,6 +394,26 @@ void TimeManager::setDeltaTime(double deltaTime) {
interpolateDeltaTime(deltaTime, 0.0);
}
void TimeManager::setDeltaTimeSteps(std::vector<double> deltaTimes) {
std::vector<double> negatives;
negatives.reserve(deltaTimes.size());
std::transform(
deltaTimes.begin(),
deltaTimes.end(),
std::back_inserter(negatives),
[](double d) { return -d; }
);
deltaTimes.reserve(2 * deltaTimes.size());
deltaTimes.insert(deltaTimes.end(), negatives.begin(), negatives.end());
std::sort(deltaTimes.begin(), deltaTimes.end());
deltaTimes.erase(std::unique(deltaTimes.begin(), deltaTimes.end()), deltaTimes.end());
_deltaTimeSteps = std::move(deltaTimes);
_deltaTimeStepsChanged = true;
}
size_t TimeManager::nKeyframes() const {
return _timeline.nKeyframes();
}
@@ -413,6 +447,14 @@ TimeManager::CallbackHandle TimeManager::addDeltaTimeChangeCallback(TimeChangeCa
return handle;
}
TimeManager::CallbackHandle
TimeManager::addDeltaTimeStepsChangeCallback(TimeChangeCallback cb)
{
CallbackHandle handle = _nextCallbackHandle++;
_deltaTimeStepsChangeCallbacks.emplace_back(handle, std::move(cb));
return handle;
}
TimeManager::CallbackHandle TimeManager::addTimeJumpCallback(TimeChangeCallback cb) {
CallbackHandle handle = _nextCallbackHandle++;
_timeJumpCallbacks.emplace_back(handle, std::move(cb));
@@ -460,6 +502,23 @@ void TimeManager::removeDeltaTimeChangeCallback(CallbackHandle handle) {
_deltaTimeChangeCallbacks.erase(it);
}
void TimeManager::removeDeltaTimeStepsChangeCallback(CallbackHandle handle) {
const auto it = std::find_if(
_deltaTimeStepsChangeCallbacks.begin(),
_deltaTimeStepsChangeCallbacks.end(),
[handle](const std::pair<CallbackHandle, std::function<void()>>& cb) {
return cb.first == handle;
}
);
ghoul_assert(
it != _deltaTimeStepsChangeCallbacks.end(),
"handle must be a valid callback handle"
);
_deltaTimeStepsChangeCallbacks.erase(it);
}
void TimeManager::triggerPlaybackStart() {
_playbackModeEnabled = true;
}
@@ -526,6 +585,10 @@ double TimeManager::targetDeltaTime() const {
return _targetDeltaTime;
}
std::vector<double> TimeManager::deltaTimeSteps() const {
return _deltaTimeSteps;
}
void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolationDuration)
{
if (newDeltaTime == _targetDeltaTime) {
@@ -553,6 +616,79 @@ void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolation
addKeyframe(now + interpolationDuration, futureKeyframe);
}
std::optional<double> TimeManager::nextDeltaTimeStep() {
if (!hasNextDeltaTimeStep()) {
return std::nullopt;
}
std::vector<double>::iterator nextStepIterator = std::upper_bound(
_deltaTimeSteps.begin(),
_deltaTimeSteps.end(),
_targetDeltaTime
);
if (nextStepIterator == _deltaTimeSteps.end()) {
return std::nullopt; // should not get here
}
return *nextStepIterator;
}
std::optional<double> TimeManager::previousDeltaTimeStep() {
if (!hasPreviousDeltaTimeStep()) {
return std::nullopt;
}
std::vector<double>::iterator lowerBoundIterator = std::lower_bound(
_deltaTimeSteps.begin(),
_deltaTimeSteps.end(),
_targetDeltaTime
);
if (lowerBoundIterator == _deltaTimeSteps.begin()) {
return std::nullopt; // should not get here
}
std::vector<double>::iterator prevStepIterator = lowerBoundIterator - 1;
return *prevStepIterator;
}
bool TimeManager::hasNextDeltaTimeStep() const {
if (_deltaTimeSteps.empty())
return false;
return _targetDeltaTime < _deltaTimeSteps.back();
}
bool TimeManager::hasPreviousDeltaTimeStep() const {
if (_deltaTimeSteps.empty())
return false;
return _targetDeltaTime > _deltaTimeSteps.front();
}
void TimeManager::setNextDeltaTimeStep() {
interpolateNextDeltaTimeStep(0);
}
void TimeManager::setPreviousDeltaTimeStep() {
interpolatePreviousDeltaTimeStep(0);
}
void TimeManager::interpolateNextDeltaTimeStep(double durationSeconds) {
if (!hasNextDeltaTimeStep())
return;
double nextDeltaTime = nextDeltaTimeStep().value();
interpolateDeltaTime(nextDeltaTime, durationSeconds);
}
void TimeManager::interpolatePreviousDeltaTimeStep(double durationSeconds) {
if (!hasPreviousDeltaTimeStep())
return;
double previousDeltaTime = previousDeltaTimeStep().value();
interpolateDeltaTime(previousDeltaTime, durationSeconds);
}
void TimeManager::setPause(bool pause) {
interpolatePause(pause, 0);
}