mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-22 11:18:22 -05:00
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:
@@ -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));
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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())
|
||||
));
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 << "[";
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user