mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-30 07:49:31 -05:00
Merging Master
This commit is contained in:
@@ -58,6 +58,9 @@ namespace openspace {
|
||||
void registerCoreClasses(documentation::DocumentationEngine& engine) {
|
||||
engine.addDocumentation(LogFactoryDocumentation());
|
||||
engine.addDocumentation(Mission::Documentation());
|
||||
engine.addDocumentation(
|
||||
interaction::NavigationHandler::NavigationState::Documentation()
|
||||
);
|
||||
engine.addDocumentation(Renderable::Documentation());
|
||||
engine.addDocumentation(Rotation::Documentation());
|
||||
engine.addDocumentation(Scale::Documentation());
|
||||
|
||||
@@ -811,7 +811,6 @@ void OpenSpaceEngine::deinitialize() {
|
||||
|
||||
ghoul::logging::LogManager::deinitialize();
|
||||
|
||||
ghoul::deinitialize();
|
||||
LTRACE("deinitialize(end)");
|
||||
|
||||
|
||||
@@ -1013,8 +1012,6 @@ void OpenSpaceEngine::preSynchronization() {
|
||||
}
|
||||
|
||||
global::renderEngine.updateScene();
|
||||
//_navigationHandler->updateCamera(dt);
|
||||
|
||||
|
||||
if (_scene) {
|
||||
Camera* camera = _scene->camera();
|
||||
|
||||
@@ -27,14 +27,17 @@
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
#include <openspace/network/parallelpeer.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
@@ -43,7 +46,11 @@ namespace {
|
||||
constexpr const char* KeyAnchor = "Anchor";
|
||||
constexpr const char* KeyAim = "Aim";
|
||||
constexpr const char* KeyPosition = "Position";
|
||||
constexpr const char* KeyRotation = "Rotation";
|
||||
constexpr const char* KeyUp = "Up";
|
||||
constexpr const char* KeyYaw = "Yaw";
|
||||
constexpr const char* KeyPitch = "Pitch";
|
||||
constexpr const char* KeyReferenceFrame = "ReferenceFrame";
|
||||
const double Epsilon = 1E-7;
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo KeyFrameInfo = {
|
||||
"UseKeyFrameInteraction",
|
||||
@@ -51,24 +58,101 @@ namespace {
|
||||
"If this is set to 'true' the entire interaction is based off key frames rather "
|
||||
"than using the mouse interaction."
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "navigationhandler_lua.inl"
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
|
||||
ghoul::Dictionary
|
||||
openspace::interaction::NavigationHandler::NavigationState::dictionary() const
|
||||
{
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, position);
|
||||
cameraDict.setValue(KeyAnchor, anchor);
|
||||
|
||||
if (anchor != referenceFrame) {
|
||||
cameraDict.setValue(KeyReferenceFrame, referenceFrame);
|
||||
}
|
||||
if (!aim.empty()) {
|
||||
cameraDict.setValue(KeyAim, aim);
|
||||
}
|
||||
if (up.has_value()) {
|
||||
cameraDict.setValue(KeyUp, up.value());
|
||||
|
||||
if (std::abs(yaw) > Epsilon) {
|
||||
cameraDict.setValue(KeyYaw, yaw);
|
||||
}
|
||||
if (std::abs(pitch) > Epsilon) {
|
||||
cameraDict.setValue(KeyPitch, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
return cameraDict;
|
||||
}
|
||||
|
||||
openspace::interaction::NavigationHandler::NavigationState::NavigationState(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
const bool hasAnchor = dictionary.hasValue<std::string>(KeyAnchor);
|
||||
const bool hasPosition = dictionary.hasValue<glm::dvec3>(KeyPosition);
|
||||
if (!hasAnchor || !hasPosition) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Position and Anchor need to be defined for navigation dictionary."
|
||||
);
|
||||
}
|
||||
|
||||
anchor = dictionary.value<std::string>(KeyAnchor);
|
||||
position = dictionary.value<glm::dvec3>(KeyPosition);
|
||||
|
||||
if (dictionary.hasValue<std::string>(KeyReferenceFrame)) {
|
||||
referenceFrame = dictionary.value<std::string>(KeyReferenceFrame);
|
||||
}
|
||||
else {
|
||||
referenceFrame = anchor;
|
||||
}
|
||||
if (dictionary.hasValue<std::string>(KeyAim)) {
|
||||
aim = dictionary.value<std::string>(KeyAim);
|
||||
}
|
||||
|
||||
if (dictionary.hasValue<glm::dvec3>(KeyUp)) {
|
||||
up = dictionary.value<glm::dvec3>(KeyUp);
|
||||
|
||||
if (dictionary.hasValue<double>(KeyYaw)) {
|
||||
yaw = dictionary.value<double>(KeyYaw);
|
||||
}
|
||||
if (dictionary.hasValue<double>(KeyPitch)) {
|
||||
pitch = dictionary.value<double>(KeyPitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openspace::interaction::NavigationHandler::NavigationState::NavigationState(
|
||||
std::string anchor,
|
||||
std::string aim,
|
||||
std::string referenceFrame,
|
||||
glm::dvec3 position,
|
||||
std::optional<glm::dvec3> up,
|
||||
double yaw,
|
||||
double pitch)
|
||||
: anchor(std::move(anchor))
|
||||
, aim(std::move(aim))
|
||||
, referenceFrame(std::move(referenceFrame))
|
||||
, position(std::move(position))
|
||||
, up(std::move(up))
|
||||
, yaw(yaw)
|
||||
, pitch(pitch)
|
||||
{}
|
||||
|
||||
NavigationHandler::NavigationHandler()
|
||||
: properties::PropertyOwner({ "NavigationHandler" })
|
||||
, _useKeyFrameInteraction(KeyFrameInfo, false)
|
||||
{
|
||||
|
||||
_inputState = std::make_unique<InputState>();
|
||||
_orbitalNavigator = std::make_unique<OrbitalNavigator>();
|
||||
_keyframeNavigator = std::make_unique<KeyframeNavigator>();
|
||||
|
||||
// Add the properties
|
||||
addProperty(_useKeyFrameInteraction);
|
||||
addPropertySubOwner(*_orbitalNavigator);
|
||||
addPropertySubOwner(_orbitalNavigator);
|
||||
}
|
||||
|
||||
NavigationHandler::~NavigationHandler() {} // NOLINT
|
||||
@@ -90,19 +174,25 @@ void NavigationHandler::deinitialize() {
|
||||
|
||||
void NavigationHandler::setCamera(Camera* camera) {
|
||||
_camera = camera;
|
||||
_orbitalNavigator->setCamera(camera);
|
||||
_orbitalNavigator.setCamera(camera);
|
||||
}
|
||||
|
||||
const OrbitalNavigator& NavigationHandler::orbitalNavigator() const {
|
||||
return *_orbitalNavigator;
|
||||
void NavigationHandler::setNavigationStateNextFrame(
|
||||
NavigationHandler::NavigationState state)
|
||||
{
|
||||
_pendingNavigationState = std::move(state);
|
||||
}
|
||||
|
||||
OrbitalNavigator& NavigationHandler::orbitalNavigator() {
|
||||
return *_orbitalNavigator;
|
||||
return _orbitalNavigator;
|
||||
}
|
||||
|
||||
KeyframeNavigator& NavigationHandler::keyframeNavigator() const {
|
||||
return *_keyframeNavigator;
|
||||
const OrbitalNavigator& NavigationHandler::orbitalNavigator() const {
|
||||
return _orbitalNavigator;
|
||||
}
|
||||
|
||||
KeyframeNavigator& NavigationHandler::keyframeNavigator() {
|
||||
return _keyframeNavigator;
|
||||
}
|
||||
|
||||
bool NavigationHandler::isKeyFrameInteractionEnabled() const {
|
||||
@@ -110,33 +200,93 @@ bool NavigationHandler::isKeyFrameInteractionEnabled() const {
|
||||
}
|
||||
|
||||
float NavigationHandler::interpolationTime() const {
|
||||
return _orbitalNavigator->retargetInterpolationTime();
|
||||
return _orbitalNavigator.retargetInterpolationTime();
|
||||
}
|
||||
|
||||
void NavigationHandler::setInterpolationTime(float durationInSeconds) {
|
||||
_orbitalNavigator->setRetargetInterpolationTime(durationInSeconds);
|
||||
_orbitalNavigator.setRetargetInterpolationTime(durationInSeconds);
|
||||
}
|
||||
|
||||
void NavigationHandler::updateCamera(double deltaTime) {
|
||||
ghoul_assert(_inputState != nullptr, "InputState must not be nullptr");
|
||||
ghoul_assert(_camera != nullptr, "Camera must not be nullptr");
|
||||
|
||||
if (_cameraUpdatedFromScript) {
|
||||
_cameraUpdatedFromScript = false;
|
||||
}
|
||||
else {
|
||||
if (!_playbackModeEnabled && _camera) {
|
||||
if (_useKeyFrameInteraction) {
|
||||
_keyframeNavigator->updateCamera(*_camera, _playbackModeEnabled);
|
||||
}
|
||||
else {
|
||||
_orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime);
|
||||
_orbitalNavigator->updateCameraStateFromStates(deltaTime);
|
||||
}
|
||||
if (_pendingNavigationState.has_value()) {
|
||||
applyNavigationState(_pendingNavigationState.value());
|
||||
_orbitalNavigator.resetVelocities();
|
||||
_pendingNavigationState.reset();
|
||||
} else if (!_playbackModeEnabled && _camera) {
|
||||
if (_useKeyFrameInteraction) {
|
||||
_keyframeNavigator.updateCamera(*_camera, _playbackModeEnabled);
|
||||
}
|
||||
else {
|
||||
_orbitalNavigator.updateStatesFromInput(_inputState, deltaTime);
|
||||
_orbitalNavigator.updateCameraStateFromStates(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationHandler::applyNavigationState(const NavigationHandler::NavigationState& ns)
|
||||
{
|
||||
const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame);
|
||||
const SceneGraphNode* anchor = sceneGraphNode(ns.anchor);
|
||||
|
||||
if (!anchor) {
|
||||
LERROR(fmt::format(
|
||||
"Could not find scene graph node '{}' used as anchor.", ns.referenceFrame
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!ns.aim.empty() && !sceneGraphNode(ns.aim)) {
|
||||
LERROR(fmt::format(
|
||||
"Could not find scene graph node '{}' used as aim.", ns.referenceFrame
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!referenceFrame) {
|
||||
LERROR(fmt::format(
|
||||
"Could not find scene graph node '{}' used as reference frame.",
|
||||
ns.referenceFrame)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const glm::dvec3 anchorWorldPosition = anchor->worldPosition();
|
||||
const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix();
|
||||
|
||||
_orbitalNavigator.setAnchorNode(ns.anchor);
|
||||
_orbitalNavigator.setAimNode(ns.aim);
|
||||
|
||||
const SceneGraphNode* anchorNode = _orbitalNavigator.anchorNode();
|
||||
const SceneGraphNode* aimNode = _orbitalNavigator.aimNode();
|
||||
if (!aimNode) {
|
||||
aimNode = anchorNode;
|
||||
}
|
||||
|
||||
const glm::dvec3 cameraPositionWorld = anchorWorldPosition +
|
||||
glm::dvec3(referenceFrameTransform * glm::dvec4(ns.position, 1.0));
|
||||
|
||||
glm::dvec3 up = ns.up.has_value() ?
|
||||
glm::normalize(referenceFrameTransform * ns.up.value()) :
|
||||
glm::dvec3(0.0, 1.0, 0.0);
|
||||
|
||||
// Construct vectors of a "neutral" view, i.e. when the aim is centered in view.
|
||||
glm::dvec3 neutralView =
|
||||
glm::normalize(aimNode->worldPosition() - cameraPositionWorld);
|
||||
|
||||
glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt(
|
||||
glm::dvec3(0.0),
|
||||
neutralView,
|
||||
up
|
||||
)));
|
||||
|
||||
glm::dquat pitchRotation = glm::angleAxis(ns.pitch, glm::dvec3(1.f, 0.f, 0.f));
|
||||
glm::dquat yawRotation = glm::angleAxis(ns.yaw, glm::dvec3(0.f, -1.f, 0.f));
|
||||
|
||||
_camera->setPositionVec3(cameraPositionWorld);
|
||||
_camera->setRotation(neutralCameraRotation * yawRotation * pitchRotation);
|
||||
_orbitalNavigator.clearPreviousState();
|
||||
}
|
||||
|
||||
void NavigationHandler::setEnableKeyFrameInteraction() {
|
||||
_useKeyFrameInteraction = true;
|
||||
}
|
||||
@@ -150,8 +300,8 @@ void NavigationHandler::triggerPlaybackStart() {
|
||||
}
|
||||
|
||||
void NavigationHandler::stopPlayback() {
|
||||
_orbitalNavigator->resetVelocities();
|
||||
_orbitalNavigator->resetNodeMovements();
|
||||
_orbitalNavigator.resetVelocities();
|
||||
_orbitalNavigator.resetNodeMovements();
|
||||
_playbackModeEnabled = false;
|
||||
}
|
||||
|
||||
@@ -160,131 +310,120 @@ Camera* NavigationHandler::camera() const {
|
||||
}
|
||||
|
||||
const InputState& NavigationHandler::inputState() const {
|
||||
return *_inputState;
|
||||
return _inputState;
|
||||
}
|
||||
|
||||
void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) {
|
||||
_inputState->mouseButtonCallback(button, action);
|
||||
_inputState.mouseButtonCallback(button, action);
|
||||
}
|
||||
|
||||
void NavigationHandler::mousePositionCallback(double x, double y) {
|
||||
_inputState->mousePositionCallback(x, y);
|
||||
_inputState.mousePositionCallback(x, y);
|
||||
}
|
||||
|
||||
void NavigationHandler::mouseScrollWheelCallback(double pos) {
|
||||
_inputState->mouseScrollWheelCallback(pos);
|
||||
_inputState.mouseScrollWheelCallback(pos);
|
||||
}
|
||||
|
||||
void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action)
|
||||
{
|
||||
_inputState->keyboardCallback(key, modifier, action);
|
||||
_inputState.keyboardCallback(key, modifier, action);
|
||||
}
|
||||
|
||||
void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict)
|
||||
NavigationHandler::NavigationState NavigationHandler::navigationState(
|
||||
const SceneGraphNode& referenceFrame) const
|
||||
{
|
||||
bool readSuccessful = true;
|
||||
const SceneGraphNode* anchor = _orbitalNavigator.anchorNode();
|
||||
const SceneGraphNode* aim = _orbitalNavigator.aimNode();
|
||||
|
||||
std::string anchor;
|
||||
std::string aim;
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first.
|
||||
|
||||
readSuccessful &= cameraDict.getValue(KeyAnchor, anchor);
|
||||
readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition);
|
||||
readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation);
|
||||
cameraDict.getValue(KeyAim, aim); // Aim is not required
|
||||
|
||||
if (!readSuccessful) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Position, Rotation and Focus need to be defined for camera dictionary."
|
||||
);
|
||||
if (!aim) {
|
||||
aim = anchor;
|
||||
}
|
||||
|
||||
// Set state
|
||||
_orbitalNavigator->setAnchorNode(anchor);
|
||||
_orbitalNavigator->setAimNode(aim);
|
||||
const glm::dquat invNeutralRotation = glm::quat_cast(glm::lookAt(
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
aim->worldPosition() - _camera->positionVec3(),
|
||||
glm::normalize(_camera->lookUpVectorWorldSpace())
|
||||
));
|
||||
|
||||
_camera->setPositionVec3(cameraPosition);
|
||||
_camera->setRotation(glm::dquat(
|
||||
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
|
||||
glm::dquat localRotation = invNeutralRotation * _camera->rotationQuaternion();
|
||||
glm::dvec3 eulerAngles = glm::eulerAngles(localRotation);
|
||||
|
||||
const double pitch = eulerAngles.x;
|
||||
const double yaw = -eulerAngles.y;
|
||||
|
||||
// Need to compensate by redisual roll left in local rotation:
|
||||
const glm::dquat unroll = glm::angleAxis(eulerAngles.z, glm::dvec3(0, 0, 1));
|
||||
const glm::dvec3 neutralUp =
|
||||
glm::inverse(invNeutralRotation) * unroll * _camera->lookUpVectorCameraSpace();
|
||||
|
||||
const glm::dmat3 invReferenceFrameTransform =
|
||||
glm::inverse(referenceFrame.worldRotationMatrix());
|
||||
|
||||
const glm::dvec3 position = invReferenceFrameTransform *
|
||||
(glm::dvec4(_camera->positionVec3() - anchor->worldPosition(), 1.0));
|
||||
|
||||
return NavigationState(
|
||||
_orbitalNavigator.anchorNode()->identifier(),
|
||||
_orbitalNavigator.aimNode() ?
|
||||
_orbitalNavigator.aimNode()->identifier() : "",
|
||||
referenceFrame.identifier(),
|
||||
position,
|
||||
invReferenceFrameTransform * neutralUp, yaw, pitch
|
||||
);
|
||||
}
|
||||
|
||||
ghoul::Dictionary NavigationHandler::cameraStateDictionary() {
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dquat quat;
|
||||
glm::dvec4 cameraRotation;
|
||||
void NavigationHandler::saveNavigationState(const std::string& filepath,
|
||||
const std::string& referenceFrameIdentifier)
|
||||
{
|
||||
const SceneGraphNode* referenceFrame = _orbitalNavigator.followingNodeRotation() ?
|
||||
_orbitalNavigator.anchorNode() :
|
||||
sceneGraph()->root();
|
||||
|
||||
cameraPosition = _camera->positionVec3();
|
||||
quat = _camera->rotationQuaternion();
|
||||
cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z);
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, cameraPosition);
|
||||
cameraDict.setValue(KeyRotation, cameraRotation);
|
||||
cameraDict.setValue(KeyAnchor, _orbitalNavigator->anchorNode()->identifier());
|
||||
if (_orbitalNavigator->aimNode()) {
|
||||
cameraDict.setValue(KeyAim, _orbitalNavigator->aimNode()->identifier());
|
||||
}
|
||||
|
||||
return cameraDict;
|
||||
}
|
||||
|
||||
void NavigationHandler::saveCameraStateToFile(const std::string& filepath) {
|
||||
if (!filepath.empty()) {
|
||||
std::string fullpath = absPath(filepath);
|
||||
LINFO(fmt::format("Saving camera position: {}", filepath));
|
||||
|
||||
ghoul::Dictionary cameraDict = cameraStateDictionary();
|
||||
|
||||
// TODO(abock): Should get the camera state as a dictionary and save the
|
||||
// dictionary to a file in form of a lua state and not use ofstreams here.
|
||||
|
||||
std::ofstream ofs(fullpath.c_str());
|
||||
|
||||
glm::dvec3 p = _camera->positionVec3();
|
||||
glm::dquat q = _camera->rotationQuaternion();
|
||||
|
||||
ofs << "return {" << std::endl;
|
||||
ofs << " " << KeyAnchor << " = " << "\"" <<
|
||||
_orbitalNavigator->anchorNode()->identifier() << "\""
|
||||
<< "," << std::endl;
|
||||
|
||||
if (_orbitalNavigator->aimNode()) {
|
||||
ofs << " " << KeyAim << " = " << "\"" <<
|
||||
_orbitalNavigator->aimNode()->identifier() << "\""
|
||||
<< "," << std::endl;
|
||||
if (!referenceFrameIdentifier.empty()) {
|
||||
referenceFrame = sceneGraphNode(referenceFrameIdentifier);
|
||||
if (!referenceFrame) {
|
||||
LERROR(fmt::format(
|
||||
"Could not find node '{}' to use as reference frame",
|
||||
referenceFrameIdentifier
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ofs << " " << KeyPosition << " = {"
|
||||
<< std::to_string(p.x) << ", "
|
||||
<< std::to_string(p.y) << ", "
|
||||
<< std::to_string(p.z) << "}," << std::endl;
|
||||
ofs << " " << KeyRotation << " = {"
|
||||
<< std::to_string(q.w) << ", "
|
||||
<< std::to_string(q.x) << ", "
|
||||
<< std::to_string(q.y) << ", "
|
||||
<< std::to_string(q.z) << "}," << std::endl;
|
||||
ofs << "}"<< std::endl;
|
||||
if (!filepath.empty()) {
|
||||
std::string absolutePath = absPath(filepath);
|
||||
LINFO(fmt::format("Saving camera position: {}", absolutePath));
|
||||
|
||||
ghoul::Dictionary cameraDict = navigationState(*referenceFrame).dictionary();
|
||||
ghoul::DictionaryLuaFormatter formatter;
|
||||
|
||||
std::ofstream ofs(absolutePath.c_str());
|
||||
ofs << "return " << formatter.format(cameraDict);
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) {
|
||||
LINFO(fmt::format("Reading camera state from file: {}", filepath));
|
||||
if (!FileSys.fileExists(filepath)) {
|
||||
throw ghoul::FileNotFoundError(filepath, "CameraFilePath");
|
||||
void NavigationHandler::loadNavigationState(const std::string& filepath) {
|
||||
const std::string absolutePath = absPath(filepath);
|
||||
LINFO(fmt::format("Reading camera state from file: {}", absolutePath));
|
||||
|
||||
if (!FileSys.fileExists(absolutePath)) {
|
||||
throw ghoul::FileNotFoundError(absolutePath, "NavigationState");
|
||||
}
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
ghoul::Dictionary navigationStateDictionary;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(filepath, cameraDict);
|
||||
setCameraStateFromDictionary(cameraDict);
|
||||
_cameraUpdatedFromScript = true;
|
||||
ghoul::lua::loadDictionaryFromFile(absolutePath, navigationStateDictionary);
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
NavigationState::Documentation(),
|
||||
navigationStateDictionary,
|
||||
"NavigationState"
|
||||
);
|
||||
setNavigationStateNextFrame(NavigationState(navigationStateDictionary));
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LWARNING("Unable to set camera position");
|
||||
LWARNING(e.message);
|
||||
LERROR(fmt::format("Unable to set camera position: {}", e.message));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +432,7 @@ void NavigationHandler::setJoystickAxisMapping(int axis,
|
||||
JoystickCameraStates::AxisInvert shouldInvert,
|
||||
JoystickCameraStates::AxisNormalize shouldNormalize)
|
||||
{
|
||||
_orbitalNavigator->joystickStates().setAxisMapping(
|
||||
_orbitalNavigator.joystickStates().setAxisMapping(
|
||||
axis,
|
||||
mapping,
|
||||
shouldInvert,
|
||||
@@ -304,15 +443,15 @@ void NavigationHandler::setJoystickAxisMapping(int axis,
|
||||
JoystickCameraStates::AxisInformation
|
||||
NavigationHandler::joystickAxisMapping(int axis) const
|
||||
{
|
||||
return _orbitalNavigator->joystickStates().axisMapping(axis);
|
||||
return _orbitalNavigator.joystickStates().axisMapping(axis);
|
||||
}
|
||||
|
||||
void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) {
|
||||
_orbitalNavigator->joystickStates().setDeadzone(axis, deadzone);
|
||||
_orbitalNavigator.joystickStates().setDeadzone(axis, deadzone);
|
||||
}
|
||||
|
||||
float NavigationHandler::joystickAxisDeadzone(int axis) const {
|
||||
return _orbitalNavigator->joystickStates().deadzone(axis);
|
||||
return _orbitalNavigator.joystickStates().deadzone(axis);
|
||||
}
|
||||
|
||||
void NavigationHandler::bindJoystickButtonCommand(int button, std::string command,
|
||||
@@ -320,7 +459,7 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman
|
||||
JoystickCameraStates::ButtonCommandRemote remote,
|
||||
std::string documentation)
|
||||
{
|
||||
_orbitalNavigator->joystickStates().bindButtonCommand(
|
||||
_orbitalNavigator.joystickStates().bindButtonCommand(
|
||||
button,
|
||||
std::move(command),
|
||||
action,
|
||||
@@ -330,11 +469,68 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman
|
||||
}
|
||||
|
||||
void NavigationHandler::clearJoystickButtonCommand(int button) {
|
||||
_orbitalNavigator->joystickStates().clearButtonCommand(button);
|
||||
_orbitalNavigator.joystickStates().clearButtonCommand(button);
|
||||
}
|
||||
|
||||
std::vector<std::string> NavigationHandler::joystickButtonCommand(int button) const {
|
||||
return _orbitalNavigator->joystickStates().buttonCommand(button);
|
||||
return _orbitalNavigator.joystickStates().buttonCommand(button);
|
||||
}
|
||||
|
||||
documentation::Documentation NavigationHandler::NavigationState::Documentation() {
|
||||
using namespace documentation;
|
||||
|
||||
return {
|
||||
"Navigation State",
|
||||
"core_navigation_state",
|
||||
{
|
||||
{
|
||||
KeyAnchor,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The identifier of the anchor node."
|
||||
},
|
||||
{
|
||||
KeyAim,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The identifier of the aim node, if used."
|
||||
},
|
||||
{
|
||||
KeyReferenceFrame,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"The identifier of the scene graph node to use as reference frame. "
|
||||
"If not specified, this will be the same as the anchor."
|
||||
},
|
||||
{
|
||||
KeyPosition,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
"The position of the camera relative to the anchor node, "
|
||||
"expressed in meters in the specified reference frame."
|
||||
},
|
||||
{
|
||||
KeyUp,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
"The up vector expressed in the coordinate system of the reference frame."
|
||||
},
|
||||
{
|
||||
KeyYaw,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The yaw angle in radians. "
|
||||
"Positive angle means yawing camera to the right."
|
||||
},
|
||||
{
|
||||
KeyPitch,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The pitch angle in radians. "
|
||||
"Positive angle means pitching camera upwards."
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
scripting::LuaLibrary NavigationHandler::luaLibrary() {
|
||||
@@ -342,25 +538,33 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() {
|
||||
"navigation",
|
||||
{
|
||||
{
|
||||
"setCameraState",
|
||||
&luascriptfunctions::setCameraState,
|
||||
"setNavigationState",
|
||||
&luascriptfunctions::setNavigationState,
|
||||
{},
|
||||
"object",
|
||||
"Set the camera state"
|
||||
"table",
|
||||
"Set the navigation state. "
|
||||
"The argument must be a valid Navigation State."
|
||||
},
|
||||
{
|
||||
"saveCameraStateToFile",
|
||||
&luascriptfunctions::saveCameraStateToFile,
|
||||
"saveNavigationState",
|
||||
&luascriptfunctions::saveNavigationState,
|
||||
{},
|
||||
"string",
|
||||
"Save the current camera state to file"
|
||||
"string, [string]",
|
||||
"Save the current navigation state to a file with the path given by the "
|
||||
"first argument. The optoinal second argument is the scene graph node to "
|
||||
"use as reference frame. By default, the reference frame will picked "
|
||||
"based on whether the orbital navigator is currently following the "
|
||||
"anchor node rotation. If it is, the anchor will be chosen as reference "
|
||||
"frame. If not, the reference frame will be set to the scene graph root."
|
||||
},
|
||||
{
|
||||
"restoreCameraStateFromFile",
|
||||
&luascriptfunctions::restoreCameraStateFromFile,
|
||||
"loadNavigationState",
|
||||
&luascriptfunctions::loadNavigationState,
|
||||
{},
|
||||
"string",
|
||||
"Restore the camera state from file"
|
||||
"Load a navigation state from file. The file should be a lua file "
|
||||
"returning the navigation state as a table formatted as a "
|
||||
"Navigation State, such as the output files of saveNavigationState."
|
||||
},
|
||||
{
|
||||
"retargetAnchor",
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
int restoreCameraStateFromFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::restoreCameraStateFromFile");
|
||||
int loadNavigationState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadNavigationState");
|
||||
|
||||
const std::string& cameraStateFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
@@ -39,27 +39,35 @@ int restoreCameraStateFromFile(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::navigationHandler.restoreCameraStateFromFile(cameraStateFilePath);
|
||||
global::navigationHandler.loadNavigationState(cameraStateFilePath);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setCameraState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setCameraState");
|
||||
int setNavigationState(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setNavigationState");
|
||||
|
||||
try {
|
||||
ghoul::Dictionary dictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, dictionary);
|
||||
global::navigationHandler.setCameraStateFromDictionary(dictionary);
|
||||
} catch (const ghoul::RuntimeError& e) {
|
||||
ghoul::Dictionary navigationStateDictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary);
|
||||
|
||||
using namespace openspace::documentation;
|
||||
|
||||
TestResult r = testSpecification(
|
||||
interaction::NavigationHandler::NavigationState::Documentation(),
|
||||
navigationStateDictionary
|
||||
);
|
||||
|
||||
if (!r.success) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Could not set camera state: {}", e.what())
|
||||
fmt::format("Could not set camera state: {}", ghoul::to_string(r))
|
||||
);
|
||||
}
|
||||
|
||||
global::navigationHandler.setNavigationStateNextFrame(navigationStateDictionary);
|
||||
|
||||
// @CLEANUP: When luaDictionaryFromState doesn't leak space anymore, remove the next
|
||||
// line ---abock(2018-02-15)
|
||||
lua_settop(L, 0);
|
||||
@@ -67,21 +75,27 @@ int setCameraState(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saveCameraStateToFile(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::saveCameraStateToFile");
|
||||
|
||||
const std::string& cameraStateFilePath = ghoul::lua::value<std::string>(
|
||||
int saveNavigationState(lua_State* L) {
|
||||
const int n = ghoul::lua::checkArgumentsAndThrow(
|
||||
L,
|
||||
1,
|
||||
ghoul::lua::PopValue::Yes
|
||||
{ 1, 2 },
|
||||
"lua::saveNavigationState"
|
||||
);
|
||||
|
||||
const std::string& cameraStateFilePath = ghoul::lua::value<std::string>(L, 1);
|
||||
|
||||
std::string referenceFrame = "";
|
||||
if (n > 1) {
|
||||
referenceFrame = ghoul::lua::value<std::string>(L, 2);
|
||||
}
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return ghoul::lua::luaError(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
global::navigationHandler.saveCameraStateToFile(cameraStateFilePath);
|
||||
global::navigationHandler.saveNavigationState(cameraStateFilePath, referenceFrame);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -365,20 +365,26 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
|
||||
const glm::dvec3 anchorPos = _anchorNode->worldPosition();
|
||||
const glm::dvec3 prevCameraPosition = _camera->positionVec3();
|
||||
const glm::dvec3 anchorDisplacement = anchorPos - _previousAnchorNodePosition;
|
||||
const glm::dvec3 anchorDisplacement = _previousAnchorNodePosition.has_value() ?
|
||||
(anchorPos - _previousAnchorNodePosition.value()) :
|
||||
glm::dvec3(0.0);
|
||||
|
||||
CameraPose pose = {
|
||||
_camera->positionVec3() + anchorDisplacement,
|
||||
_camera->rotationQuaternion()
|
||||
};
|
||||
|
||||
if (_aimNode && _aimNode != _anchorNode) {
|
||||
const bool hasPreviousPositions =
|
||||
_previousAnchorNodePosition.has_value() &&
|
||||
_previousAimNodePosition.has_value();
|
||||
|
||||
if (_aimNode && _aimNode != _anchorNode && hasPreviousPositions) {
|
||||
const glm::dvec3 aimPos = _aimNode->worldPosition();
|
||||
const glm::dvec3 cameraToAnchor =
|
||||
_previousAnchorNodePosition - prevCameraPosition;
|
||||
_previousAnchorNodePosition.value() - prevCameraPosition;
|
||||
|
||||
Displacement anchorToAim = {
|
||||
_previousAimNodePosition - _previousAnchorNodePosition,
|
||||
_previousAimNodePosition.value() - _previousAnchorNodePosition.value(),
|
||||
aimPos - anchorPos
|
||||
};
|
||||
|
||||
@@ -413,8 +419,9 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
glm::dquat anchorRotation =
|
||||
glm::quat_cast(_anchorNode->worldRotationMatrix());
|
||||
|
||||
glm::dquat anchorNodeRotationDiff =
|
||||
_previousAnchorNodeRotation * glm::inverse(anchorRotation);
|
||||
glm::dquat anchorNodeRotationDiff = _previousAnchorNodeRotation.has_value() ?
|
||||
_previousAnchorNodeRotation.value() * glm::inverse(anchorRotation) :
|
||||
glm::dquat();
|
||||
|
||||
_previousAnchorNodeRotation = anchorRotation;
|
||||
|
||||
@@ -563,11 +570,17 @@ void OrbitalNavigator::setAnchorNode(const SceneGraphNode* anchorNode) {
|
||||
_anchorNode = anchorNode;
|
||||
|
||||
if (_anchorNode) {
|
||||
_previousAnchorNodePosition = _anchorNode->worldPosition();
|
||||
_previousAnchorNodeRotation = glm::quat_cast(_anchorNode->worldRotationMatrix());
|
||||
_previousAnchorNodePosition.reset();
|
||||
_previousAnchorNodeRotation.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void OrbitalNavigator::clearPreviousState() {
|
||||
_previousAnchorNodePosition.reset();
|
||||
_previousAnchorNodeRotation.reset();
|
||||
_previousAimNodePosition.reset();
|
||||
}
|
||||
|
||||
void OrbitalNavigator::setAimNode(const SceneGraphNode* aimNode) {
|
||||
_retargetAimInterpolator.end();
|
||||
_aimNode = aimNode;
|
||||
@@ -652,6 +665,9 @@ void OrbitalNavigator::setRetargetInterpolationTime(float durationInSeconds) {
|
||||
}
|
||||
|
||||
bool OrbitalNavigator::followingNodeRotation() const {
|
||||
if (_aimNode != nullptr && _aimNode != _anchorNode) {
|
||||
return false;
|
||||
}
|
||||
return _followRotationInterpolator.value() >= 1.0;
|
||||
}
|
||||
|
||||
@@ -1219,4 +1235,8 @@ JoystickCameraStates& OrbitalNavigator::joystickStates() {
|
||||
return _joystickStates;
|
||||
}
|
||||
|
||||
const JoystickCameraStates& OrbitalNavigator::joystickStates() const {
|
||||
return _joystickStates;
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -848,7 +848,7 @@ void SessionRecording::playbackCamera() {
|
||||
pbFrame.followFocusNodeRotation = (rotationFollowing == "F");
|
||||
}
|
||||
if (_setSimulationTimeWithNextCameraKeyframe) {
|
||||
global::timeManager.setTimeNextFrame(timeSim);
|
||||
global::timeManager.setTimeNextFrame(Time(timeSim));
|
||||
_setSimulationTimeWithNextCameraKeyframe = false;
|
||||
_saveRenderingCurrentRecordedTime = timeRec;
|
||||
}
|
||||
|
||||
+39
-64
@@ -31,6 +31,7 @@
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
#include <ghoul/fmt.h>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
@@ -44,8 +45,8 @@ using namespace openspace;
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static NSString* pauseResultId = @"com.openspaceproject.pause_resume";
|
||||
static NSString* showFullGuiId = @"com.openspaceproject.show_full_gui";
|
||||
static NSString* showSimpleGuiId = @"com.openspaceproject.show_simple_gui";
|
||||
static NSString* hideGuiId = @"com.openspaceproject.hide_gui";
|
||||
static NSString* hideOnScreenTextId = @"com.openspaceproject.hide_onscreen";
|
||||
NSArray* focusIdentifiers;
|
||||
|
||||
|
||||
@@ -55,8 +56,8 @@ NSArray* focusIdentifiers;
|
||||
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
|
||||
- (void)pauseResumeButtonAction:(id)sender;
|
||||
- (void)focusObjectAction:(id)sender;
|
||||
- (void)fullGuiButtonAction:(id)sender;
|
||||
- (void)simpleGuiButtonAction:(id)sender;
|
||||
- (void)hideTextAction:(id)sender;
|
||||
- (void)hideGuiAction:(id)sender;
|
||||
@end
|
||||
|
||||
@implementation TouchBarDelegate
|
||||
@@ -66,7 +67,7 @@ NSArray* focusIdentifiers;
|
||||
|
||||
touchBar.customizationIdentifier = @"com.openspaceproject.main_touch_bar";
|
||||
|
||||
NSArray* objs = [@[showSimpleGuiId, showFullGuiId,
|
||||
NSArray* objs = [@[hideGuiId, hideOnScreenTextId,
|
||||
NSTouchBarItemIdentifierFixedSpaceSmall, pauseResultId,
|
||||
NSTouchBarItemIdentifierFlexibleSpace]
|
||||
arrayByAddingObjectsFromArray: focusIdentifiers];
|
||||
@@ -85,8 +86,6 @@ NSArray* focusIdentifiers;
|
||||
- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar
|
||||
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
|
||||
{
|
||||
// @TODO(abock): Potential memory leak here by returning an alloc?
|
||||
|
||||
// Remove the unused variable warning
|
||||
(void)touchBar;
|
||||
|
||||
@@ -112,38 +111,38 @@ NSArray* focusIdentifiers;
|
||||
return [touchBarItem autorelease];
|
||||
}
|
||||
|
||||
if ([identifier isEqualToString:showFullGuiId]) {
|
||||
if ([identifier isEqualToString:hideOnScreenTextId]) {
|
||||
NSButton* button = [NSButton
|
||||
buttonWithTitle:@"Full GUI"
|
||||
target:self action:@selector(fullGuiButtonAction:)
|
||||
buttonWithTitle:@"Toggle Text"
|
||||
target:self action:@selector(hideTextAction:)
|
||||
];
|
||||
|
||||
NSCustomTouchBarItem* touchBarItem = [
|
||||
[NSCustomTouchBarItem alloc]
|
||||
initWithIdentifier:showFullGuiId
|
||||
initWithIdentifier:hideOnScreenTextId
|
||||
];
|
||||
touchBarItem.view = button;
|
||||
touchBarItem.customizationLabel = NSLocalizedString(
|
||||
@"Toggles the full GUI",
|
||||
@"Toogles on-screen text",
|
||||
@""
|
||||
);
|
||||
|
||||
return [touchBarItem autorelease];
|
||||
}
|
||||
|
||||
if ([identifier isEqualToString:showSimpleGuiId]) {
|
||||
if ([identifier isEqualToString:hideGuiId]) {
|
||||
NSButton* button = [NSButton
|
||||
buttonWithTitle:@"Simple GUI"
|
||||
target:self action:@selector(simpleGuiButtonAction:)
|
||||
buttonWithTitle:@"Toggle GUI"
|
||||
target:self action:@selector(hideGuiAction:)
|
||||
];
|
||||
|
||||
NSCustomTouchBarItem* touchBarItem = [
|
||||
[NSCustomTouchBarItem alloc]
|
||||
initWithIdentifier:showSimpleGuiId
|
||||
initWithIdentifier:hideGuiId
|
||||
];
|
||||
touchBarItem.view = button;
|
||||
touchBarItem.customizationLabel = NSLocalizedString(
|
||||
@"Toggles the simple GUI",
|
||||
@"Toggles the main GUI",
|
||||
@""
|
||||
);
|
||||
|
||||
@@ -188,63 +187,40 @@ NSArray* focusIdentifiers;
|
||||
|
||||
NSString* title = [button title];
|
||||
|
||||
std::string str = fmt::format(
|
||||
"openspace.setPropertyValueSingle('{}', '{}');\
|
||||
openspace.setPropertyValueSingle('{}', '');\
|
||||
openspace.setPropertyValueSingle('{}', '');",
|
||||
"NavigationHandler.OrbitalNavigator.Anchor", std::string([title UTF8String]),
|
||||
"NavigationHandler.OrbitalNavigator.Aim",
|
||||
"NavigationHandler.OrbitalNavigator.RetargetAnchor"
|
||||
);
|
||||
global::scriptEngine.queueScript(
|
||||
"openspace.setPropertyValue('NavigationHandler.Origin', '" +
|
||||
std::string([title UTF8String]) + "');",
|
||||
str,
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
- (void)fullGuiButtonAction:(id)sender {
|
||||
- (void)hideTextAction:(id)sender {
|
||||
// Remove unused variable warning
|
||||
(void)sender;
|
||||
|
||||
global::scriptEngine.queueScript(
|
||||
"local b = openspace.getPropertyValue(\
|
||||
'Modules.ImGUI.Main.Enabled'\
|
||||
);\
|
||||
openspace.setPropertyValueSingle(\
|
||||
'Modules.ImGUI.Main.Enabled',\
|
||||
not b\
|
||||
);\
|
||||
openspace.setPropertyValueSingle(\
|
||||
'Modules.ImGUI.Main.IsHidden',\
|
||||
b\
|
||||
);",
|
||||
"local isEnabled = openspace.getPropertyValue('Dashboard.IsEnabled');\
|
||||
openspace.setPropertyValueSingle('Dashboard.IsEnabled', not isEnabled);\
|
||||
openspace.setPropertyValueSingle('RenderEngine.ShowLog', not isEnabled);\
|
||||
openspace.setPropertyValueSingle('RenderEngine.ShowVersion', not isEnabled);\
|
||||
openspace.setPropertyValueSingle('RenderEngine.ShowCamera', not isEnabled)",
|
||||
scripting::ScriptEngine::RemoteScripting::No
|
||||
);
|
||||
}
|
||||
|
||||
- (void)simpleGuiButtonAction:(id)sender {
|
||||
- (void)hideGuiAction:(id)sender {
|
||||
// Remove unused variable warning
|
||||
(void)sender;
|
||||
global::scriptEngine.queueScript(
|
||||
"local b = openspace.getPropertyValue('Modules.ImGUI.Main.FeaturedProperties.Enabled');\n\
|
||||
local c = openspace.getPropertyValue('Modules.ImGUI.Main.IsHidden');\n\
|
||||
openspace.setPropertyValue('Modules.ImGUI.*.Enabled', false);\n\
|
||||
if b and c then\n\
|
||||
-- This can happen if the main properties window is enabled, the main gui\n\
|
||||
-- is enabled and then closed again. So the main properties window is\n\
|
||||
-- enabled, but also all windows are hidden\n\
|
||||
openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', false);\n\
|
||||
openspace.setPropertyValueSingle(\n\
|
||||
'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\
|
||||
true\n\
|
||||
);\n\
|
||||
openspace.setPropertyValueSingle(\n\
|
||||
'Modules.ImGUI.Main.SpaceTime.Enabled',\n\
|
||||
true\n\
|
||||
);\n\
|
||||
else\n\
|
||||
openspace.setPropertyValueSingle(\n\
|
||||
'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\
|
||||
not b\n\
|
||||
);\n\
|
||||
openspace.setPropertyValueSingle(\n\
|
||||
'Modules.ImGUI.Main.SpaceTime.Enabled',\n\
|
||||
not b\n\
|
||||
);\n\
|
||||
openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', b);\n\
|
||||
end",
|
||||
"local isEnabled = openspace.getPropertyValue('Modules.CefWebGui.Visible');\
|
||||
openspace.setPropertyValueSingle('Modules.CefWebGui.Visible', not isEnabled);",
|
||||
scripting::ScriptEngine::RemoteScripting::No
|
||||
);
|
||||
}
|
||||
@@ -266,19 +242,18 @@ void showTouchbar() {
|
||||
[NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES;
|
||||
}
|
||||
|
||||
std::vector<SceneGraphNode*> nodes =
|
||||
global::renderEngine.scene()->allSceneGraphNodes();
|
||||
std::vector<SceneGraphNode*> ns = global::renderEngine.scene()->allSceneGraphNodes();
|
||||
|
||||
std::sort(
|
||||
nodes.begin(),
|
||||
nodes.end(),
|
||||
ns.begin(),
|
||||
ns.end(),
|
||||
[](SceneGraphNode* lhs, SceneGraphNode* rhs) {
|
||||
return lhs->guiName() < rhs->guiName();
|
||||
}
|
||||
);
|
||||
|
||||
NSMutableArray* ids = [[NSMutableArray alloc] init];
|
||||
for (SceneGraphNode* n : nodes) {
|
||||
for (SceneGraphNode* n : ns) {
|
||||
const std::vector<std::string>& tags = n->tags();
|
||||
auto it = std::find(tags.begin(), tags.end(), "GUI.Interesting");
|
||||
if (it != tags.end()) {
|
||||
|
||||
@@ -325,7 +325,7 @@ void ParallelPeer::dataMessageReceived(const std::vector<char>& message)
|
||||
TimeKeyframeData timeKeyframeData;
|
||||
timeKeyframeData.delta = kfMessage._dt;
|
||||
timeKeyframeData.pause = kfMessage._paused;
|
||||
timeKeyframeData.time = kfMessage._time;
|
||||
timeKeyframeData.time = Time(kfMessage._time);
|
||||
timeKeyframeData.jump = kfMessage._requiresTimeJump;
|
||||
|
||||
const double kfTimestamp = convertTimestamp(kfMessage._timestamp);
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ namespace openspace {
|
||||
std::string licenseText() {
|
||||
return "OpenSpace\n\
|
||||
\n\
|
||||
Copyright (c) 2014-2018\n\
|
||||
Copyright (c) 2014-2019\n\
|
||||
\n\
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this\n\
|
||||
software and associated documentation files (the \"Software\"), to deal in the Software\n\
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace openspace::performance {
|
||||
// The ghoul::SharedData block addressed by OpenSpacePerformanceMeasurementSharedData
|
||||
// will only get allocated once and contains the total number of allocated shared memory
|
||||
// blocks alongside a list of names of these blocks
|
||||
//
|
||||
|
||||
void PerformanceManager::CreateGlobalSharedMemory() {
|
||||
static_assert(
|
||||
@@ -70,6 +69,8 @@ void PerformanceManager::CreateGlobalSharedMemory() {
|
||||
"The global memory struct does not fit the allocated global memory space"
|
||||
);
|
||||
|
||||
ghoul::SharedMemory::remove(GlobalSharedMemoryName);
|
||||
|
||||
if (ghoul::SharedMemory::exists(GlobalSharedMemoryName)) {
|
||||
ghoul::SharedMemory sharedMemory(GlobalSharedMemoryName);
|
||||
sharedMemory.acquireLock();
|
||||
|
||||
@@ -48,7 +48,13 @@ int addDashboardItem(lua_State* L) {
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
|
||||
global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d));
|
||||
try {
|
||||
global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d));
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC("addDashboardItem", e.what());
|
||||
return ghoul::lua::luaError(L, "Error adding dashboard item");
|
||||
}
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
|
||||
@@ -144,11 +144,20 @@ namespace {
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ShowFrameNumberInfo = {
|
||||
"ShowFrameNumber",
|
||||
"Show Frame Number",
|
||||
"If this value is enabled, the current frame number is rendered into the window."
|
||||
"ShowFrameInformation",
|
||||
"Show Frame Information",
|
||||
"If this value is enabled, the current frame number and frame times are rendered "
|
||||
"into the window."
|
||||
};
|
||||
|
||||
#ifdef OPENSPACE_WITH_INSTRUMENTATION
|
||||
constexpr openspace::properties::Property::PropertyInfo SaveFrameInfo = {
|
||||
"SaveFrameInformation",
|
||||
"Save Frame Information",
|
||||
"Saves the frame information to disk"
|
||||
};
|
||||
#endif // OPENSPACE_WITH_INSTRUMENTATION
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo DisableMasterInfo = {
|
||||
"DisableMasterRendering",
|
||||
"Disable Master Rendering",
|
||||
@@ -287,10 +296,14 @@ RenderEngine::RenderEngine()
|
||||
, _showCameraInfo(ShowCameraInfo, true)
|
||||
, _takeScreenshot(TakeScreenshotInfo)
|
||||
, _applyWarping(ApplyWarpingInfo, false)
|
||||
, _showFrameNumber(ShowFrameNumberInfo, false)
|
||||
, _showFrameInformation(ShowFrameNumberInfo, false)
|
||||
#ifdef OPENSPACE_WITH_INSTRUMENTATION
|
||||
, _saveFrameInformation(SaveFrameInfo, false)
|
||||
#endif // OPENSPACE_WITH_INSTRUMENTATION
|
||||
, _disableMasterRendering(DisableMasterInfo, false)
|
||||
, _globalBlackOutFactor(GlobalBlackoutFactorInfo, 1.f, 0.f, 1.f)
|
||||
, _nAaSamples(AaSamplesInfo, 4, 1, 8)
|
||||
<<<<<<< HEAD
|
||||
, _tmoOwner(TMOInfo)
|
||||
, _hdrExposure(HDRExposureInfo, 1.68f, 0.01f, 10.0f)
|
||||
, _maxWhite(MaxWhiteInfo, 4.f, 0.001f, 100.0f)
|
||||
@@ -302,6 +315,11 @@ RenderEngine::RenderEngine()
|
||||
, _value(ValueInfo, 1.f, 0.0f, 5.0f)
|
||||
, _lightness(LightnessInfo, 1.1f, 0.0f, 5.0f)
|
||||
, _colorSpace(ColorSpaceInfo, properties::OptionProperty::DisplayType::Dropdown)
|
||||
=======
|
||||
, _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f)
|
||||
, _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f)
|
||||
, _gamma(GammaInfo, 2.2f, 0.01f, 10.0f)
|
||||
>>>>>>> master
|
||||
, _horizFieldOfView(HorizFieldOfViewInfo, 80.f, 1.f, 179.0f)
|
||||
, _globalRotation(
|
||||
GlobalRotationInfo,
|
||||
@@ -320,7 +338,11 @@ RenderEngine::RenderEngine()
|
||||
glm::vec3(0.f),
|
||||
glm::vec3(-glm::pi<float>()),
|
||||
glm::vec3(glm::pi<float>())
|
||||
<<<<<<< HEAD
|
||||
)
|
||||
=======
|
||||
)
|
||||
>>>>>>> master
|
||||
{
|
||||
_doPerformanceMeasurements.onChange([this](){
|
||||
global::performanceManager.setEnabled(_doPerformanceMeasurements);
|
||||
@@ -440,7 +462,15 @@ RenderEngine::RenderEngine()
|
||||
_takeScreenshot.onChange([this](){ _shouldTakeScreenshot = true; });
|
||||
addProperty(_takeScreenshot);
|
||||
|
||||
addProperty(_showFrameNumber);
|
||||
addProperty(_showFrameInformation);
|
||||
#ifdef OPENSPACE_WITH_INSTRUMENTATION
|
||||
_saveFrameInformation.onChange([&]() {
|
||||
if (_saveFrameInformation) {
|
||||
_frameInfo.lastSavedFrame = frameNumber();
|
||||
}
|
||||
});
|
||||
addProperty(_saveFrameInformation);
|
||||
#endif // OPENSPACE_WITH_INSTRUMENTATION
|
||||
|
||||
addProperty(_globalRotation);
|
||||
addProperty(_screenSpaceRotation);
|
||||
@@ -538,12 +568,12 @@ void RenderEngine::initializeGL() {
|
||||
// development
|
||||
global::windowDelegate.setNearFarClippingPlane(0.001f, 1000.f);
|
||||
|
||||
//Set horizontal FOV value with whatever the field of view (in degrees) is of the
|
||||
// Set horizontal FOV value with whatever the field of view (in degrees) is of the
|
||||
// initialized window
|
||||
_horizFieldOfView = static_cast<float>(global::windowDelegate.getHorizFieldOfView());
|
||||
|
||||
constexpr const float FontSizeBig = 50.f;
|
||||
_fontBig = global::fontManager.font(KeyFontMono, FontSizeBig);
|
||||
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;
|
||||
@@ -705,13 +735,18 @@ void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMat
|
||||
);
|
||||
}
|
||||
|
||||
if (_showFrameNumber) {
|
||||
if (_showFrameInformation) {
|
||||
glm::vec2 penPosition = glm::vec2(
|
||||
fontResolution().x / 2 - 50,
|
||||
fontResolution().y / 3
|
||||
);
|
||||
|
||||
RenderFont(*_fontBig, penPosition, std::to_string(_frameNumber));
|
||||
std::string fn = std::to_string(_frameNumber);
|
||||
std::string dt = std::to_string(global::windowDelegate.deltaTime());
|
||||
std::string avgDt = std::to_string(global::windowDelegate.averageDeltaTime());
|
||||
|
||||
std::string res = "Frame: " + fn + '\n' + "Dt: " + dt + '\n' + "Avg Dt: " + avgDt;
|
||||
RenderFont(*_fontFrameInfo, penPosition, res);
|
||||
}
|
||||
|
||||
++_frameNumber;
|
||||
@@ -917,6 +952,35 @@ void RenderEngine::postDraw() {
|
||||
scene()->allSceneGraphNodes()
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef OPENSPACE_WITH_INSTRUMENTATION
|
||||
if (_saveFrameInformation) {
|
||||
_frameInfo.frames.push_back({
|
||||
frameNumber(),
|
||||
global::windowDelegate.deltaTime(),
|
||||
global::windowDelegate.averageDeltaTime()
|
||||
});
|
||||
}
|
||||
|
||||
const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame;
|
||||
const bool shouldSave = _saveFrameInformation && frameNumber() >= next;
|
||||
if (shouldSave) {
|
||||
std::string filename = fmt::format(
|
||||
"_inst_renderengine_{}_{}.txt",
|
||||
_frameInfo.lastSavedFrame, _frameInfo.saveEveryNthFrame
|
||||
);
|
||||
std::ofstream file(absPath("${BIN}/" + filename));
|
||||
for (const FrameInfo& i : _frameInfo.frames) {
|
||||
std::string line = fmt::format(
|
||||
"{}\t{}\t{}", i.iFrame, i.deltaTime, i.avgDeltaTime
|
||||
);
|
||||
file << line << '\n';
|
||||
}
|
||||
|
||||
_frameInfo.frames.clear();
|
||||
_frameInfo.lastSavedFrame = frameNumber();
|
||||
}
|
||||
#endif // OPENSPACE_WITH_INSTRUMENTATION
|
||||
}
|
||||
|
||||
Scene* RenderEngine::scene() {
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyTag = "Tag";
|
||||
|
||||
constexpr const std::array<const char*, 5> UniformNames = {
|
||||
"OcclusionDepth", "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1"
|
||||
constexpr const std::array<const char*, 4> UniformNames = {
|
||||
"Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EnabledInfo = {
|
||||
@@ -451,7 +451,6 @@ bool ScreenSpaceRenderable::initialize() {
|
||||
}
|
||||
|
||||
bool ScreenSpaceRenderable::initializeGL() {
|
||||
_originalViewportSize = global::windowDelegate.currentWindowResolution();
|
||||
createShaders();
|
||||
return isReady();
|
||||
}
|
||||
@@ -523,15 +522,9 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() {
|
||||
float textureRatio =
|
||||
static_cast<float>(_objectSize.y) / static_cast<float>(_objectSize.x);
|
||||
|
||||
float scalingRatioX = _originalViewportSize.x / resolution.x;
|
||||
float scalingRatioY = _originalViewportSize.y / resolution.y;
|
||||
glm::mat4 scale = glm::scale(
|
||||
glm::mat4(1.f),
|
||||
glm::vec3(
|
||||
_scale * scalingRatioX,
|
||||
_scale * scalingRatioY * textureRatio,
|
||||
1.f
|
||||
)
|
||||
glm::vec3(_scale, _scale * textureRatio, 1.f)
|
||||
);
|
||||
|
||||
// Simulate orthographic projection by distance to plane.
|
||||
@@ -614,9 +607,8 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) {
|
||||
unbindTexture();
|
||||
}
|
||||
|
||||
void ScreenSpaceRenderable::bindTexture() {}
|
||||
|
||||
void ScreenSpaceRenderable::unbindTexture() {}
|
||||
void ScreenSpaceRenderable::unbindTexture() {
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -374,14 +374,14 @@ void SceneGraphNode::update(const UpdateData& data) {
|
||||
}
|
||||
UpdateData newUpdateData = data;
|
||||
|
||||
_worldRotationCached = calculateWorldRotation();
|
||||
_worldScaleCached = calculateWorldScale();
|
||||
// Assumes _worldRotationCached and _worldScaleCached have been calculated for parent
|
||||
_worldPositionCached = calculateWorldPosition();
|
||||
_worldRotationCached = calculateWorldRotation();
|
||||
_worldScaleCached = calculateWorldScale();
|
||||
|
||||
newUpdateData.modelTransform.translation = worldPosition();
|
||||
newUpdateData.modelTransform.rotation = worldRotationMatrix();
|
||||
newUpdateData.modelTransform.scale = worldScale();
|
||||
newUpdateData.modelTransform.translation = _worldPositionCached;
|
||||
newUpdateData.modelTransform.rotation = _worldRotationCached;
|
||||
newUpdateData.modelTransform.scale = _worldScaleCached;
|
||||
|
||||
glm::dmat4 translation = glm::translate(
|
||||
glm::dmat4(1.0),
|
||||
@@ -655,7 +655,7 @@ bool SceneGraphNode::hasGuiHintHidden() const {
|
||||
glm::dvec3 SceneGraphNode::calculateWorldPosition() const {
|
||||
// recursive up the hierarchy if there are parents available
|
||||
if (_parent) {
|
||||
const glm::dvec3 wp = _parent->calculateWorldPosition();
|
||||
const glm::dvec3 wp = _parent->worldPosition();
|
||||
const glm::dmat3 wrot = _parent->worldRotationMatrix();
|
||||
const double ws = _parent->worldScale();
|
||||
const glm::dvec3 p = position();
|
||||
@@ -684,7 +684,7 @@ bool SceneGraphNode::isTimeFrameActive(const Time& time) const {
|
||||
glm::dmat3 SceneGraphNode::calculateWorldRotation() const {
|
||||
// recursive up the hierarchy if there are parents available
|
||||
if (_parent) {
|
||||
return _parent->calculateWorldRotation() * rotationMatrix();
|
||||
return _parent->worldRotationMatrix() * rotationMatrix();
|
||||
}
|
||||
else {
|
||||
return rotationMatrix();
|
||||
@@ -694,7 +694,7 @@ glm::dmat3 SceneGraphNode::calculateWorldRotation() const {
|
||||
double SceneGraphNode::calculateWorldScale() const {
|
||||
// recursive up the hierarchy if there are parents available
|
||||
if (_parent) {
|
||||
return _parent->calculateWorldScale() * scale();
|
||||
return _parent->worldScale() * scale();
|
||||
}
|
||||
else {
|
||||
return scale();
|
||||
|
||||
@@ -333,12 +333,12 @@ int time_setTime(lua_State* L) {
|
||||
if (nArguments == 1) {
|
||||
if (isNumber) {
|
||||
double value = lua_tonumber(L, 1);
|
||||
global::timeManager.setTimeNextFrame(value);
|
||||
global::timeManager.setTimeNextFrame(Time(value));
|
||||
return 0;
|
||||
}
|
||||
if (isString) {
|
||||
const char* time = lua_tostring(L, 1);
|
||||
global::timeManager.setTimeNextFrame(Time::convertTime(time));
|
||||
global::timeManager.setTimeNextFrame(Time(Time::convertTime(time)));
|
||||
return 0;
|
||||
}
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -424,7 +424,7 @@ int time_interpolateTime(lua_State* L) {
|
||||
global::timeManager.interpolateTime(targetTime, duration);
|
||||
}
|
||||
else {
|
||||
global::timeManager.setTimeNextFrame(targetTime);
|
||||
global::timeManager.setTimeNextFrame(Time(targetTime));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -486,7 +486,7 @@ int time_interpolateTimeRelative(lua_State* L) {
|
||||
}
|
||||
else {
|
||||
global::timeManager.setTimeNextFrame(
|
||||
global::timeManager.time().j2000Seconds() + delta
|
||||
Time(global::timeManager.time().j2000Seconds() + delta)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-15
@@ -109,7 +109,7 @@ void TimeManager::interpolateTime(double targetTime, double durationSeconds) {
|
||||
const bool pause = isPaused();
|
||||
|
||||
const TimeKeyframeData current = { time(), deltaTime(), false, false };
|
||||
const TimeKeyframeData next = { targetTime, targetDeltaTime(), pause, false };
|
||||
const TimeKeyframeData next = { Time(targetTime), targetDeltaTime(), pause, false };
|
||||
|
||||
clearKeyframes();
|
||||
addKeyframe(now, current);
|
||||
@@ -138,7 +138,7 @@ void TimeManager::preSynchronization(double dt) {
|
||||
if (newTime != _lastTime) {
|
||||
using K = const CallbackHandle;
|
||||
using V = TimeChangeCallback;
|
||||
for (const std::pair<const K, V>& it : _timeChangeCallbacks) {
|
||||
for (const std::pair<K, V>& it : _timeChangeCallbacks) {
|
||||
it.second();
|
||||
}
|
||||
}
|
||||
@@ -148,14 +148,14 @@ void TimeManager::preSynchronization(double dt) {
|
||||
{
|
||||
using K = const CallbackHandle;
|
||||
using V = TimeChangeCallback;
|
||||
for (const std::pair<const K, V>& it : _deltaTimeChangeCallbacks) {
|
||||
for (const std::pair<K, V>& it : _deltaTimeChangeCallbacks) {
|
||||
it.second();
|
||||
}
|
||||
}
|
||||
if (_timelineChanged) {
|
||||
using K = const CallbackHandle;
|
||||
using V = TimeChangeCallback;
|
||||
for (const std::pair<const K, V>& it : _timelineChangeCallbacks) {
|
||||
for (const std::pair<K, V>& it : _timelineChangeCallbacks) {
|
||||
it.second();
|
||||
}
|
||||
}
|
||||
@@ -193,12 +193,12 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) {
|
||||
} else if (hasPastKeyframes) {
|
||||
// Extrapolate based on last past keyframe
|
||||
const double deltaApplicationTime = applicationTime - lastPastKeyframe->timestamp;
|
||||
Time predictedTime = {
|
||||
Time predictedTime(
|
||||
lastPastKeyframe->data.time.j2000Seconds() +
|
||||
deltaApplicationTime *
|
||||
(lastPastKeyframe->data.pause ? 0.0 : lastPastKeyframe->data.delta)
|
||||
};
|
||||
return TimeKeyframeData{
|
||||
);
|
||||
return TimeKeyframeData {
|
||||
predictedTime,
|
||||
lastPastKeyframe->data.delta,
|
||||
false,
|
||||
@@ -206,7 +206,7 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) {
|
||||
};
|
||||
}
|
||||
// As the last option, fall back on the current time.
|
||||
return TimeKeyframeData{ _currentTime, _targetDeltaTime, _timePaused, false };
|
||||
return TimeKeyframeData { _currentTime, _targetDeltaTime, _timePaused, false };
|
||||
}
|
||||
|
||||
void TimeManager::progressTime(double dt) {
|
||||
@@ -230,7 +230,7 @@ void TimeManager::progressTime(double dt) {
|
||||
|
||||
using K = const CallbackHandle;
|
||||
using V = TimeChangeCallback;
|
||||
for (const std::pair<const K, V>& it : _timeJumpCallbacks) {
|
||||
for (const std::pair<K, V>& it : _timeJumpCallbacks) {
|
||||
it.second();
|
||||
}
|
||||
return;
|
||||
@@ -316,7 +316,7 @@ TimeKeyframeData TimeManager::interpolate(const Keyframe<TimeKeyframeData>& past
|
||||
deltaAppTime;
|
||||
|
||||
TimeKeyframeData data {
|
||||
interpolatedTime,
|
||||
Time(interpolatedTime),
|
||||
interpolatedDeltaTime,
|
||||
past.data.pause,
|
||||
past.data.jump
|
||||
@@ -532,9 +532,9 @@ void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolation
|
||||
}
|
||||
|
||||
const double now = global::windowDelegate.applicationTime();
|
||||
|
||||
Time newTime = time().j2000Seconds() +
|
||||
(_deltaTime + newDeltaTime) * 0.5 * interpolationDuration;
|
||||
Time newTime(
|
||||
time().j2000Seconds() + (_deltaTime + newDeltaTime) * 0.5 * interpolationDuration
|
||||
);
|
||||
|
||||
TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false };
|
||||
TimeKeyframeData futureKeyframe = { newTime, newDeltaTime, false, false };
|
||||
@@ -556,8 +556,9 @@ void TimeManager::interpolatePause(bool pause, double interpolationDuration) {
|
||||
|
||||
const double now = global::windowDelegate.applicationTime();
|
||||
double targetDelta = pause ? 0.0 : _targetDeltaTime;
|
||||
Time newTime = time().j2000Seconds() +
|
||||
(_deltaTime + targetDelta) * 0.5 * interpolationDuration;
|
||||
Time newTime(
|
||||
time().j2000Seconds() + (_deltaTime + targetDelta) * 0.5 * interpolationDuration
|
||||
);
|
||||
|
||||
TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false };
|
||||
TimeKeyframeData futureKeyframe = { newTime, _targetDeltaTime, pause, false };
|
||||
|
||||
Reference in New Issue
Block a user