From 4359478d02b98cc1f524c54af9a79bdefb0c96a6 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Wed, 5 May 2021 19:54:52 +0300 Subject: [PATCH 01/10] merged add/remove handler commands --- StereoPlus2/InfrastructureTypes.hpp | 39 ++++++++++------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/StereoPlus2/InfrastructureTypes.hpp b/StereoPlus2/InfrastructureTypes.hpp index 29a1073..b7f4d72 100644 --- a/StereoPlus2/InfrastructureTypes.hpp +++ b/StereoPlus2/InfrastructureTypes.hpp @@ -368,34 +368,24 @@ class FuncCommand : Command { template class IEvent { - FuncCommand* addHandlersCommand = nullptr; + FuncCommand* modifyHandlersCommand = nullptr; std::map> handlersToBeAdded; - - FuncCommand* removeHandlersCommand = nullptr; std::vector handlersToBeRemoved; - void EnsureAddHandlersCommand() { - if (!addHandlersCommand) { - addHandlersCommand = new FuncCommand(); - addHandlersCommand->func = [&] { + void EnsureModifyHandlersCommand() { + if (!modifyHandlersCommand) { + modifyHandlersCommand = new FuncCommand(); + modifyHandlersCommand->func = [&] { handlers.insert(handlersToBeAdded.begin(), handlersToBeAdded.end()); - addHandlersCommand = nullptr; - handlersToBeAdded.clear(); - }; - } - } - void EnsureRemoveHandlersCommand() { - if (!removeHandlersCommand) { - removeHandlersCommand = new FuncCommand(); - removeHandlersCommand->func = [&] { for (auto h : handlersToBeRemoved) handlers.erase(h); - removeHandlersCommand = nullptr; + + modifyHandlersCommand = nullptr; + handlersToBeAdded.clear(); handlersToBeRemoved.clear(); }; } } - protected: std::map> handlers; public: @@ -403,14 +393,14 @@ class IEvent { static size_t id = 0; handlersToBeAdded[id] = func; - EnsureAddHandlersCommand(); + EnsureModifyHandlersCommand(); return id++; } void RemoveHandler(size_t v) { handlersToBeRemoved.push_back(v); - EnsureRemoveHandlersCommand(); + EnsureModifyHandlersCommand(); } size_t operator += (std::function func) { @@ -423,10 +413,8 @@ class IEvent { ~IEvent() { // Commands will be executed with skipping the assigned func // and then will be deleted so we only need to abort them. - if (addHandlersCommand) - addHandlersCommand->Abort(); - if (removeHandlersCommand) - removeHandlersCommand->Abort(); + if (modifyHandlersCommand) + modifyHandlersCommand->Abort(); } void AddHandlersFrom(const IEvent& o) { @@ -434,8 +422,7 @@ class IEvent { handlersToBeAdded.insert(o.handlersToBeAdded.begin(), o.handlersToBeAdded.end()); handlersToBeRemoved.insert(handlersToBeRemoved.end(), o.handlersToBeRemoved.begin(), o.handlersToBeRemoved.end()); - EnsureAddHandlersCommand(); - EnsureRemoveHandlersCommand(); + EnsureModifyHandlersCommand(); } }; template From be1cf6741ffc4eb0da072208f87e96b11fe64a14 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Wed, 5 May 2021 19:55:27 +0300 Subject: [PATCH 02/10] moved all math to a separate file --- StereoPlus2/DomainTypes.hpp | 182 +------------- StereoPlus2/DomainUtils.hpp | 134 ---------- StereoPlus2/Input.hpp | 13 +- StereoPlus2/Math.hpp | 313 ++++++++++++++++++++++++ StereoPlus2/Settings.hpp | 16 +- StereoPlus2/StereoPlus2.vcxproj | 1 + StereoPlus2/StereoPlus2.vcxproj.filters | 3 + StereoPlus2/Tools.hpp | 1 + StereoPlus2/main.cpp | 26 +- 9 files changed, 360 insertions(+), 329 deletions(-) create mode 100644 StereoPlus2/Math.hpp diff --git a/StereoPlus2/DomainTypes.hpp b/StereoPlus2/DomainTypes.hpp index 401de03..4d6bb64 100644 --- a/StereoPlus2/DomainTypes.hpp +++ b/StereoPlus2/DomainTypes.hpp @@ -8,6 +8,7 @@ #include "DomainUtils.hpp" #include #include +#include "Math.hpp" class GroupObject : public SceneObject { public: @@ -224,30 +225,7 @@ class SineCurve : public LeafObject { } void updateCacheAsPolyLine(int from, int to) { - auto size = to - from; - std::vector vs; - - for (size_t i = 0; i < size; i++) - vs.push_back(vertices[i + from]); - - for (auto v : vs) - verticesCache.push_back(v); - } - - glm::quat getRotation(glm::vec3 ac, glm::vec3 ab) { - auto zPlaneLocal = glm::cross(ac, ab); - zPlaneLocal = glm::normalize(zPlaneLocal); - - auto zPlaneGlobal = glm::vec3(0, 0, 1); - - auto r1 = glm::rotation(zPlaneGlobal, zPlaneLocal); - - auto acRotatedBack = glm::rotate(glm::inverse(r1), ac); - acRotatedBack = glm::normalize(acRotatedBack); - - auto r2 = glm::rotation(glm::vec3(1, 0, 0), acRotatedBack); - auto r = r1 * r2; - return r; + verticesCache.insert(verticesCache.end(), vertices.begin() + from, vertices.begin() + to); } /// @@ -278,74 +256,16 @@ void UpdateCache() { return; } - size_t i = 0; - - for (; i < vertices.size(); i += 2) + for (size_t i = 0; i < vertices.size(); i += 2) { if (i + 2 >= vertices.size()) { updateCacheAsPolyLine(i + 1, vertices.size()); break; } - - auto ac = vertices[i + 2] - vertices[i]; - auto ab = vertices[i + 1] - vertices[i]; - auto bc = vertices[i + 2] - vertices[i + 1]; - - auto acUnit = glm::normalize(ac); - auto abadScalarProjection = glm::dot(ab, acUnit); - auto db = ab - acUnit * abadScalarProjection; - auto abdbScalarProjection = glm::dot(ab, glm::normalize(db)); - - if (isnan(abadScalarProjection) || isnan(abdbScalarProjection)) { - updateCacheAsPolyLine(i, i + 2); - break; - } - - auto r = getRotation(ac, ab); - if (isnan(r.x) || isnan(r.y) || isnan(r.z) || isnan(r.w)) { - updateCacheAsPolyLine(i, i + 2); - break; - } - - auto rotatedY = glm::rotate(r, glm::vec3(0, 1, 0)); - auto sameDirection = glm::dot(glm::normalize(db), rotatedY) > 0; - - auto acLength = glm::length(ac); - auto abLength = glm::length(ab); - auto bdLength = abdbScalarProjection; - auto adLength = abadScalarProjection; - auto dcLength = acLength - adLength; - - static const auto hpi = 3.1415926 / 2.; - - auto bcLength = glm::length(bc); - - int abNumber = abLength / 5 + 1; - int bcNumber = bcLength / 5 + 1; - - std::vector points; - - for (size_t j = 0; j < abNumber; j++) { - auto x = -hpi + hpi * j / (float)abNumber; - auto nx = j / (float)abNumber * adLength; - auto ny = cos(x) * bdLength; - points.push_back(glm::vec3(nx, ny, 0)); - } - for (size_t j = 0; j <= bcNumber; j++) { - auto x = hpi * j / (float)bcNumber; - auto nx = j / (float)bcNumber * dcLength + adLength; - auto ny = cos(x) * bdLength; - points.push_back(glm::vec3(nx, ny, 0)); - } - - if (!sameDirection) - for (size_t j = 0; j < points.size(); j++) - points[j].y = -points[j].y; - - for (auto p : points) - verticesCache.push_back(glm::rotate(r, p) + vertices[i]); + auto points = Build::Sine(&vertices[i]); + verticesCache.insert(verticesCache.end(), points.begin(), points.end()); } CascadeTransform(verticesCache); @@ -826,93 +746,11 @@ class Camera : public LeafObject return positionModifier + GetLocalPosition(); } - glm::vec3 getLeft(const glm::vec3& posMillimeters) { - auto pos = ConvertMillimetersToViewCoordinates(posMillimeters, ViewSize.Get(), viewSizeZ); - auto cameraPos = GetPos(); - float denominator = cameraPos.z - pos.z; - return glm::vec3( - (pos.x * cameraPos.z - pos.z * (cameraPos.x - eyeToCenterDistance)) / denominator, - (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, - 0 - ); - } - glm::vec3 getRight(const glm::vec3& posMillimeters) { - auto pos = ConvertMillimetersToViewCoordinates(posMillimeters, ViewSize.Get(), viewSizeZ); - auto cameraPos = GetPos(); - float denominator = cameraPos.z - pos.z; - return glm::vec3( - (pos.x * cameraPos.z - pos.z * (cameraPos.x + eyeToCenterDistance)) / denominator, - (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, - 0 - ); - } - - Event<> onPropertiesChanged; virtual void HandleBeforeUpdate() override { onPropertiesChanged.Invoke(); } - - // Millimeters to pixels - static glm::vec3 ConvertMillimetersToPixels(const glm::vec3& vMillimeters) { - static float inchToMillimeter = 0.0393701; - // vMillimiters[millimiter] - // inchToMillemeter[inch/millimeter] - // PPI[pixel/inch] - // vMillimiters*PPI*inchToMillemeter[millimeter*(pixel/inch)*(inch/millimeter) = millimeter*(pixel/millimeter) = pixel] - auto vPixels = Settings::PPI().Get() * inchToMillimeter * vMillimeters; - return vPixels; - } - - // Millimeters to [-1;1] - // World center-centered - // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates - static glm::vec3 ConvertMillimetersToViewCoordinates(const glm::vec3& vMillimeters, const glm::vec2& viewSizePixels, const float& viewSizeZMillimeters) { - static float inchToMillimeter = 0.0393701; - auto vsph = viewSizePixels / 2.f; - auto vszmh = viewSizeZMillimeters / 2.f; - - auto vView = glm::vec3( - vMillimeters.x * Settings::PPI().Get() * inchToMillimeter / vsph.x, - vMillimeters.y * Settings::PPI().Get() * inchToMillimeter / vsph.y, - vMillimeters.z / vszmh - ); - return vView; - } - - // Millimeters to [-1;1] - // World center-centered - // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates - static float ConvertMillimetersToViewCoordinates(const float& vMillimeters, const float& viewSizePixels) { - static float inchToMillimeter = 0.0393701; - auto vsph = viewSizePixels / 2.f; - - auto vView = vMillimeters * Settings::PPI().Get() * inchToMillimeter / vsph; - return vView; - } - - - // Pixels to Millimeters - static glm::vec3 ConvertPixelsToMillimeters(const glm::vec3& vPixels) { - static float inchToMillimeter = 0.0393701; - // vPixels[pixel] - // inchToMillimeter[inch/millimeter] - // PPI[pixel/inch] - // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] - auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; - return vMillimiters; - } - static glm::vec2 ConvertPixelsToMillimeters(const glm::vec2& vPixels) { - static float inchToMillimeter = 0.0393701; - // vPixels[pixel] - // inchToMillimeter[inch/millimeter] - // PPI[pixel/inch] - // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] - auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; - return vMillimiters; - } - public: // Pixels ReadonlyProperty ViewSize; @@ -925,9 +763,9 @@ class Camera : public LeafObject Camera() { Name = "camera"; EyeToCenterDistance.OnChanged() += [&](const float& v) { - eyeToCenterDistance = ConvertMillimetersToViewCoordinates(v, ViewSize->x); }; + eyeToCenterDistance = Convert::Unit::MillimetersToViewCoordinates(v, ViewSize->x); }; PositionModifier.OnChanged() += [&](const glm::vec3& v) { - positionModifier = ConvertMillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); }; + positionModifier = Convert::Unit::MillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); }; ViewSize.OnChanged() += [&](const glm::vec2 v) { // Trigger conversion. @@ -941,10 +779,10 @@ class Camera : public LeafObject } glm::vec3 GetLeft(const glm::vec3& v) { - return getLeft(v); + return Convert::Stereo::GetLeft(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); } glm::vec3 GetRight(const glm::vec3& v) { - return getRight(v); + return Convert::Stereo::GetRight(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); } @@ -957,7 +795,7 @@ class Camera : public LeafObject ImGui::Extensions::PushActive(false); ImGui::DragFloat2("view size", (float*)&ViewSize.Get()); - auto viewSizeMillimeters = ConvertPixelsToMillimeters(ViewSize.Get()); + auto viewSizeMillimeters = Convert::Unit::PixelsToMillimeters(ViewSize.Get()); ImGui::DragFloat2("view size millimeters", (float*)(&viewSizeMillimeters), 1, 0, 0, "%.1f"); ImGui::Extensions::PopActive(); diff --git a/StereoPlus2/DomainUtils.hpp b/StereoPlus2/DomainUtils.hpp index fc81a99..49d9ff1 100644 --- a/StereoPlus2/DomainUtils.hpp +++ b/StereoPlus2/DomainUtils.hpp @@ -281,137 +281,3 @@ class DragDropBuffer { } }; -class Transform { - // Trims angle to 360 degrees - static float trimAngle(float a) { - int b = a; - return b % 360 + (a - b); - } - - // Trims angle to [-180;180] and converts to radian - static float convertToDeltaDegree(float a) { - return trimAngle(a) * 3.1415926f * 2 / 360; - } - - // Get rotation angle around the axe. - // Calculates a simple sum of absolute values of angles from all axes, - // converts angle from radians to degrees - // and then trims it to 180 degrees. - static float getDirectedDeltaAngle(const glm::vec3& rotation) { - float angle = 0; - // Rotation axe determines the rotating direction - // so the rotation angles should be positive - for (auto i = 0; i < 3; i++) - angle += abs(rotation[i]); - return trimAngle(angle) * 3.1415926f * 2 / 360; - } - - // Get rotation angle around the axe. - // Calculates a simple sum of absolute values of angles from all axes, - // trims angle to 180 degrees and then converts to radians - static bool tryGetLocalRotation(const glm::vec3& rotation, glm::vec3& axe, float& angle) { - glm::vec3 t[2] = { glm::vec3(), glm::vec3() }; - float angles[2] = { 0, 0 }; - - // Supports rotation around 1,2 axes simultaneously. - auto modifiedAxeNumber = 0; - for (auto i = 0; i < 3; i++) { - assert(modifiedAxeNumber < 3); - if (rotation[i] != 0) { - t[modifiedAxeNumber][i] = rotation[i] > 0 ? 1 : -1; - angles[modifiedAxeNumber] = abs(rotation[i]); - modifiedAxeNumber++; - } - } - - if (modifiedAxeNumber == 0) { - axe = glm::vec3(); - return false; - } - if (modifiedAxeNumber == 1) { - angle = convertToDeltaDegree(angles[0]); - axe = t[0]; - return true; - } - - angle = convertToDeltaDegree(angles[0] + angles[1]); - axe = t[0] + t[1]; - return true; - } - - // Convert local rotation to global rotation relative to cross rotation. - // - // Shortly, Isolates rotation in cross' local space. - // - // Based on quaternion intransitivity, applying new local rotation and then applying inverted initial global rotation - // results in new local rotation being converted to global rotation. - // r0 * r1Local * r0^-1 = r1Global - // - // Basically, moves rotation initial point from (0;0;0;1) to cross global rotation. - // Compromises performance since cross new rotation is calculated both here and ourside of this method - // but improves readability and maintainability of the code. - static glm::quat getIsolatedRotation(const glm::quat& localRotation, const glm::quat crossGlobalRotation) { - auto crossNewRotation = crossGlobalRotation * localRotation; - auto rIsolated = crossNewRotation * glm::inverse(crossGlobalRotation); - return rIsolated; - } - -public: - static void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list& targets) { - for (auto target : targets) { - target->SetWorldPosition((target->GetWorldPosition() - center) / oldScale * scale + center); - for (size_t i = 0; i < target->GetVertices().size(); i++) - target->SetVertice(i, (target->GetVertices()[i] - center) / oldScale * scale + center); - } - } - static void Translate(const glm::vec3& transformVector, std::list& targets, SceneObject* cross) { - // Need to calculate average rotation. - // https://stackoverflow.com/questions/12374087/average-of-multiple-quaternions/27410865#27410865 - if (Settings::SpaceMode().Get() == SpaceMode::Local) { - auto r = glm::rotate(cross->GetWorldRotation(), transformVector); - - cross->SetWorldPosition(cross->GetWorldPosition() + r); - for (auto o : targets) { - o->SetWorldPosition(o->GetWorldPosition() + r); - for (size_t i = 0; i < o->GetVertices().size(); i++) - o->SetVertice(i, o->GetVertices()[i] + r); - } - return; - } - - cross->SetWorldPosition(cross->GetWorldPosition() + transformVector); - for (auto o : targets) { - o->SetWorldPosition(o->GetWorldPosition() + transformVector); - for (size_t i = 0; i < o->GetVertices().size(); i++) - o->SetVertice(i, o->GetVertices()[i] + transformVector); - } - } - static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list& targets, SceneObject* cross) { - glm::vec3 axe; - float angle; - - if (!tryGetLocalRotation(rotation, axe, angle)) - return; - - auto r = glm::normalize(glm::angleAxis(angle, axe)); - - // Convert local rotation to global rotation. - // It is required to rotate all vertices since they don't store their own rotation - // meaning that their rotation = (0;0;0;1). - // - // When multiple objects are selected cross' rotation is equal to the first - // object in selection. See TransformTool::OnSelectionChanged - if (Settings::SpaceMode().Get() == SpaceMode::Local) - r = getIsolatedRotation(r, cross->GetWorldRotation()); - - cross->SetLocalRotation(r * cross->GetLocalRotation()); - - for (auto& target : targets) { - target->SetWorldPosition(glm::rotate(r, target->GetWorldPosition() - center) + center); - for (size_t i = 0; i < target->GetVertices().size(); i++) - target->SetVertice(i, glm::rotate(r, target->GetVertices()[i] - center) + center); - - target->SetWorldRotation(r * target->GetWorldRotation()); - } - } -}; diff --git a/StereoPlus2/Input.hpp b/StereoPlus2/Input.hpp index 160a8a2..5b9cd92 100644 --- a/StereoPlus2/Input.hpp +++ b/StereoPlus2/Input.hpp @@ -66,7 +66,10 @@ class Input { ContinuousInput continuousInputOneSecondDelay = ContinuousInput(1); ContinuousInput continuousInputNoDelay = ContinuousInput(0); - CombinationNode combinations; + static CombinationNode& combinationTree() { + static CombinationNode v; + return v; + } void FillAxes() { mouseOldPos = mouseNewPos; @@ -264,11 +267,11 @@ class Input { } } - void AddShortcut(const Key::Combination& combination, const std::function& callback) { + static void AddShortcut(const Key::Combination& combination, const std::function& callback) { if (auto b = combination.modifiers.cbegin(), e = combination.modifiers.cend(); - InsertCombination(combinations, &b, &e, combination.key, callback)) + InsertCombination(combinationTree(), &b, &e, combination.key, callback)) return; - Logger.Error("Shortcut is already taken."); + Log::For().Error("Shortcut is already taken."); } @@ -281,7 +284,7 @@ class Input { // Make sure printable characters don't trigger combinations // while keyboard is captured by text input if (io->AnyKeyPressed) - ExecuteFirstMatchingCombination(combinations, io->WantCaptureKeyboard); + ExecuteFirstMatchingCombination(combinationTree(), io->WantCaptureKeyboard); // Handle OnInput actions for (auto [id,handler] : handlers) diff --git a/StereoPlus2/Math.hpp b/StereoPlus2/Math.hpp new file mode 100644 index 0000000..a4d984c --- /dev/null +++ b/StereoPlus2/Math.hpp @@ -0,0 +1,313 @@ +#pragma once + +#include "SceneObject.hpp" + +class Transform { + // Trims angle to 360 degrees + static float trimAngle(float a) { + int b = a; + return b % 360 + (a - b); + } + + // Trims angle to [-180;180] and converts to radian + static float convertToDeltaDegree(float a) { + return trimAngle(a) * 3.1415926f * 2 / 360; + } + + // Get rotation angle around the axe. + // Calculates a simple sum of absolute values of angles from all axes, + // converts angle from radians to degrees + // and then trims it to 180 degrees. + static float getDirectedDeltaAngle(const glm::vec3& rotation) { + float angle = 0; + // Rotation axe determines the rotating direction + // so the rotation angles should be positive + for (auto i = 0; i < 3; i++) + angle += abs(rotation[i]); + return trimAngle(angle) * 3.1415926f * 2 / 360; + } + + // Get rotation angle around the axe. + // Calculates a simple sum of absolute values of angles from all axes, + // trims angle to 180 degrees and then converts to radians + static bool tryGetLocalRotation(const glm::vec3& rotation, glm::vec3& axe, float& angle) { + glm::vec3 t[2] = { glm::vec3(), glm::vec3() }; + float angles[2] = { 0, 0 }; + + // Supports rotation around 1,2 axes simultaneously. + auto modifiedAxeNumber = 0; + for (auto i = 0; i < 3; i++) { + assert(modifiedAxeNumber < 3); + if (rotation[i] != 0) { + t[modifiedAxeNumber][i] = rotation[i] > 0 ? 1 : -1; + angles[modifiedAxeNumber] = abs(rotation[i]); + modifiedAxeNumber++; + } + } + + if (modifiedAxeNumber == 0) { + axe = glm::vec3(); + return false; + } + if (modifiedAxeNumber == 1) { + angle = convertToDeltaDegree(angles[0]); + axe = t[0]; + return true; + } + + angle = convertToDeltaDegree(angles[0] + angles[1]); + axe = t[0] + t[1]; + return true; + } + + // Convert local rotation to global rotation relative to cross rotation. + // + // Shortly, Isolates rotation in cross' local space. + // + // Based on quaternion intransitivity, applying new local rotation and then applying inverted initial global rotation + // results in new local rotation being converted to global rotation. + // r0 * r1Local * r0^-1 = r1Global + // + // Basically, moves rotation initial point from (0;0;0;1) to cross global rotation. + // Compromises performance since cross new rotation is calculated both here and ourside of this method + // but improves readability and maintainability of the code. + static glm::quat getIsolatedRotation(const glm::quat& localRotation, const glm::quat crossGlobalRotation) { + auto crossNewRotation = crossGlobalRotation * localRotation; + auto rIsolated = crossNewRotation * glm::inverse(crossGlobalRotation); + return rIsolated; + } + +public: + static void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list& targets) { + for (auto& target : targets) { + target->SetWorldPosition((target->GetWorldPosition() - center) / oldScale * scale + center); + for (size_t i = 0; i < target->GetVertices().size(); i++) + target->SetVertice(i, (target->GetVertices()[i] - center) / oldScale * scale + center); + } + } + static void Translate(const glm::vec3& transformVector, std::list& targets, SceneObject* cross) { + // Need to calculate average rotation. + // https://stackoverflow.com/questions/12374087/average-of-multiple-quaternions/27410865#27410865 + if (Settings::SpaceMode().Get() == SpaceMode::Local) { + auto r = glm::rotate(cross->GetWorldRotation(), transformVector); + + cross->SetWorldPosition(cross->GetWorldPosition() + r); + for (auto o : targets) { + o->SetWorldPosition(o->GetWorldPosition() + r); + for (size_t i = 0; i < o->GetVertices().size(); i++) + o->SetVertice(i, o->GetVertices()[i] + r); + } + return; + } + + cross->SetWorldPosition(cross->GetWorldPosition() + transformVector); + for (auto o : targets) { + o->SetWorldPosition(o->GetWorldPosition() + transformVector); + for (size_t i = 0; i < o->GetVertices().size(); i++) + o->SetVertice(i, o->GetVertices()[i] + transformVector); + } + } + static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list& targets, SceneObject* cross) { + glm::vec3 axe; + float angle; + + if (!tryGetLocalRotation(rotation, axe, angle)) + return; + + auto r = glm::normalize(glm::angleAxis(angle, axe)); + + // Convert local rotation to global rotation. + // It is required to rotate all vertices since they don't store their own rotation + // meaning that their rotation = (0;0;0;1). + // + // When multiple objects are selected cross' rotation is equal to the first + // object in selection. See TransformTool::OnSelectionChanged + if (Settings::SpaceMode().Get() == SpaceMode::Local) + r = getIsolatedRotation(r, cross->GetWorldRotation()); + + cross->SetLocalRotation(r * cross->GetLocalRotation()); + + for (auto& target : targets) { + target->SetWorldPosition(glm::rotate(r, target->GetWorldPosition() - center) + center); + for (size_t i = 0; i < target->GetVertices().size(); i++) + target->SetVertice(i, glm::rotate(r, target->GetVertices()[i] - center) + center); + + target->SetWorldRotation(r * target->GetWorldRotation()); + } + } +}; + +struct Convert { + struct Unit { + // Millimeters to pixels + static glm::vec3 MillimetersToPixels(const glm::vec3& vMillimeters) { + static float inchToMillimeter = 0.0393701; + // vMillimiters[millimiter] + // inchToMillemeter[inch/millimeter] + // PPI[pixel/inch] + // vMillimiters*PPI*inchToMillemeter[millimeter*(pixel/inch)*(inch/millimeter) = millimeter*(pixel/millimeter) = pixel] + auto vPixels = Settings::PPI().Get() * inchToMillimeter * vMillimeters; + return vPixels; + } + + // Millimeters to [-1;1] + // World center-centered + // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates + static glm::vec3 MillimetersToViewCoordinates(const glm::vec3& vMillimeters, const glm::vec2& viewSizePixels, const float& viewSizeZMillimeters) { + static float inchToMillimeter = 0.0393701; + auto vsph = viewSizePixels / 2.f; + auto vszmh = viewSizeZMillimeters / 2.f; + + auto vView = glm::vec3( + vMillimeters.x * Settings::PPI().Get() * inchToMillimeter / vsph.x, + vMillimeters.y * Settings::PPI().Get() * inchToMillimeter / vsph.y, + vMillimeters.z / vszmh + ); + return vView; + } + + // Millimeters to [-1;1] + // World center-centered + // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates + static float MillimetersToViewCoordinates(const float& vMillimeters, const float& viewSizePixels) { + static float inchToMillimeter = 0.0393701; + auto vsph = viewSizePixels / 2.f; + + auto vView = vMillimeters * Settings::PPI().Get() * inchToMillimeter / vsph; + return vView; + } + + // Pixels to Millimeters + static glm::vec3 PixelsToMillimeters(const glm::vec3& vPixels) { + static float inchToMillimeter = 0.0393701; + // vPixels[pixel] + // inchToMillimeter[inch/millimeter] + // PPI[pixel/inch] + // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] + auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; + return vMillimiters; + } + static glm::vec2 PixelsToMillimeters(const glm::vec2& vPixels) { + static float inchToMillimeter = 0.0393701; + // vPixels[pixel] + // inchToMillimeter[inch/millimeter] + // PPI[pixel/inch] + // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] + auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; + return vMillimiters; + } + + }; + class Stereo { + static glm::vec3 getLeft(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + auto pos = Convert::Unit::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); + float denominator = cameraPos.z - pos.z; + return glm::vec3( + (pos.x * cameraPos.z - pos.z * (cameraPos.x - eyeToCenterDistance)) / denominator, + (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, + 0 + ); + } + static glm::vec3 getRight(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + auto pos = Convert::Unit::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); + float denominator = cameraPos.z - pos.z; + return glm::vec3( + (pos.x * cameraPos.z - pos.z * (cameraPos.x + eyeToCenterDistance)) / denominator, + (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, + 0 + ); + } + public: + static glm::vec3 GetLeft(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + return getLeft(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); + } + static glm::vec3 GetRight(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + return getRight(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); + } + + }; +}; + +class Build { + static glm::quat getRotation(glm::vec3 ac, glm::vec3 ab) { + auto zPlaneLocal = glm::cross(ac, ab); + zPlaneLocal = glm::normalize(zPlaneLocal); + + auto zPlaneGlobal = glm::vec3(0, 0, 1); + + auto r1 = glm::rotation(zPlaneGlobal, zPlaneLocal); + + auto acRotatedBack = glm::rotate(glm::inverse(r1), ac); + acRotatedBack = glm::normalize(acRotatedBack); + + auto r2 = glm::rotation(glm::vec3(1, 0, 0), acRotatedBack); + auto r = r1 * r2; + return r; + } + +public: + + /// + /// B + /// / | \ + /// A--D---C + /// + static const std::vector Sine(const glm::vec3 vertices[3]) { + auto ac = vertices[2] - vertices[0]; + auto ab = vertices[1] - vertices[0]; + auto bc = vertices[2] - vertices[1]; + + auto acUnit = glm::normalize(ac); + auto abadScalarProjection = glm::dot(ab, acUnit); + auto db = ab - acUnit * abadScalarProjection; + auto abdbScalarProjection = glm::dot(ab, glm::normalize(db)); + + if (isnan(abadScalarProjection) || isnan(abdbScalarProjection)) + return { vertices[1], vertices[2] }; + + auto r = getRotation(ac, ab); + + if (isnan(r.x) || isnan(r.y) || isnan(r.z) || isnan(r.w)) + return { vertices[1], vertices[2] }; + + auto rotatedY = glm::rotate(r, glm::vec3(0, 1, 0)); + auto sameDirection = glm::dot(glm::normalize(db), rotatedY) > 0; + + auto acLength = glm::length(ac); + auto abLength = glm::length(ab); + auto bdLength = abdbScalarProjection; + auto adLength = abadScalarProjection; + auto dcLength = acLength - adLength; + + static const auto hpi = 3.1415926 / 2.; + + auto bcLength = glm::length(bc); + + int abNumber = abLength / 5 + 1; + int bcNumber = bcLength / 5 + 1; + + std::vector points; + + for (size_t j = 0; j < abNumber; j++) { + auto x = -hpi + hpi * j / (float)abNumber; + auto nx = j / (float)abNumber * adLength; + auto ny = cos(x) * bdLength; + points.push_back(glm::vec3(nx, ny, 0)); + } + for (size_t j = 0; j <= bcNumber; j++) { + auto x = hpi * j / (float)bcNumber; + auto nx = j / (float)bcNumber * dcLength + adLength; + auto ny = cos(x) * bdLength; + points.push_back(glm::vec3(nx, ny, 0)); + } + + if (!sameDirection) + for (size_t j = 0; j < points.size(); j++) + points[j].y = -points[j].y; + + for (size_t j = 0; j < points.size(); j++) + points[j] = glm::rotate(r, points[j]) + vertices[0]; + + return points; + } +}; \ No newline at end of file diff --git a/StereoPlus2/Settings.hpp b/StereoPlus2/Settings.hpp index f392732..0081686 100644 --- a/StereoPlus2/Settings.hpp +++ b/StereoPlus2/Settings.hpp @@ -18,16 +18,21 @@ enum class ExtrusionEditingToolMode { Step, }; -enum class ObjectMode { - Object, - Vertex, -}; +//enum class ObjectMode { +// Object, +// Vertex, +//}; enum class SpaceMode { World, Local, }; +enum class TargetMode { + Object, + Pivot, +}; + enum class TransformToolMode { Translate, Scale, @@ -42,8 +47,9 @@ enum class MoveCoordinateAction { class Settings { public: - StaticProperty(::ObjectMode, ObjectMode) + //StaticProperty(::ObjectMode, ObjectMode) StaticProperty(::SpaceMode, SpaceMode) + StaticProperty(::TargetMode, TargetMode) StaticProperty(::MoveCoordinateAction, MoveCoordinateAction) StaticProperty(bool, ShouldDetectPosition) diff --git a/StereoPlus2/StereoPlus2.vcxproj b/StereoPlus2/StereoPlus2.vcxproj index 59ee622..fb83716 100644 --- a/StereoPlus2/StereoPlus2.vcxproj +++ b/StereoPlus2/StereoPlus2.vcxproj @@ -163,6 +163,7 @@ + diff --git a/StereoPlus2/StereoPlus2.vcxproj.filters b/StereoPlus2/StereoPlus2.vcxproj.filters index 51139fe..1343e03 100644 --- a/StereoPlus2/StereoPlus2.vcxproj.filters +++ b/StereoPlus2/StereoPlus2.vcxproj.filters @@ -154,6 +154,9 @@ infrastructure + + source files + diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index 1790134..69ae6fd 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -10,6 +10,7 @@ #include #include "TemplateExtensions.hpp" #include "Settings.hpp" +#include "Math.hpp" class Tool { protected: diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index a84e4e7..dbe8012 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -33,35 +33,35 @@ bool CustomRenderFunc(Scene& scene, Renderer& renderPipeline, PositionDetector& return true; } -void ConfigureShortcuts(ToolWindow& tw, KeyBinding& kb, CustomRenderWindow& crw) { +void ConfigureShortcuts(ToolWindow& tw, CustomRenderWindow& crw) { // Internal shortcuts. - kb.input->AddShortcut(Key::Combination(Key::Escape), + Input::AddShortcut(Key::Combination(Key::Escape), [&] { tw.Unbind(); }); - kb.input->AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Z), + Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Z), [&] { StateBuffer::Rollback(); }); - kb.input->AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Y), + Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Y), [&] { StateBuffer::Repeat(); }); - kb.input->AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::D), + Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::D), [&] { ObjectSelection::RemoveAll(); }); // Tools - kb.input->AddShortcut(Key::Combination(Key::T), + Input::AddShortcut(Key::Combination(Key::T), [&] { tw.ApplyTool(); }); - kb.input->AddShortcut(Key::Combination(Key::P), + Input::AddShortcut(Key::Combination(Key::P), [&] { tw.ApplyTool(); }); - kb.input->AddShortcut(Key::Combination(Key::E), + Input::AddShortcut(Key::Combination(Key::E), [&] { tw.ApplyTool, ExtrusionEditingTool>(); }); // Render - kb.input->AddShortcut(Key::Combination(Key::F5), + Input::AddShortcut(Key::Combination(Key::F5), [&] { crw.shouldSaveViewportImage = true; }); - kb.input->AddShortcut(Key::Combination(Key::F6), + Input::AddShortcut(Key::Combination(Key::F6), [&] { crw.shouldSaveAdvancedImage = true; }); // State - kb.input->AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Q), + Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Q), [&] { Settings::UseDiscreteMovement() = !Settings::UseDiscreteMovement().Get(); }); - kb.input->AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::W), + Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::W), [&] { Settings::SpaceMode() = Settings::SpaceMode().Get() == SpaceMode::Local ? SpaceMode::World : SpaceMode::Local; }); } @@ -207,7 +207,7 @@ int main() { customRenderWindow.OnResize() += updateCacheForAllObjects; camera.OnPropertiesChanged() += updateCacheForAllObjects; - ConfigureShortcuts(toolWindow, gui.keyBinding, customRenderWindow); + ConfigureShortcuts(toolWindow, customRenderWindow); // Start the main loop and clean the memory when closed. if (!gui.MainLoop() | From a6ee31522fe813e49038298a90acd5f59457927d Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Wed, 5 May 2021 21:49:37 +0300 Subject: [PATCH 03/10] simplified math classes --- StereoPlus2/DomainTypes.hpp | 10 +-- StereoPlus2/Math.hpp | 173 +++++++++++++++++------------------- 2 files changed, 89 insertions(+), 94 deletions(-) diff --git a/StereoPlus2/DomainTypes.hpp b/StereoPlus2/DomainTypes.hpp index 4d6bb64..1f8a23c 100644 --- a/StereoPlus2/DomainTypes.hpp +++ b/StereoPlus2/DomainTypes.hpp @@ -763,9 +763,9 @@ class Camera : public LeafObject Camera() { Name = "camera"; EyeToCenterDistance.OnChanged() += [&](const float& v) { - eyeToCenterDistance = Convert::Unit::MillimetersToViewCoordinates(v, ViewSize->x); }; + eyeToCenterDistance = Convert::MillimetersToViewCoordinates(v, ViewSize->x); }; PositionModifier.OnChanged() += [&](const glm::vec3& v) { - positionModifier = Convert::Unit::MillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); }; + positionModifier = Convert::MillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); }; ViewSize.OnChanged() += [&](const glm::vec2 v) { // Trigger conversion. @@ -779,10 +779,10 @@ class Camera : public LeafObject } glm::vec3 GetLeft(const glm::vec3& v) { - return Convert::Stereo::GetLeft(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); + return Stereo::GetLeft(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); } glm::vec3 GetRight(const glm::vec3& v) { - return Convert::Stereo::GetRight(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); + return Stereo::GetRight(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ); } @@ -795,7 +795,7 @@ class Camera : public LeafObject ImGui::Extensions::PushActive(false); ImGui::DragFloat2("view size", (float*)&ViewSize.Get()); - auto viewSizeMillimeters = Convert::Unit::PixelsToMillimeters(ViewSize.Get()); + auto viewSizeMillimeters = Convert::PixelsToMillimeters(ViewSize.Get()); ImGui::DragFloat2("view size millimeters", (float*)(&viewSizeMillimeters), 1, 0, 0, "%.1f"); ImGui::Extensions::PopActive(); diff --git a/StereoPlus2/Math.hpp b/StereoPlus2/Math.hpp index a4d984c..0416e4b 100644 --- a/StereoPlus2/Math.hpp +++ b/StereoPlus2/Math.hpp @@ -138,111 +138,106 @@ class Transform { }; struct Convert { - struct Unit { - // Millimeters to pixels - static glm::vec3 MillimetersToPixels(const glm::vec3& vMillimeters) { - static float inchToMillimeter = 0.0393701; - // vMillimiters[millimiter] - // inchToMillemeter[inch/millimeter] - // PPI[pixel/inch] - // vMillimiters*PPI*inchToMillemeter[millimeter*(pixel/inch)*(inch/millimeter) = millimeter*(pixel/millimeter) = pixel] - auto vPixels = Settings::PPI().Get() * inchToMillimeter * vMillimeters; - return vPixels; - } + // Millimeters to pixels + static glm::vec3 MillimetersToPixels(const glm::vec3& vMillimeters) { + static float inchToMillimeter = 0.0393701; + // vMillimiters[millimiter] + // inchToMillemeter[inch/millimeter] + // PPI[pixel/inch] + // vMillimiters*PPI*inchToMillemeter[millimeter*(pixel/inch)*(inch/millimeter) = millimeter*(pixel/millimeter) = pixel] + auto vPixels = Settings::PPI().Get() * inchToMillimeter * vMillimeters; + return vPixels; + } - // Millimeters to [-1;1] - // World center-centered - // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates - static glm::vec3 MillimetersToViewCoordinates(const glm::vec3& vMillimeters, const glm::vec2& viewSizePixels, const float& viewSizeZMillimeters) { - static float inchToMillimeter = 0.0393701; - auto vsph = viewSizePixels / 2.f; - auto vszmh = viewSizeZMillimeters / 2.f; - - auto vView = glm::vec3( - vMillimeters.x * Settings::PPI().Get() * inchToMillimeter / vsph.x, - vMillimeters.y * Settings::PPI().Get() * inchToMillimeter / vsph.y, - vMillimeters.z / vszmh - ); - return vView; - } + // Millimeters to [-1;1] + // World center-centered + // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates + static glm::vec3 MillimetersToViewCoordinates(const glm::vec3& vMillimeters, const glm::vec2& viewSizePixels, const float& viewSizeZMillimeters) { + static float inchToMillimeter = 0.0393701; + auto vsph = viewSizePixels / 2.f; + auto vszmh = viewSizeZMillimeters / 2.f; + + auto vView = glm::vec3( + vMillimeters.x * Settings::PPI().Get() * inchToMillimeter / vsph.x, + vMillimeters.y * Settings::PPI().Get() * inchToMillimeter / vsph.y, + vMillimeters.z / vszmh + ); + return vView; + } - // Millimeters to [-1;1] - // World center-centered - // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates - static float MillimetersToViewCoordinates(const float& vMillimeters, const float& viewSizePixels) { - static float inchToMillimeter = 0.0393701; - auto vsph = viewSizePixels / 2.f; + // Millimeters to [-1;1] + // World center-centered + // (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates + static float MillimetersToViewCoordinates(const float& vMillimeters, const float& viewSizePixels) { + static float inchToMillimeter = 0.0393701; + auto vsph = viewSizePixels / 2.f; - auto vView = vMillimeters * Settings::PPI().Get() * inchToMillimeter / vsph; - return vView; - } + auto vView = vMillimeters * Settings::PPI().Get() * inchToMillimeter / vsph; + return vView; + } - // Pixels to Millimeters - static glm::vec3 PixelsToMillimeters(const glm::vec3& vPixels) { - static float inchToMillimeter = 0.0393701; - // vPixels[pixel] - // inchToMillimeter[inch/millimeter] - // PPI[pixel/inch] - // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] - auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; - return vMillimiters; - } - static glm::vec2 PixelsToMillimeters(const glm::vec2& vPixels) { - static float inchToMillimeter = 0.0393701; - // vPixels[pixel] - // inchToMillimeter[inch/millimeter] - // PPI[pixel/inch] - // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] - auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; - return vMillimiters; - } + // Pixels to Millimeters + static glm::vec3 PixelsToMillimeters(const glm::vec3& vPixels) { + static float inchToMillimeter = 0.0393701; + // vPixels[pixel] + // inchToMillimeter[inch/millimeter] + // PPI[pixel/inch] + // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] + auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; + return vMillimiters; + } + static glm::vec2 PixelsToMillimeters(const glm::vec2& vPixels) { + static float inchToMillimeter = 0.0393701; + // vPixels[pixel] + // inchToMillimeter[inch/millimeter] + // PPI[pixel/inch] + // vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter] + auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter; + return vMillimiters; + } +}; - }; - class Stereo { - static glm::vec3 getLeft(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { - auto pos = Convert::Unit::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); - float denominator = cameraPos.z - pos.z; - return glm::vec3( - (pos.x * cameraPos.z - pos.z * (cameraPos.x - eyeToCenterDistance)) / denominator, - (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, - 0 - ); - } - static glm::vec3 getRight(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { - auto pos = Convert::Unit::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); - float denominator = cameraPos.z - pos.z; - return glm::vec3( - (pos.x * cameraPos.z - pos.z * (cameraPos.x + eyeToCenterDistance)) / denominator, - (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, - 0 - ); - } - public: - static glm::vec3 GetLeft(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { - return getLeft(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); - } - static glm::vec3 GetRight(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { - return getRight(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); - } +class Stereo { + static glm::vec3 getLeft(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + auto pos = Convert::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); + float denominator = cameraPos.z - pos.z; + return glm::vec3( + (pos.x * cameraPos.z - pos.z * (cameraPos.x - eyeToCenterDistance)) / denominator, + (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, + 0 + ); + } + static glm::vec3 getRight(const glm::vec3& posMillimeters, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + auto pos = Convert::MillimetersToViewCoordinates(posMillimeters, viewSize, viewSizeZ); + float denominator = cameraPos.z - pos.z; + return glm::vec3( + (pos.x * cameraPos.z - pos.z * (cameraPos.x + eyeToCenterDistance)) / denominator, + (cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator, + 0 + ); + } +public: + static glm::vec3 GetLeft(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + return getLeft(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); + } + static glm::vec3 GetRight(const glm::vec3& v, const glm::vec3& cameraPos, float eyeToCenterDistance, const glm::vec2& viewSize, float viewSizeZ) { + return getRight(v, cameraPos, eyeToCenterDistance, viewSize, viewSizeZ); + } - }; }; class Build { static glm::quat getRotation(glm::vec3 ac, glm::vec3 ab) { - auto zPlaneLocal = glm::cross(ac, ab); - zPlaneLocal = glm::normalize(zPlaneLocal); + auto zPlaneLocal = glm::normalize(glm::cross(ac, ab)); auto zPlaneGlobal = glm::vec3(0, 0, 1); auto r1 = glm::rotation(zPlaneGlobal, zPlaneLocal); - auto acRotatedBack = glm::rotate(glm::inverse(r1), ac); - acRotatedBack = glm::normalize(acRotatedBack); + auto acRotatedBack = glm::normalize(glm::rotate(glm::inverse(r1), ac)); auto r2 = glm::rotation(glm::vec3(1, 0, 0), acRotatedBack); - auto r = r1 * r2; - return r; + return r1 * r2; } public: @@ -256,7 +251,7 @@ class Build { auto ac = vertices[2] - vertices[0]; auto ab = vertices[1] - vertices[0]; auto bc = vertices[2] - vertices[1]; - + auto acUnit = glm::normalize(ac); auto abadScalarProjection = glm::dot(ab, acUnit); auto db = ab - acUnit * abadScalarProjection; From 798a6b265ca75eb59a96a9a3b97f244d55962596 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sat, 8 May 2021 17:33:59 +0300 Subject: [PATCH 04/10] separete pivot mode. Reworked rotation math --- StereoPlus2/Math.hpp | 83 ++++++++++++++++++++++++++++++---------- StereoPlus2/Tools.hpp | 84 ++++++++++++++++++++++++----------------- StereoPlus2/Windows.hpp | 55 +++++++++++++-------------- StereoPlus2/main.cpp | 2 + 4 files changed, 141 insertions(+), 83 deletions(-) diff --git a/StereoPlus2/Math.hpp b/StereoPlus2/Math.hpp index 0416e4b..2f57514 100644 --- a/StereoPlus2/Math.hpp +++ b/StereoPlus2/Math.hpp @@ -85,6 +85,15 @@ class Transform { target->SetVertice(i, (target->GetVertices()[i] - center) / oldScale * scale + center); } } + static void Translate(const glm::vec3& transformVector, SceneObject* cross) { + if (Settings::SpaceMode().Get() == SpaceMode::Local) { + auto r = glm::rotate(cross->GetWorldRotation(), transformVector); + cross->SetWorldPosition(cross->GetWorldPosition() + r); + return; + } + + cross->SetWorldPosition(cross->GetWorldPosition() + transformVector); + } static void Translate(const glm::vec3& transformVector, std::list& targets, SceneObject* cross) { // Need to calculate average rotation. // https://stackoverflow.com/questions/12374087/average-of-multiple-quaternions/27410865#27410865 @@ -107,6 +116,26 @@ class Transform { o->SetVertice(i, o->GetVertices()[i] + transformVector); } } + static void Rotate(const glm::vec3& center, const glm::vec3& rotation, SceneObject* cross) { + glm::vec3 axe; + float angle; + + if (!tryGetLocalRotation(rotation, axe, angle)) + return; + + auto r = glm::normalize(glm::angleAxis(angle, axe)); + + // Convert local rotation to global rotation. + // It is required to rotate all vertices since they don't store their own rotation + // meaning that their rotation = (0;0;0;1). + // + // When multiple objects are selected cross' rotation is equal to the first + // object in selection. See TransformTool::OnSelectionChanged + if (Settings::SpaceMode().Get() == SpaceMode::Local) + r = getIsolatedRotation(r, cross->GetWorldRotation()); + + cross->SetLocalRotation(r * cross->GetLocalRotation()); + } static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list& targets, SceneObject* cross) { glm::vec3 axe; float angle; @@ -227,19 +256,40 @@ class Stereo { }; class Build { - static glm::quat getRotation(glm::vec3 ac, glm::vec3 ab) { - auto zPlaneLocal = glm::normalize(glm::cross(ac, ab)); + // Rotation on angle between orig and dest from the view point of observer. + static glm::quat rotation(const glm::vec3& orig, const glm::vec3& dest, const glm::vec3& observer) + { + auto cosTheta = dot(orig, dest); - auto zPlaneGlobal = glm::vec3(0, 0, 1); + if (cosTheta >= 1.f - glm::epsilon()) + // orig and dest point in the same direction + return glm::quat(1,0,0,0); - auto r1 = glm::rotation(zPlaneGlobal, zPlaneLocal); + if (cosTheta < -1.f + glm::epsilon()) + // orig and dest point in the opposite directions + // so the rotation axis is observer. + return glm::angleAxis(glm::pi(), observer); - auto acRotatedBack = glm::normalize(glm::rotate(glm::inverse(r1), ac)); + // Implementation from Stan Melax's Game Programming Gems 1 article + auto rotationAxis = cross(orig, dest); - auto r2 = glm::rotation(glm::vec3(1, 0, 0), acRotatedBack); - return r1 * r2; + auto sinTheta = sqrt((1.f + cosTheta) * 2.f); + + return glm::quat(sinTheta / 2, rotationAxis / sinTheta); } + static glm::quat getSpaceOrientation(const glm::vec3& xLocal, const glm::vec3& yLocal) { + auto yGlobal = glm::vec3(0, 1, 0);// Y global + auto xGlobal = glm::vec3(1, 0, 0);// X global + + auto rY = rotation(yGlobal, yLocal, xGlobal);// rotation of Y axis + + auto xLocalRotatedBack = glm::normalize(glm::rotate(glm::inverse(rY), xLocal)); + + auto rX = rotation(xGlobal, xLocalRotatedBack, yGlobal);// rotation of X axis + + return rY * rX; + } public: /// @@ -254,19 +304,16 @@ class Build { auto acUnit = glm::normalize(ac); auto abadScalarProjection = glm::dot(ab, acUnit); - auto db = ab - acUnit * abadScalarProjection; - auto abdbScalarProjection = glm::dot(ab, glm::normalize(db)); + auto dbUnit = glm::normalize(ab - acUnit * abadScalarProjection); + auto abdbScalarProjection = glm::dot(ab, dbUnit); if (isnan(abadScalarProjection) || isnan(abdbScalarProjection)) - return { vertices[1], vertices[2] }; + return { vertices[0], vertices[1], vertices[2] }; - auto r = getRotation(ac, ab); + auto r = getSpaceOrientation(acUnit, dbUnit); if (isnan(r.x) || isnan(r.y) || isnan(r.z) || isnan(r.w)) - return { vertices[1], vertices[2] }; - - auto rotatedY = glm::rotate(r, glm::vec3(0, 1, 0)); - auto sameDirection = glm::dot(glm::normalize(db), rotatedY) > 0; + return { vertices[0], vertices[1], vertices[2] }; auto acLength = glm::length(ac); auto abLength = glm::length(ab); @@ -274,7 +321,7 @@ class Build { auto adLength = abadScalarProjection; auto dcLength = acLength - adLength; - static const auto hpi = 3.1415926 / 2.; + static const auto hpi = glm::half_pi(); auto bcLength = glm::length(bc); @@ -296,10 +343,6 @@ class Build { points.push_back(glm::vec3(nx, ny, 0)); } - if (!sameDirection) - for (size_t j = 0; j < points.size(); j++) - points[j].y = -points[j].y; - for (size_t j = 0; j < points.size(); j++) points[j] = glm::rotate(r, points[j]) + vertices[0]; diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index 69ae6fd..51e14e1 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -1038,46 +1038,50 @@ class TransformTool : public EditingTool { // Check if we need to process tool. if (targets.parentObjects.empty() || !targets.parentObjects.front().HasValue()) { - MoveCross(relativeMovement); + TransformCross(relativeMovement, relativeScale, relativeRotation); + //TranslateCross(relativeMovement); return; } if (input->IsDown(Key::Escape, true)) { - MoveCross(relativeMovement); + TransformCross(relativeMovement, relativeScale, relativeRotation); + //TranslateCross(relativeMovement); UnbindSceneObjects(); return; } - switch (mode) { - case Mode::Translate: - if (relativeMovement == zero) - return; + if (Settings::TargetMode().Get() == TargetMode::Pivot) + TransformCross(relativeMovement, relativeScale, relativeRotation); + else + switch (mode) { + case Mode::Translate: + if (relativeMovement == zero) + return; - Translate(relativeMovement, targets.parentObjects); - break; - case Mode::Scale: - MoveCross(relativeMovement); - if (relativeScale == oldScale) - return; - - Scale(cross->GetWorldPosition(), oldScale, relativeScale, targets.parentObjects); - oldScale = scale = relativeScale; - break; - case Mode::Rotate: - MoveCross(relativeMovement); - if (relativeRotation == zero) - return; - - Rotate(cross->GetWorldPosition(), relativeRotation, targets.parentObjects); - nullifyUntouchedAngles(); - oldAngle = angle; - break; - default: - Logger.Warning("Unsupported Editing Tool target Type or Unsupported combination of ObjectType and Transformation"); - break; - } + Translate(relativeMovement, targets.parentObjects); + break; + case Mode::Scale: + TransformCross(relativeMovement, relativeScale, relativeRotation); + if (relativeScale == oldScale) + return; + + Scale(cross->GetWorldPosition(), oldScale, relativeScale, targets.parentObjects); + oldScale = scale = relativeScale; + break; + case Mode::Rotate: + TranslateCross(relativeMovement); + if (relativeRotation == zero) + return; + + Rotate(cross->GetWorldPosition(), relativeRotation, targets.parentObjects); + nullifyUntouchedAngles(); + oldAngle = angle; + break; + default: + Logger.Warning("Unsupported Editing Tool target Type or Unsupported combination of ObjectType and Transformation"); + break; + } transformOldPos = transformPos; - cross->ForceUpdateCache(); } void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list& targets) { if (shouldTrace) @@ -1138,9 +1142,19 @@ class TransformTool : public EditingTool { } } - - void MoveCross(const glm::vec3& movement) { - cross->SetLocalPosition(cross->GetLocalPosition() + movement); + void TransformCross(const glm::vec3& relativeMovement, const float relativeScale, const glm::vec3& relativeRotation) { + if (relativeMovement != glm::vec3()) + Transform::Translate(relativeMovement, &cross.Get()); + if (relativeRotation != glm::vec3()) { + Transform::Rotate(cross->GetWorldPosition(), relativeRotation, &cross.Get()); + nullifyUntouchedAngles(); + oldAngle = angle; + } + if (relativeScale != oldScale) + oldScale = scale = relativeScale; + } + void TranslateCross(const glm::vec3& transformVector) { + Transform::Translate(transformVector, &cross.Get()); } void nullifyUntouchedAngles() { @@ -1188,7 +1202,7 @@ class TransformTool : public EditingTool { targets.orphanedObjects.clear(); targets.parentObjects.clear(); - for (auto o : v) + for (auto& o : v) targets.parentObjects.push_back(o); cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); @@ -1344,7 +1358,7 @@ class SinePenTool : public EditingTool { return; } - if (cross->GetWorldPosition() == target->GetVertices().back()) + if (cross->GetWorldPosition() == target->GetVertices()[currentVertice]) return; target->SetVertice(currentVertice, cross->GetWorldPosition()); diff --git a/StereoPlus2/Windows.hpp b/StereoPlus2/Windows.hpp index 75070c9..92d37bc 100644 --- a/StereoPlus2/Windows.hpp +++ b/StereoPlus2/Windows.hpp @@ -1329,25 +1329,25 @@ class ToolWindow : Window { virtual bool Design() { auto windowName = LocaleProvider::Get(Window::name) + "###" + Window::name; ImGui::Begin(windowName.c_str()); - - if (ImGui::Button(LocaleProvider::GetC("object:polyline"))) - polyLineTool.Create(); - if (ImGui::Button(LocaleProvider::GetC("object:sinecurve"))) - sineCurveTool.Create(); - if (ImGui::Button(LocaleProvider::GetC("object:group"))) - groupObjectTool.Create(); - - ImGui::Separator(); - - if (ImGui::Button(LocaleProvider::GetC("tool:extrusion"))) - ApplyTool, ExtrusionEditingTool>(); - if (ImGui::Button(LocaleProvider::GetC("tool:pen"))) - ApplyTool(); - if (ImGui::Button(LocaleProvider::GetC("tool:sinepen"))) - ApplyTool(); - if (ImGui::Button(LocaleProvider::GetC("tool:transformation"))) - ApplyTool(); - + { + if (ImGui::Button(LocaleProvider::GetC("object:polyline"))) + polyLineTool.Create(); + if (ImGui::Button(LocaleProvider::GetC("object:sinecurve"))) + sineCurveTool.Create(); + if (ImGui::Button(LocaleProvider::GetC("object:group"))) + groupObjectTool.Create(); + } + { + ImGui::Separator(); + if (ImGui::Button(LocaleProvider::GetC("tool:extrusion"))) + ApplyTool, ExtrusionEditingTool>(); + if (ImGui::Button(LocaleProvider::GetC("tool:pen"))) + ApplyTool(); + if (ImGui::Button(LocaleProvider::GetC("tool:sinepen"))) + ApplyTool(); + if (ImGui::Button(LocaleProvider::GetC("tool:transformation"))) + ApplyTool(); + } { ImGui::Separator(); auto v = (int)Settings::SpaceMode().Get(); @@ -1356,15 +1356,14 @@ class ToolWindow : Window { if (ImGui::RadioButton(LocaleProvider::GetC("local"), &v, (int)SpaceMode::Local)) Settings::SpaceMode() = SpaceMode::Local; } - //{ - // ImGui::Separator(); - // ImGui::Text(LocaleProvider::GetC("actionOnParentChange")); - // static int v = (int)Settings::MoveCoordinateAction().Get(); - // if (ImGui::RadioButton(LocaleProvider::GetC("adaptCoordinates"), &v, (int)MoveCoordinateAction::Adapt)) - // Settings::MoveCoordinateAction() = MoveCoordinateAction::Adapt; - // if (ImGui::RadioButton(LocaleProvider::GetC("none"), &v, (int)MoveCoordinateAction::None)) - // Settings::MoveCoordinateAction() = MoveCoordinateAction::None; - //} + { + ImGui::Separator(); + auto v = (int)Settings::TargetMode().Get(); + if (ImGui::RadioButton(LocaleProvider::GetC("object"), &v, (int)TargetMode::Object)) + Settings::TargetMode() = TargetMode::Object; + if (ImGui::RadioButton(LocaleProvider::GetC("pivot"), &v, (int)TargetMode::Pivot)) + Settings::TargetMode() = TargetMode::Pivot; + } ImGui::Separator(); if (bool v = Settings::UseDiscreteMovement().Get(); diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index dbe8012..8e8c03f 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -63,6 +63,8 @@ void ConfigureShortcuts(ToolWindow& tw, CustomRenderWindow& crw) { [&] { Settings::UseDiscreteMovement() = !Settings::UseDiscreteMovement().Get(); }); Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::W), [&] { Settings::SpaceMode() = Settings::SpaceMode().Get() == SpaceMode::Local ? SpaceMode::World : SpaceMode::Local; }); + Input::AddShortcut(Key::Combination(Key::C), + [&] { Settings::TargetMode() = Settings::TargetMode().Get() == TargetMode::Object ? TargetMode::Pivot : TargetMode::Object; }); } int main() { From 6d94bfd530e9053ef19336ae3cb4b062031eb167 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 11:14:59 +0300 Subject: [PATCH 05/10] added function property --- StereoPlus2/InfrastructureTypes.hpp | 108 +++++++++++++++++++++++++++- StereoPlus2/Tools.hpp | 23 +++--- StereoPlus2/Windows.hpp | 26 +++---- StereoPlus2/main.cpp | 30 ++++---- 4 files changed, 150 insertions(+), 37 deletions(-) diff --git a/StereoPlus2/InfrastructureTypes.hpp b/StereoPlus2/InfrastructureTypes.hpp index b7f4d72..4d7c2a1 100644 --- a/StereoPlus2/InfrastructureTypes.hpp +++ b/StereoPlus2/InfrastructureTypes.hpp @@ -442,6 +442,7 @@ template class PropertyNode { T value; Event changed; + bool isAssigned = false; public: const T& Get() const { return value; @@ -451,18 +452,19 @@ class PropertyNode { } void Set(const T& v) { value = v; + isAssigned = true; changed.Invoke(v); } IEvent& OnChanged() { return changed; } bool IsAssigned() { - return true; + return isAssigned; } }; template class PropertyNode { - T* value; + T* value = nullptr; Event changed; public: const T& Get() const { @@ -482,6 +484,31 @@ class PropertyNode { return value != nullptr; } }; +template +class PropertyNode> { + std::function value; + Event> changed; + bool isAssigned = false; +public: + const std::function& Get() const { + return value; + } + void Set(const std::function& v) { + value = v; + isAssigned = true; + changed.Invoke(v); + } + IEvent>& OnChanged() { + return changed; + } + bool IsAssigned() { + return isAssigned; + } + R operator()(T... vs) { + return value(vs...); + } +}; + template class ReadonlyProperty { @@ -565,6 +592,47 @@ class ReadonlyProperty { ReplaceNode(v.node); } }; +template +class ReadonlyProperty> { +protected: + std::shared_ptr>> node = std::make_shared>>(); + ReadonlyProperty(const std::shared_ptr>>& node) { + this->node = node; + } + void ReplaceNode(const std::shared_ptr>>& node) { + node->OnChanged().AddHandlersFrom(this->node->OnChanged()); + this->node = node; + } +public: + ReadonlyProperty() {} + ReadonlyProperty(std::function o) { + node->Set(o); + } + + bool IsAssigned() { + return node->IsAssigned(); + } + + const std::function& Get() const { + return node->Get(); + } + + ReadonlyProperty> CloneReadonly() { + return new ReadonlyProperty(node); + } + + IEvent>& OnChanged() { + return node->OnChanged(); + } + + ReadonlyProperty>& operator=(const ReadonlyProperty>&) = delete; + R operator()(T... vs) const { + return Get()(vs...); + } + void operator<<=(const ReadonlyProperty>& v) { + ReplaceNode(v.node); + } +}; template class NonAssignProperty : public ReadonlyProperty { @@ -618,6 +686,25 @@ class NonAssignProperty : public ReadonlyProperty { ReadonlyProperty::ReplaceNode(v.node); } }; +template +class NonAssignProperty> : public ReadonlyProperty> { +protected: + NonAssignProperty(const PropertyNode>& node) { + ReadonlyProperty>::node = node; + } +public: + NonAssignProperty() {} + NonAssignProperty(const std::function& o) : ReadonlyProperty>(o) {} + + NonAssignProperty> CloneNonAssign() { + return new NonAssignProperty(ReadonlyProperty>::node); + } + + NonAssignProperty>& operator=(const NonAssignProperty>&) = delete; + void operator<<=(const NonAssignProperty>& v) { + ReadonlyProperty>::ReplaceNode(v.node); + } +}; template class Property : public NonAssignProperty { @@ -651,6 +738,23 @@ class Property : public NonAssignProperty { ReadonlyProperty::ReplaceNode(v.node); } }; +template +class Property< std::function> : public NonAssignProperty> { +public: + Property() {} + Property(const std::function& o) : NonAssignProperty>(o) {} + Property(const Property>&) = delete; + + + Property>& operator=(const Property>&) = delete; + Property>& operator=(const std::function& v) { + ReadonlyProperty>::node->Set(v); + return *this; + } + void operator<<=(const Property>& v) { + ReadonlyProperty>::ReplaceNode(v.node); + } +}; #define StaticProperty(type,name)\ static Property& name() {\ diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index 51e14e1..f2e890b 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -212,7 +212,7 @@ class PenTool : public EditingTool { // If the cos between vectors is less than E // then we merge those vectors. - double E = 1e-6; + float E = 1e-6; // If distance between previous point and // cursor is less than this number @@ -985,9 +985,9 @@ class TransformTool : public EditingTool { auto maxAxe = 0; // Find non-zero axes - int t[2] = {0,0}; - size_t n = 0; - for (size_t i = 0; i < 3; i++) { + short t[2] = {0,0}; + short n = 0; + for (short i = 0; i < 3; i++) { if (mouseAxe[i] != 0) t[n] = i; } @@ -1159,9 +1159,9 @@ class TransformTool : public EditingTool { void nullifyUntouchedAngles() { auto da = angle - oldAngle; - for (size_t i = 0; i < 3; i++) - if (da[i] == 0) - angle[i] = oldAngle [i] = 0; + for (auto i = 0; i < 3; i++) + if (da[i] == 0.f) + angle[i] = oldAngle[i] = 0.f; } @@ -1213,6 +1213,13 @@ class TransformTool : public EditingTool { keyBinding->RemoveHandler(cross->keyboardBindingHandlerId); inputHandlerId = keyBinding->AddHandler([this](Input* input) { this->ProcessInput(type, mode, input); }); + //inputHandlerId = keyBinding->AddHandler([this](Input* input) { + // this->ProcessInput(type, mode, input); + // if (input->IsDown(Key::N5)) + // cross->SetWorldPosition(Avg(GetWorldPositions(targets.parentObjects))); + // else if (input->IsDown(Key::N0)) + // cross->SetWorldPosition(glm::vec3(0,0,0)); + // }); stateChangedHandlerId = StateBuffer::OnStateChange().AddHandler([&] { cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); }); @@ -1315,7 +1322,7 @@ class SinePenTool : public EditingTool { bool createdAdditionalPoints; bool createdNewObject; - int currentVertice = 0; + size_t currentVertice = 0; void Step123() { if (!createdAdditionalPoints || target->GetVertices().empty()) { diff --git a/StereoPlus2/Windows.hpp b/StereoPlus2/Windows.hpp index 92d37bc..6729c72 100644 --- a/StereoPlus2/Windows.hpp +++ b/StereoPlus2/Windows.hpp @@ -1266,7 +1266,8 @@ class ToolWindow : Window { } public: - AttributesWindow* attributesWindow; + StaticProperty(::AttributesWindow*, AttributesWindow) + StaticProperty(std::function, ApplyDefaultTool) template using unbindTool = decltype(std::declval().UnbindTool()); @@ -1274,23 +1275,23 @@ class ToolWindow : Window { template static constexpr bool hasUnbindTool = is_detected_v; - template> * = nullptr> - void ApplyTool() { + template>* = nullptr> + static void ApplyTool() { auto tool = new TWindow(); tool->tool = ToolPool::GetTool(); tool->tool->Activate(); auto targetWindow = new SceneObjectPropertiesWindow(); - attributesWindow->UnbindTarget(); - attributesWindow->UnbindTool(); - attributesWindow->BindTool((Attributes*)tool); - attributesWindow->BindTarget((Attributes*)targetWindow); + AttributesWindow()->UnbindTarget(); + AttributesWindow()->UnbindTool(); + AttributesWindow()->BindTool((Attributes*)tool); + AttributesWindow()->BindTarget((Attributes*)targetWindow); auto deleteAllhandlerId = Scene::OnDeleteAll() += [t = tool] { t->UnbindTargets(); t->tool->UnbindTool(); }; - attributesWindow->onUnbindTool = [t = tool, d = deleteAllhandlerId] { + AttributesWindow()->onUnbindTool = [t = tool, d = deleteAllhandlerId] { t->tool->UnbindTool(); Scene::OnDeleteAll().RemoveHandler(d); t->OnExit(); @@ -1298,15 +1299,14 @@ class ToolWindow : Window { }; } - - void Unbind() { + /*void Unbind() { attributesWindow->UnbindTarget(); attributesWindow->UnbindTool(); - } + }*/ virtual bool Init() { - if (attributesWindow == nullptr) + if (!AttributesWindow().IsAssigned()) { log.Error("AttributesWindow was null"); return false; @@ -1549,7 +1549,7 @@ class SettingsWindow : Window { } if (auto v = Settings::StateBufferLength().Get(); - ImGui::InputInt(LocaleProvider::GetC(Settings::Name(&Settings::StateBufferLength)), &v, 0.01, 0.1, 4)) + ImGui::InputInt(LocaleProvider::GetC(Settings::Name(&Settings::StateBufferLength)), &v, 1, 10, 4)) Settings::StateBufferLength() = v; if (auto v = Settings::Language().Get(); ImGui::TreeNode((LocaleProvider::Get(Settings::Name(&Settings::Language)) + ": " + LocaleProvider::Get(v)).c_str())) { diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index 8e8c03f..4ca10a9 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -33,24 +33,24 @@ bool CustomRenderFunc(Scene& scene, Renderer& renderPipeline, PositionDetector& return true; } -void ConfigureShortcuts(ToolWindow& tw, CustomRenderWindow& crw) { +void ConfigureShortcuts(CustomRenderWindow& crw) { // Internal shortcuts. Input::AddShortcut(Key::Combination(Key::Escape), - [&] { tw.Unbind(); }); + ToolWindow::ApplyDefaultTool().Get()); Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Z), - [&] { StateBuffer::Rollback(); }); + StateBuffer::Rollback); Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Y), - [&] { StateBuffer::Repeat(); }); + StateBuffer::Repeat); Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::D), - [&] { ObjectSelection::RemoveAll(); }); + ObjectSelection::RemoveAll); // Tools Input::AddShortcut(Key::Combination(Key::T), - [&] { tw.ApplyTool(); }); + ToolWindow::ApplyTool); Input::AddShortcut(Key::Combination(Key::P), - [&] { tw.ApplyTool(); }); + ToolWindow::ApplyTool); Input::AddShortcut(Key::Combination(Key::E), - [&] { tw.ApplyTool, ExtrusionEditingTool>(); }); + ToolWindow::ApplyTool, ExtrusionEditingTool>); // Render Input::AddShortcut(Key::Combination(Key::F5), @@ -60,11 +60,11 @@ void ConfigureShortcuts(ToolWindow& tw, CustomRenderWindow& crw) { // State Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Q), - [&] { Settings::UseDiscreteMovement() = !Settings::UseDiscreteMovement().Get(); }); + [] { Settings::UseDiscreteMovement() = !Settings::UseDiscreteMovement().Get(); }); Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::W), - [&] { Settings::SpaceMode() = Settings::SpaceMode().Get() == SpaceMode::Local ? SpaceMode::World : SpaceMode::Local; }); + [] { Settings::SpaceMode() = Settings::SpaceMode().Get() == SpaceMode::Local ? SpaceMode::World : SpaceMode::Local; }); Input::AddShortcut(Key::Combination(Key::C), - [&] { Settings::TargetMode() = Settings::TargetMode().Get() == TargetMode::Object ? TargetMode::Pivot : TargetMode::Object; }); + [] { Settings::TargetMode() = Settings::TargetMode().Get() == TargetMode::Object ? TargetMode::Pivot : TargetMode::Object; }); } int main() { @@ -99,8 +99,6 @@ int main() { Cross cross; // Initialize main components. - toolWindow.attributesWindow = &attributesWindow; - inspectorWindow.rootObject <<= scene.root(); inspectorWindow.input = &gui.input; @@ -165,6 +163,10 @@ int main() { if (!ToolPool::Init()) return false; + ToolWindow::ApplyDefaultTool() = ToolWindow::ApplyTool; + ToolWindow::AttributesWindow() = &attributesWindow; + ToolWindow::ApplyDefaultTool()(); + StateBuffer::BufferSize() <<= Settings::StateBufferLength(); StateBuffer::RootObject() <<= scene.root(); StateBuffer::Objects() <<= scene.Objects(); @@ -209,7 +211,7 @@ int main() { customRenderWindow.OnResize() += updateCacheForAllObjects; camera.OnPropertiesChanged() += updateCacheForAllObjects; - ConfigureShortcuts(toolWindow, customRenderWindow); + ConfigureShortcuts(customRenderWindow); // Start the main loop and clean the memory when closed. if (!gui.MainLoop() | From 3512156482bc08ad4b6f7ae0e9aac0f2a435ed1e Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 14:13:03 +0300 Subject: [PATCH 06/10] separated pivot and object modes for transformation --- StereoPlus2/InfrastructureTypes.hpp | 4 +- StereoPlus2/Input.hpp | 2 + StereoPlus2/Tools.hpp | 72 +++++++++-------------------- StereoPlus2/Windows.hpp | 6 ++- StereoPlus2/main.cpp | 25 ++++++---- 5 files changed, 47 insertions(+), 62 deletions(-) diff --git a/StereoPlus2/InfrastructureTypes.hpp b/StereoPlus2/InfrastructureTypes.hpp index 4d7c2a1..d61c700 100644 --- a/StereoPlus2/InfrastructureTypes.hpp +++ b/StereoPlus2/InfrastructureTypes.hpp @@ -442,7 +442,6 @@ template class PropertyNode { T value; Event changed; - bool isAssigned = false; public: const T& Get() const { return value; @@ -452,14 +451,13 @@ class PropertyNode { } void Set(const T& v) { value = v; - isAssigned = true; changed.Invoke(v); } IEvent& OnChanged() { return changed; } bool IsAssigned() { - return isAssigned; + return true; } }; template diff --git a/StereoPlus2/Input.hpp b/StereoPlus2/Input.hpp index 5b9cd92..4541969 100644 --- a/StereoPlus2/Input.hpp +++ b/StereoPlus2/Input.hpp @@ -215,6 +215,8 @@ class Input { } } + // Checks if key changed state to Pressed. + // ignoreCaptured ignores the key and returns false if keyboard is captured by text input. static bool IsDown(const Key::KeyPair& key, bool ignoreCaptured = false) { if (ignoreCaptured && ImGui::GetIO().WantCaptureKeyboard && !IsAcceptableCombination(key.code, true, 0, Key::Modifier::None)) return false; diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index f2e890b..a99d98d 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -1052,34 +1052,7 @@ class TransformTool : public EditingTool { if (Settings::TargetMode().Get() == TargetMode::Pivot) TransformCross(relativeMovement, relativeScale, relativeRotation); else - switch (mode) { - case Mode::Translate: - if (relativeMovement == zero) - return; - - Translate(relativeMovement, targets.parentObjects); - break; - case Mode::Scale: - TransformCross(relativeMovement, relativeScale, relativeRotation); - if (relativeScale == oldScale) - return; - - Scale(cross->GetWorldPosition(), oldScale, relativeScale, targets.parentObjects); - oldScale = scale = relativeScale; - break; - case Mode::Rotate: - TranslateCross(relativeMovement); - if (relativeRotation == zero) - return; - - Rotate(cross->GetWorldPosition(), relativeRotation, targets.parentObjects); - nullifyUntouchedAngles(); - oldAngle = angle; - break; - default: - Logger.Warning("Unsupported Editing Tool target Type or Unsupported combination of ObjectType and Transformation"); - break; - } + Transform(relativeMovement, relativeScale, relativeRotation); transformOldPos = transformPos; } @@ -1142,6 +1115,19 @@ class TransformTool : public EditingTool { } } + void Transform(const glm::vec3& relativeMovement, const float relativeScale, const glm::vec3& relativeRotation) { + if (relativeMovement != glm::vec3()) + Translate(relativeMovement, targets.parentObjects); + if (relativeRotation != glm::vec3()) { + Rotate(cross->GetWorldPosition(), relativeRotation, targets.parentObjects); + nullifyUntouchedAngles(); + oldAngle = angle; + } + if (relativeScale != oldScale) { + Scale(cross->GetWorldPosition(), oldScale, relativeScale, targets.parentObjects); + oldScale = scale = relativeScale; + } + } void TransformCross(const glm::vec3& relativeMovement, const float relativeScale, const glm::vec3& relativeRotation) { if (relativeMovement != glm::vec3()) Transform::Translate(relativeMovement, &cross.Get()); @@ -1205,22 +1191,19 @@ class TransformTool : public EditingTool { for (auto& o : v) targets.parentObjects.push_back(o); - cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); - if (Settings::SpaceMode().Get() == SpaceMode::World) - cross->SetWorldRotation(cross->unitQuat()); - else if (!targets.parentObjects.empty() && targets.parentObjects.front().HasValue()) - cross->SetLocalRotation(targets.parentObjects.front()->GetWorldRotation()); + if (Settings::TargetMode().Get() == TargetMode::Object) { + cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); + if (Settings::SpaceMode().Get() == SpaceMode::World) + cross->SetWorldRotation(cross->unitQuat()); + else if (!targets.parentObjects.empty() && targets.parentObjects.front().HasValue()) + cross->SetLocalRotation(targets.parentObjects.front()->GetWorldRotation()); + } keyBinding->RemoveHandler(cross->keyboardBindingHandlerId); inputHandlerId = keyBinding->AddHandler([this](Input* input) { this->ProcessInput(type, mode, input); }); - //inputHandlerId = keyBinding->AddHandler([this](Input* input) { - // this->ProcessInput(type, mode, input); - // if (input->IsDown(Key::N5)) - // cross->SetWorldPosition(Avg(GetWorldPositions(targets.parentObjects))); - // else if (input->IsDown(Key::N0)) - // cross->SetWorldPosition(glm::vec3(0,0,0)); - // }); stateChangedHandlerId = StateBuffer::OnStateChange().AddHandler([&] { + if (Settings::TargetMode().Get() == TargetMode::Pivot) + return; cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); }); anyObjectChangedHandlerId = SceneObject::OnBeforeAnyElementChanged().AddHandler([&] { @@ -1234,14 +1217,6 @@ class TransformTool : public EditingTool { spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { transformOldPos = transformPos = oldAngle = angle = glm::vec3(); oldAngle = angle = glm::vec3(); - - if (v == SpaceMode::Local) { - if (!targets.parentObjects.empty() && targets.parentObjects.front().HasValue()) - cross->SetLocalRotation(targets.parentObjects.front()->GetWorldRotation()); - //cross->SetLocalRotation(cross->unitQuat()); - } - else - cross->SetWorldRotation(cross->unitQuat()); }; } @@ -1252,7 +1227,6 @@ class TransformTool : public EditingTool { float scale = 1; glm::vec3 angle; glm::vec3 transformPos; - bool isRelativeMode; bool shouldTrace; CreatingTool traceObjectTool; diff --git a/StereoPlus2/Windows.hpp b/StereoPlus2/Windows.hpp index 6729c72..7d2ac2c 100644 --- a/StereoPlus2/Windows.hpp +++ b/StereoPlus2/Windows.hpp @@ -1021,6 +1021,8 @@ class ExtrusionToolWindow : Window, Attributes { class TransformToolWindow : Window, Attributes { int maxPrecision = 5; + bool isRelativeMode; + glm::vec3 oldAngle = glm::vec3(); std::string GetName(SceneObject* obj) { @@ -1095,9 +1097,9 @@ class TransformToolWindow : Window, Attributes { switch (transformToolModeCopy) { case TransformToolMode::Translate: ImGui::Separator(); - ImGui::Checkbox("Relative", &tool->isRelativeMode); + ImGui::Checkbox("Relative", &isRelativeMode); - if (tool->isRelativeMode) + if (isRelativeMode) DragVector(tool->transformPos, "X", "Y", "Z", "%.5f", 1); else { auto crossPosCopy = tool->cross->GetLocalPosition(); diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index 4ca10a9..021093f 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -49,6 +49,8 @@ void ConfigureShortcuts(CustomRenderWindow& crw) { ToolWindow::ApplyTool); Input::AddShortcut(Key::Combination(Key::P), ToolWindow::ApplyTool); + Input::AddShortcut(Key::Combination(Key::S), + ToolWindow::ApplyTool); Input::AddShortcut(Key::Combination(Key::E), ToolWindow::ApplyTool, ExtrusionEditingTool>); @@ -59,9 +61,9 @@ void ConfigureShortcuts(CustomRenderWindow& crw) { [&] { crw.shouldSaveAdvancedImage = true; }); // State - Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::Q), + Input::AddShortcut(Key::Combination(Key::D), [] { Settings::UseDiscreteMovement() = !Settings::UseDiscreteMovement().Get(); }); - Input::AddShortcut(Key::Combination({ Key::Modifier::Control }, Key::W), + Input::AddShortcut(Key::Combination(Key::W), [] { Settings::SpaceMode() = Settings::SpaceMode().Get() == SpaceMode::Local ? SpaceMode::World : SpaceMode::Local; }); Input::AddShortcut(Key::Combination(Key::C), [] { Settings::TargetMode() = Settings::TargetMode().Get() == TargetMode::Object ? TargetMode::Pivot : TargetMode::Object; }); @@ -105,6 +107,10 @@ int main() { cameraPropertiesWindow.Object = &camera; crossPropertiesWindow.Object = ✗ + ToolWindow::ApplyDefaultTool() = ToolWindow::ApplyTool; + ToolWindow::AttributesWindow() = &attributesWindow; + ToolWindow::ApplyDefaultTool()(); + scene.camera = &camera; scene.glWindow = renderPipeline.glWindow; scene.camera->ViewSize <<= customRenderWindow.RenderSize; @@ -145,17 +151,23 @@ int main() { }; cross.keyboardBindingHandlerId = gui.keyBinding.AddHandler(cross.keyboardBindingHandler); gui.keyBinding.AddHandler([&cross]() { - if (Input::IsDown(Key::N5, true)) { - if (Input::IsPressed(Key::Modifier::Control)) { + if (Input::IsPressed(Key::Modifier::Alt)) { + if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) { glm::vec3 v(0); for (auto& o : ObjectSelection::Selected()) v += o.Get()->GetWorldPosition(); v /= ObjectSelection::Selected().size(); cross.SetWorldPosition(v); } - else + else if (Input::IsDown(Key::N0, true)) cross.SetWorldPosition(glm::vec3()); } + else if (Input::IsPressed(Key::Modifier::Control)) { + if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) + cross.SetWorldRotation(ObjectSelection::Selected().begin()._Ptr->_Myval->GetWorldRotation()); + else if (Input::IsDown(Key::N0, true)) + cross.SetWorldRotation(glm::quat(1,0,0,0)); + } }); @@ -163,9 +175,6 @@ int main() { if (!ToolPool::Init()) return false; - ToolWindow::ApplyDefaultTool() = ToolWindow::ApplyTool; - ToolWindow::AttributesWindow() = &attributesWindow; - ToolWindow::ApplyDefaultTool()(); StateBuffer::BufferSize() <<= Settings::StateBufferLength(); StateBuffer::RootObject() <<= scene.root(); From 8c5ce1edb1f9534088658df7e3001530c3777294 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 15:30:44 +0300 Subject: [PATCH 07/10] made input static --- StereoPlus2/GUI.hpp | 3 +- StereoPlus2/InfrastructureTypes.hpp | 17 +- StereoPlus2/Input.hpp | 215 +++++++++++++----------- StereoPlus2/StereoPlus2.vcxproj | 1 + StereoPlus2/StereoPlus2.vcxproj.filters | 1 + StereoPlus2/Tools.hpp | 118 ++++++------- StereoPlus2/Windows.hpp | 2 +- StereoPlus2/cpp.hint | 8 + StereoPlus2/main.cpp | 31 +--- 9 files changed, 207 insertions(+), 189 deletions(-) create mode 100644 StereoPlus2/cpp.hint diff --git a/StereoPlus2/GUI.hpp b/StereoPlus2/GUI.hpp index c8c8450..d4a58dc 100644 --- a/StereoPlus2/GUI.hpp +++ b/StereoPlus2/GUI.hpp @@ -159,7 +159,6 @@ class GUI { bool Init() { - keyBinding.input = &input; input.GLFWindow() = glWindow; @@ -221,7 +220,7 @@ class GUI { //ImFont* font = io.Fonts->AddFontFromFileTTF("open-sans.ttf", 20); //IM_ASSERT(font != NULL); - input.io = io; + input.io() = io; if (!input.Init() || !keyBinding.Init()) return false; diff --git a/StereoPlus2/InfrastructureTypes.hpp b/StereoPlus2/InfrastructureTypes.hpp index d61c700..2d6cfa9 100644 --- a/StereoPlus2/InfrastructureTypes.hpp +++ b/StereoPlus2/InfrastructureTypes.hpp @@ -754,8 +754,23 @@ class Property< std::function> : public NonAssignProperty& name() {\ - static Property v;\ + static Property v = Property();\ + return v;\ +} + +#define StaticField(type,name)\ +static type& name() {\ + static type v = type();\ + return v;\ +} + +#define StaticFieldDefault(type,name,defaultValue)\ +static type& name() {\ + static type v = defaultValue;\ return v;\ } \ No newline at end of file diff --git a/StereoPlus2/Input.hpp b/StereoPlus2/Input.hpp index 4541969..196bf43 100644 --- a/StereoPlus2/Input.hpp +++ b/StereoPlus2/Input.hpp @@ -52,35 +52,38 @@ class Input { } }; - const Log Logger = Log::For(); + StaticField(glm::vec2, mouseOldPos) + StaticField(glm::vec2, mouseNewPos) - glm::vec2 mouseOldPos; - glm::vec2 mouseNewPos; + //StaticField(bool, isMouseBoundlessMode) + StaticField(bool, isRawMouseMotionSupported) - bool isMouseBoundlessMode = false; - bool isRawMouseMotionSupported = false; + StaticFieldDefault(float, mouseSensivity, 1e-2) + StaticFieldDefault(float, mouseMaxMagnitude, 1e4) - float mouseSensivity = 1e-2; - float mouseMaxMagnitude = 1e4; + StaticFieldDefault(ContinuousInput, continuousInputOneSecondDelay, ContinuousInput(1)) + StaticFieldDefault(ContinuousInput, continuousInputNoDelay, ContinuousInput(0)) - ContinuousInput continuousInputOneSecondDelay = ContinuousInput(1); - ContinuousInput continuousInputNoDelay = ContinuousInput(0); + static std::map>& handlers() { + static std::map> v; + return v; + } static CombinationNode& combinationTree() { static CombinationNode v; return v; } - void FillAxes() { - mouseOldPos = mouseNewPos; - mouseNewPos = ImGui::GetMousePos(); + static void FillAxes() { + mouseOldPos() = mouseNewPos(); + mouseNewPos() = ImGui::GetMousePos(); auto useDiscreteMovement = Settings::UseDiscreteMovement().Get(); - ArrowAxe = glm::vec3( + ArrowAxe() = glm::vec3( -IsPressed(Key::Left, useDiscreteMovement) + IsPressed(Key::Right, useDiscreteMovement), IsPressed(Key::Up, useDiscreteMovement) + -IsPressed(Key::Down, useDiscreteMovement), 0); - NumpadAxe = IsPressed(Key::Modifier::Shift) + NumpadAxe() = IsPressed(Key::Modifier::Shift) ? glm::vec3() : glm::vec3( -IsPressed(Key::N4, useDiscreteMovement) + IsPressed(Key::N6, useDiscreteMovement), @@ -89,12 +92,12 @@ class Input { if (IsCustomRenderImageActive().Get()) { auto mouseMoveDirection = MouseMoveDirection(); - MouseAxe = IsPressed(Key::MouseRight) + MouseAxe() = IsPressed(Key::MouseRight) ? glm::vec3(0, 0, -mouseMoveDirection.y) : glm::vec3(mouseMoveDirection.x, -mouseMoveDirection.y, 0); } - else MouseAxe = glm::vec3(); + else MouseAxe() = glm::vec3(); } static bool InsertCombination( @@ -177,19 +180,18 @@ class Input { public: StaticProperty(GLFWwindow*, GLFWindow); - ImGuiIO* io; + StaticProperty(ImGuiIO*, io) - glm::vec3 ArrowAxe; - glm::vec3 NumpadAxe; - glm::vec3 MouseAxe; + StaticField(glm::vec3, ArrowAxe) + StaticField(glm::vec3, NumpadAxe) + StaticField(glm::vec3, MouseAxe) - glm::vec3 movement; - std::map> handlers; + StaticField(glm::vec3, movement) StaticProperty(bool, IsCustomRenderImageActive) - bool IsMoved() { - return movement != glm::vec3(); + static bool IsMoved() { + return movement() != glm::vec3(); } static bool IsPressed(Key::KeyPair key, bool discreteInput = false) { @@ -226,32 +228,32 @@ class Input { : ImGui::IsKeyPressed(key.code, false); } - bool IsUp(Key::KeyPair key) { + static bool IsUp(Key::KeyPair key) { return key.type == Key::Type::Mouse ? ImGui::IsMouseReleased(key.code) : ImGui::IsKeyReleased(key.code); } - glm::vec2 MousePosition() { - return mouseNewPos; + static glm::vec2 MousePosition() { + return mouseNewPos(); } - glm::vec2 MouseMoveDirection() { - return glm::length(mouseNewPos - mouseOldPos) == 0 ? glm::vec2(0) : mouseNewPos - mouseOldPos; + static glm::vec2 MouseMoveDirection() { + return glm::length(mouseNewPos() - mouseOldPos()) == 0 ? glm::vec2(0) : mouseNewPos() - mouseOldPos(); } // Does not include mouse movement nor scrolling. - bool IsContinuousInputOneSecondDelay() { - return continuousInputOneSecondDelay.isContinuousInput; + static bool IsContinuousInputOneSecondDelay() { + return continuousInputOneSecondDelay().isContinuousInput; } - bool IsContinuousInputNoDelay() { - return continuousInputNoDelay.isContinuousInput; + static bool IsContinuousInputNoDelay() { + return continuousInputNoDelay().isContinuousInput; } - bool MouseMoved() { - return MouseSpeed() > mouseSensivity && MouseSpeed() < mouseMaxMagnitude; + static bool MouseMoved() { + return MouseSpeed() > mouseSensivity() && MouseSpeed() < mouseMaxMagnitude(); } - float MouseSpeed() { - return glm::length(mouseNewPos - mouseOldPos); + static float MouseSpeed() { + return glm::length(mouseNewPos() - mouseOldPos()); } static void SetMouseBoundlessMode(bool enable) { if (enable) { @@ -269,6 +271,24 @@ class Input { } } + static size_t AddHandler(std::function func) { + // 0 means it isn't assigned. + static size_t id = 1; + + (new FuncCommand())->func = [id = id, func = func] { + handlers()[id] = func; + }; + + return id++; + } + static void RemoveHandler(size_t& id) { + auto cmd = new FuncCommand(); + cmd->func = [id] { + handlers().erase(id); + }; + id = 0; + } + static void AddShortcut(const Key::Combination& combination, const std::function& callback) { if (auto b = combination.modifiers.cbegin(), e = combination.modifiers.cend(); InsertCombination(combinationTree(), &b, &e, combination.key, callback)) @@ -277,111 +297,106 @@ class Input { } - void ProcessInput() { + static void ProcessInput() { FillAxes(); - continuousInputOneSecondDelay.Process(io->AnyKeyPressed); - continuousInputNoDelay.Process(io->AnyKeyPressed); + continuousInputOneSecondDelay().Process(io()->AnyKeyPressed); + continuousInputNoDelay().Process(io()->AnyKeyPressed); // Make sure printable characters don't trigger combinations // while keyboard is captured by text input - if (io->AnyKeyPressed) - ExecuteFirstMatchingCombination(combinationTree(), io->WantCaptureKeyboard); + if (io()->AnyKeyPressed) + ExecuteFirstMatchingCombination(combinationTree(), io()->WantCaptureKeyboard); // Handle OnInput actions - for (auto [id,handler] : handlers) + for (auto [id,handler] : handlers()) handler(); - continuousInputOneSecondDelay.UpdateOld(io->AnyKeyPressed); - continuousInputNoDelay.UpdateOld(io->AnyKeyPressed); + continuousInputOneSecondDelay().UpdateOld(io()->AnyKeyPressed); + continuousInputNoDelay().UpdateOld(io()->AnyKeyPressed); } - bool Init() { - isRawMouseMotionSupported = glfwRawMouseMotionSupported(); + static bool Init() { + isRawMouseMotionSupported() = glfwRawMouseMotionSupported(); return true; } }; class KeyBinding { -public: - Input* input; - Cross* cross; - - float crossScaleSpeed = 1; - float crossMinSize = 0.1; - float crossMaxSize = 100; - - - size_t AddHandler(std::function func) { - // 0 means it isn't assigned. - static size_t id = 1; - - (new FuncCommand())->func = [id = id, input = input, func = func] { - input->handlers[id] = func; - }; - - return id++; - } - size_t AddHandler(std::function func) { - return AddHandler([i = input, func] { func(i); }); - } - void RemoveHandler(size_t& id) { - auto cmd = new FuncCommand(); - cmd->func = [id, input = input] { - input->handlers.erase(id); - }; - id = 0; - } - - void ResetFocus() { - AddHandler([i = input] { - if (i->IsDown(Key::Escape)) + static void ResetFocus() { + Input::AddHandler([] { + if (Input::IsDown(Key::Escape)) ImGui::FocusWindow(NULL); }); } - void BindInputToMovement() { - AddHandler([i = input] { + static void BindInputToMovement() { + Input::AddHandler([] { // Enable or disable Mouse boundless mode // and reset movement - bool mouseBoundlessMode = i->IsPressed(Key::Modifier::Alt) || i->IsPressed(Key::Modifier::Shift) || i->IsPressed(Key::Modifier::Control); + bool mouseBoundlessMode = Input::IsPressed(Key::Modifier::Alt) || Input::IsPressed(Key::Modifier::Shift) || Input::IsPressed(Key::Modifier::Control); Input::SetMouseBoundlessMode(mouseBoundlessMode && Input::IsCustomRenderImageActive().Get()); - - i->movement = glm::vec3(); - i->movement += i->MouseAxe * Settings::MouseSensivity().Get(); - i->movement += i->ArrowAxe; - i->movement += i->NumpadAxe; + Input::movement() = glm::vec3(); + + Input::movement() += Input::MouseAxe() * Settings::MouseSensivity().Get(); + Input::movement() += Input::ArrowAxe(); + Input::movement() += Input::NumpadAxe(); + }); + Input::AddHandler([] { + if (Input::IsPressed(Key::Modifier::Alt)) { + if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) { + glm::vec3 v(0); + for (auto& o : ObjectSelection::Selected()) + v += o.Get()->GetWorldPosition(); + v /= ObjectSelection::Selected().size(); + Scene::cross()->SetWorldPosition(v); + } + else if (Input::IsDown(Key::N0, true)) + Scene::cross()->SetWorldPosition(glm::vec3()); + } + else if (Input::IsPressed(Key::Modifier::Control)) { + if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) + Scene::cross()->SetWorldRotation(ObjectSelection::Selected().begin()._Ptr->_Myval->GetWorldRotation()); + else if (Input::IsDown(Key::N0, true)) + Scene::cross()->SetWorldRotation(glm::quat(1, 0, 0, 0)); + } }); } - void Cross() { + static void Cross() { // Resize cross. - AddHandler([i = input, c = cross, &sp = crossScaleSpeed, &min = crossMinSize, &max = crossMaxSize] { - bool isScaleUp = i->IsPressed(Key::N3, true); - bool isScaleDown = i->IsPressed(Key::N7, true); + Input::AddHandler([&sp = crossScaleSpeed(), &min = crossMinSize(), &max = crossMaxSize()] { + bool isScaleUp = Input::IsPressed(Key::N3, true); + bool isScaleDown = Input::IsPressed(Key::N7, true); if (isScaleUp == isScaleDown) return; if (isScaleUp) { - float newSize = c->size += sp; + float newSize = Scene::cross()->size += sp; if (max < newSize) - c->size = max; + Scene::cross()->size = max; else - c->size = newSize; + Scene::cross()->size = newSize; } else { - float newSize = c->size -= sp; + float newSize = Scene::cross()->size -= sp; if (newSize < min) - c->size = min; + Scene::cross()->size = min; else - c->size = newSize; + Scene::cross()->size = newSize; } - c->ForceUpdateCache(); + Scene::cross()->ForceUpdateCache(); }); } - bool Init() { + +public: + StaticFieldDefault(float, crossScaleSpeed, 1) + StaticFieldDefault(float, crossMinSize, .1f) + StaticFieldDefault(float, crossMaxSize, 100) + + static bool Init() { ResetFocus(); BindInputToMovement(); Cross(); diff --git a/StereoPlus2/StereoPlus2.vcxproj b/StereoPlus2/StereoPlus2.vcxproj index fb83716..366eaf9 100644 --- a/StereoPlus2/StereoPlus2.vcxproj +++ b/StereoPlus2/StereoPlus2.vcxproj @@ -242,6 +242,7 @@ + diff --git a/StereoPlus2/StereoPlus2.vcxproj.filters b/StereoPlus2/StereoPlus2.vcxproj.filters index 1343e03..86f2d76 100644 --- a/StereoPlus2/StereoPlus2.vcxproj.filters +++ b/StereoPlus2/StereoPlus2.vcxproj.filters @@ -183,5 +183,6 @@ shaders + \ No newline at end of file diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index a99d98d..d053cdf 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -219,10 +219,10 @@ class PenTool : public EditingTool { // then don't create a new point. double Precision = 1e-4; - void Immediate(Input* input) { + void Immediate() { createdNewObject = false; - if (!input->IsContinuousInputOneSecondDelay()) { + if (!Input::IsContinuousInputOneSecondDelay()) { isBeingModified() = false; wasCommitDone = false; } @@ -307,7 +307,7 @@ class PenTool : public EditingTool { return cos > 1 - E || isnan(cos); } - void ProcessInput(Input* input) { + void ProcessInput() { if (!target.HasValue()) { UnbindSceneObjects(); return; @@ -315,7 +315,7 @@ class PenTool : public EditingTool { switch (mode) { - case Mode::Immediate: return Immediate(input); + case Mode::Immediate: return Immediate(); case Mode::Step: return Step(); default: Logger.Warning("Not suported mode was given"); @@ -327,7 +327,7 @@ class PenTool : public EditingTool { if (createNewObjectHandlerId) return; - createNewObjectHandlerId = keyBinding->AddHandler([&]() { + createNewObjectHandlerId = Input::AddHandler([&] { if (Input::IsDown(Key::Enter, true) || Input::IsDown(Key::NEnter, true)) { lockCreateNewObjectHandlerId = true; @@ -348,7 +348,7 @@ class PenTool : public EditingTool { cmd->onCreated = [&](SceneObject* o) { createdNewObject = true; ObjectSelection::Set(o); - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); lockCreateNewObjectHandlerId = false; }; } @@ -395,10 +395,10 @@ class PenTool : public EditingTool { if (!target->GetVertices().empty()) cross->SetWorldPosition(target->GetVertices().back()); - inputHandlerId = keyBinding->AddHandler([&](Input* input) { + inputHandlerId = Input::AddHandler([&] { // If handler was removed via shortcuts then don't execute it. if (inputHandlerId) - ProcessInput(input); + ProcessInput(); }); spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { if (v == SpaceMode::Local) @@ -456,10 +456,10 @@ class PenTool : public EditingTool { if (!target->GetVertices().empty()) cross->SetWorldPosition(target->GetVertices().back()); - inputHandlerId = keyBinding->AddHandler([&](Input* input) { + inputHandlerId = Input::AddHandler([&] { // If handler was removed via shortcuts then don't execute it. if (inputHandlerId) - ProcessInput(input); + ProcessInput(); }); spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { if (v == SpaceMode::Local) @@ -493,7 +493,7 @@ class PenTool : public EditingTool { } virtual bool UnbindSceneObjects() { if (!lockCreateNewObjectHandlerId) - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); if (!target.HasValue()) return true; @@ -503,7 +503,7 @@ class PenTool : public EditingTool { createdAdditionalPoints = false; } - keyBinding->RemoveHandler(inputHandlerId); + Input::RemoveHandler(inputHandlerId); Settings::SpaceMode().OnChanged() -= spaceModeChangeHandlerId; StateBuffer::OnStateChange() -= stateChangedHandlerId; SceneObject::OnBeforeAnyElementChanged() -= anyObjectChangedHandlerId; @@ -522,7 +522,7 @@ class PenTool : public EditingTool { // creating new object awaiting state. // But if the tool is unbind then it should be cancelled. if (!lockCreateNewObjectHandlerId) - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); } SceneObject* GetTarget() { @@ -597,12 +597,12 @@ class ExtrusionEditingTool : public EditingToolConfigured - void ProcessInput(Input* input) { + void ProcessInput() { std::cout << "Unsupported Editing Tool target Type or Unsupported combination of ObjectType and PointPenEditingToolMode" << std::endl; } template<> - void ProcessInput(Input* input) { - if (!input->IsContinuousInputOneSecondDelay()) { + void ProcessInput() { + if (!Input::IsContinuousInputOneSecondDelay()) { isBeingModified() = false; wasCommitDone = false; } @@ -610,7 +610,7 @@ class ExtrusionEditingTool : public EditingToolConfiguredIsDown(Key::Escape, true)) { + if (Input::IsDown(Key::Escape, true)) { UnbindSceneObjects(); return; } @@ -694,11 +694,11 @@ class ExtrusionEditingTool : public EditingToolConfigured - void ProcessInput(Input* input) { + void ProcessInput() { if (!mesh.HasValue()) return; - if (input->IsDown(Key::Escape, true)) { + if (Input::IsDown(Key::Escape, true)) { UnbindSceneObjects(); return; } @@ -722,7 +722,7 @@ class ExtrusionEditingTool : public EditingToolConfiguredIsDown(Key::Enter, true) || input->IsDown(Key::NEnter, true)) { + if (Input::IsDown(Key::Enter, true) || Input::IsDown(Key::NEnter, true)) { isBeingModified() = false; wasCommitDone = false; @@ -743,13 +743,13 @@ class ExtrusionEditingTool : public EditingToolConfiguredSetVertice(meshPoints.size() - penPoints.size() + i, penPoints[i] + transformVector); } - void ProcessInput(Input* input) { + void ProcessInput() { switch (mode) { case Mode::Immediate: - return ProcessInput(input); + return ProcessInput(); case Mode::Step: - return ProcessInput(input); + return ProcessInput(); default: std::cout << "Not suported mode was given" << std::endl; return; @@ -808,7 +808,7 @@ class ExtrusionEditingTool : public EditingToolConfiguredSetLocalPosition(crossOriginalPosition); Settings::SpaceMode().OnChanged() -= spaceModeChangeHandlerId; - keyBinding->RemoveHandler(inputHandlerId); + Input::RemoveHandler(inputHandlerId); StateBuffer::OnStateChange().RemoveHandler(stateChangedHandlerId); SceneObject::OnBeforeAnyElementChanged().RemoveHandler(anyObjectChangedHandlerId); @@ -876,7 +876,7 @@ class ExtrusionEditingTool : public EditingToolConfiguredAddHandler([&](Input * input) { ProcessInput(input); }); + inputHandlerId = Input::AddHandler([&] { ProcessInput(); }); spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { if (!mesh.HasValue()) return; @@ -960,28 +960,28 @@ class TransformTool : public EditingTool { bool wasCommitDone = false; - const glm::vec3 GetRelativeMovement(Input* input) { + const glm::vec3 GetRelativeMovement() { static glm::vec3 zero = glm::vec3(); - if (!input->IsPressed(Key::Modifier::Alt) || input->movement == zero) + if (!Input::IsPressed(Key::Modifier::Alt) || Input::movement() == zero) return transformPos - transformOldPos; - return input->movement * Settings::TranslationStep().Get(); + return Input::movement() * Settings::TranslationStep().Get(); } - const glm::vec3 GetRelativeRotation(Input* input) { + const glm::vec3 GetRelativeRotation() { static glm::vec3 zero = glm::vec3(); - if (!input->IsPressed(Key::Modifier::Control) || input->movement == zero) + if (!Input::IsPressed(Key::Modifier::Control) || Input::movement() == zero) return angle - oldAngle; // If all 3 axes are modified then don't apply such rotation. // Quaternion can't rotate around 3 axes. - if (input->movement.x && input->movement.y && input->movement.z) + if (Input::movement().x && Input::movement().y && Input::movement().z) return angle - oldAngle; auto mouseThresholdMin = 0.8; auto mouseThresholdMax = 1.25; - auto mouseAxe = input->MouseAxe; + auto mouseAxe = Input::MouseAxe(); auto maxAxe = 0; // Find non-zero axes @@ -1002,39 +1002,39 @@ class TransformTool : public EditingTool { else mouseAxe = zero; - mouseAxe *= Settings::MouseSensivity().Get() * input->MouseSpeed(); + mouseAxe *= Settings::MouseSensivity().Get() * Input::MouseSpeed(); - auto na = (input->ArrowAxe + input->NumpadAxe + mouseAxe) * Settings::RotationStep().Get(); + auto na = (Input::ArrowAxe() + Input::NumpadAxe() + mouseAxe) * Settings::RotationStep().Get(); angle += na; return na; } - const float GetRelativeScale(Input* input) { + const float GetRelativeScale() { static glm::vec3 zero = glm::vec3(); - if (!input->IsPressed(Key::Modifier::Shift) || input->movement == zero) + if (!Input::IsPressed(Key::Modifier::Shift) || Input::movement() == zero) return scale; - return scale + input->movement.x * Settings::ScalingStep().Get(); + return scale + Input::movement().x * Settings::ScalingStep().Get(); } - void ProcessInput(const ObjectType& type, const Mode& mode, Input* input) { + void ProcessInput(const ObjectType& type, const Mode& mode) { static glm::vec3 zero = glm::vec3(); - if (!input->IsContinuousInputNoDelay()) { + if (!Input::IsContinuousInputNoDelay()) { isBeingModified() = false; wasCommitDone = false; } // We can move cross without having any objects bind. - if (!input->IsContinuousInputNoDelay()) { + if (!Input::IsContinuousInputNoDelay()) { transformPos = transformOldPos = zero; angle = oldAngle = zero; scale = oldScale = 1; } - const auto relativeScale = GetRelativeScale(input); - const auto relativeMovement = GetRelativeMovement(input); - const auto relativeRotation = GetRelativeRotation(input); + const auto relativeScale = GetRelativeScale(); + const auto relativeMovement = GetRelativeMovement(); + const auto relativeRotation = GetRelativeRotation(); // Check if we need to process tool. if (targets.parentObjects.empty() || !targets.parentObjects.front().HasValue()) { @@ -1042,7 +1042,7 @@ class TransformTool : public EditingTool { //TranslateCross(relativeMovement); return; } - if (input->IsDown(Key::Escape, true)) { + if (Input::IsDown(Key::Escape, true)) { TransformCross(relativeMovement, relativeScale, relativeRotation); //TranslateCross(relativeMovement); UnbindSceneObjects(); @@ -1199,8 +1199,8 @@ class TransformTool : public EditingTool { cross->SetLocalRotation(targets.parentObjects.front()->GetWorldRotation()); } - keyBinding->RemoveHandler(cross->keyboardBindingHandlerId); - inputHandlerId = keyBinding->AddHandler([this](Input* input) { this->ProcessInput(type, mode, input); }); + Input::RemoveHandler(cross->keyboardBindingHandlerId); + inputHandlerId = Input::AddHandler([this]{ ProcessInput(type, mode); }); stateChangedHandlerId = StateBuffer::OnStateChange().AddHandler([&] { if (Settings::TargetMode().Get() == TargetMode::Pivot) return; @@ -1248,10 +1248,10 @@ class TransformTool : public EditingTool { oldAngle = glm::vec3(); transformPos = glm::vec3(); - keyBinding->RemoveHandler(inputHandlerId); + Input::RemoveHandler(inputHandlerId); // Remove if exists and add a new one. - keyBinding->RemoveHandler(cross->keyboardBindingHandlerId); - cross->keyboardBindingHandlerId = keyBinding->AddHandler(cross->keyboardBindingHandler); + Input::RemoveHandler(cross->keyboardBindingHandlerId); + cross->keyboardBindingHandlerId = Input::AddHandler(cross->keyboardBindingHandler); Settings::SpaceMode().OnChanged().RemoveHandler(spaceModeChangeHandlerId); StateBuffer::OnStateChange().RemoveHandler(stateChangedHandlerId); @@ -1376,7 +1376,7 @@ class SinePenTool : public EditingTool { cross->SetWorldPosition(target->GetVertices()[i]); } - void ProcessInput(Input* input) { + void ProcessInput() { if (!target.HasValue()) { UnbindSceneObjects(); return; @@ -1396,7 +1396,7 @@ class SinePenTool : public EditingTool { if (createNewObjectHandlerId) return; - createNewObjectHandlerId = keyBinding->AddHandler([&]() { + createNewObjectHandlerId = Input::AddHandler([&] { if (Input::IsDown(Key::Enter, true) || Input::IsDown(Key::NEnter, true)) { lockCreateNewObjectHandlerId = true; @@ -1417,7 +1417,7 @@ class SinePenTool : public EditingTool { cmd->onCreated = [&](SceneObject* o) { createdNewObject = true; ObjectSelection::Set(o); - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); lockCreateNewObjectHandlerId = false; }; } @@ -1465,10 +1465,10 @@ class SinePenTool : public EditingTool { if (!target->GetVertices().empty()) cross->SetWorldPosition(target->GetVertices().back()); - inputHandlerId = keyBinding->AddHandler([&](Input* input) { + inputHandlerId = Input::AddHandler([&]{ // If handler was removed via shortcuts then don't execute it. if (inputHandlerId) - ProcessInput(input); + ProcessInput(); }); spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { if (v == SpaceMode::Local) @@ -1531,10 +1531,10 @@ class SinePenTool : public EditingTool { if (!target->GetVertices().empty()) cross->SetWorldPosition(target->GetVertices().back()); - inputHandlerId = keyBinding->AddHandler([&](Input* input) { + inputHandlerId = Input::AddHandler([&] { // If handler was removed via shortcuts then don't execute it. if (inputHandlerId) - ProcessInput(input); + ProcessInput(); }); spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { if (v == SpaceMode::Local) @@ -1568,7 +1568,7 @@ class SinePenTool : public EditingTool { } virtual bool UnbindSceneObjects() { if (!lockCreateNewObjectHandlerId) - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); if (!target.HasValue()) return true; @@ -1576,7 +1576,7 @@ class SinePenTool : public EditingTool { target->RemoveVertice(); createdAdditionalPoints = false; - keyBinding->RemoveHandler(inputHandlerId); + Input::RemoveHandler(inputHandlerId); Settings::SpaceMode().OnChanged() -= spaceModeChangeHandlerId; StateBuffer::OnStateChange() -= stateChangedHandlerId; SceneObject::OnBeforeAnyElementChanged() -= anyObjectChangedHandlerId; @@ -1596,7 +1596,7 @@ class SinePenTool : public EditingTool { // creating new object awaiting state. // But if the tool is unbind then it should be cancelled. if (!lockCreateNewObjectHandlerId) - keyBinding->RemoveHandler(createNewObjectHandlerId); + Input::RemoveHandler(createNewObjectHandlerId); } SceneObject* GetTarget() { diff --git a/StereoPlus2/Windows.hpp b/StereoPlus2/Windows.hpp index 7d2ac2c..ba20a92 100644 --- a/StereoPlus2/Windows.hpp +++ b/StereoPlus2/Windows.hpp @@ -1112,7 +1112,7 @@ class TransformToolWindow : Window, Attributes { ImGui::DragFloat("scale", &tool->scale, 0.01f, 0, 0, "%.2f"); break; case TransformToolMode::Rotate: - if (!tool->keyBinding->input->IsContinuousInputNoDelay()) + if (!Input::IsContinuousInputNoDelay()) oldAngle = tool->angle; ImGui::Separator(); diff --git a/StereoPlus2/cpp.hint b/StereoPlus2/cpp.hint new file mode 100644 index 0000000..2cde2c4 --- /dev/null +++ b/StereoPlus2/cpp.hint @@ -0,0 +1,8 @@ +// Hint files help the Visual Studio IDE interpret Visual C++ identifiers +// such as names of functions and macros. +// For more information see https://go.microsoft.com/fwlink/?linkid=865984 +#define StaticProperty(type, name) static Property& name() { static Property v; return v;} +#define StaticFieldDefault(type, name, defaultValue) static type& name() { static type v = defaultValue; return v;} +#define StaticField(type, name) static type& name() { static type v; return v;} +#define NULL +#define NULL ((void *)0) diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index 021093f..991c56c 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -129,7 +129,6 @@ int main() { gui.glWindow = renderPipeline.glWindow; gui.glsl_version = renderPipeline.glsl_version; gui.scene = &scene; - gui.keyBinding.cross = ✗ gui.settingsWindow = &settingsWindow; gui.renderViewport = [&customRenderWindow] { customRenderWindow.shouldSaveViewportImage = true; }; gui.renderAdvanced = [&customRenderWindow] { customRenderWindow.shouldSaveAdvancedImage = true; }; @@ -137,39 +136,19 @@ int main() { return false; cross.Name = "Cross"; - cross.GUIPositionEditHandler = [&cross, i = &gui.input]() { i->movement += cross.GUIPositionEditDifference; }; - cross.GUIPositionEditHandlerId = gui.keyBinding.AddHandler(cross.GUIPositionEditHandler); + cross.GUIPositionEditHandler = [&cross, i = &gui.input]() { i->movement() += cross.GUIPositionEditDifference; }; + cross.GUIPositionEditHandlerId = Input::AddHandler(cross.GUIPositionEditHandler); cross.keyboardBindingHandler = [&cross, i = &gui.input]() { if (!Input::IsPressed(Key::Modifier::Alt) && cross.GUIPositionEditDifference == glm::vec3()) return; - auto m = i->movement * Settings::TranslationStep().Get(); + auto m = i->movement() * Settings::TranslationStep().Get(); if (Settings::SpaceMode().Get() == SpaceMode::Local) m = glm::rotate(cross.GetWorldRotation(), m); cross.SetWorldPosition(cross.GetWorldPosition() + m); }; - cross.keyboardBindingHandlerId = gui.keyBinding.AddHandler(cross.keyboardBindingHandler); - gui.keyBinding.AddHandler([&cross]() { - if (Input::IsPressed(Key::Modifier::Alt)) { - if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) { - glm::vec3 v(0); - for (auto& o : ObjectSelection::Selected()) - v += o.Get()->GetWorldPosition(); - v /= ObjectSelection::Selected().size(); - cross.SetWorldPosition(v); - } - else if (Input::IsDown(Key::N0, true)) - cross.SetWorldPosition(glm::vec3()); - } - else if (Input::IsPressed(Key::Modifier::Control)) { - if (Input::IsDown(Key::N5, true) && !ObjectSelection::Selected().empty()) - cross.SetWorldRotation(ObjectSelection::Selected().begin()._Ptr->_Myval->GetWorldRotation()); - else if (Input::IsDown(Key::N0, true)) - cross.SetWorldRotation(glm::quat(1,0,0,0)); - } - }); - + cross.keyboardBindingHandlerId = Input::AddHandler(cross.keyboardBindingHandler); ToolPool::KeyBinding() = &gui.keyBinding; if (!ToolPool::Init()) @@ -179,7 +158,7 @@ int main() { StateBuffer::BufferSize() <<= Settings::StateBufferLength(); StateBuffer::RootObject() <<= scene.root(); StateBuffer::Objects() <<= scene.Objects(); - gui.keyBinding.AddHandler([s = &scene]{ + Input::AddHandler([s = &scene]{ if (Input::IsDown(Key::Delete, true)) { StateBuffer::Commit(); s->DeleteSelected(); From 5cb66c87c4ccb6b84575cba04afaadc20c9032eb Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 18:02:54 +0300 Subject: [PATCH 08/10] allowed advanced movement and rotation for other tools --- CHANGE_LOG.md | 5 +- StereoPlus2/Input.hpp | 56 +++++++++++ StereoPlus2/Math.hpp | 8 +- StereoPlus2/ToolPool.hpp | 9 +- StereoPlus2/Tools.hpp | 201 ++++++++------------------------------- StereoPlus2/main.cpp | 20 ++-- docs/dev.doc.en.md | 5 +- docs/doc.en.md | 5 +- 8 files changed, 120 insertions(+), 189 deletions(-) diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index 1d31979..8d32635 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -48,4 +48,7 @@ Now Release copies (CopyIfNewer) necessary files to output so the folder can be easily run from output or transferred to another pc and run there. Added Publish configuration that cleans output before build and copies only necessary files without any debug symbols; # 0.13.3 -- property/event overhaul; \ No newline at end of file +- property/event overhaul; +# 0.14 +- introduced independent cross movement and rotation; +- isolated main math in separate static classes; \ No newline at end of file diff --git a/StereoPlus2/Input.hpp b/StereoPlus2/Input.hpp index 196bf43..72cd4ed 100644 --- a/StereoPlus2/Input.hpp +++ b/StereoPlus2/Input.hpp @@ -321,6 +321,62 @@ class Input { return true; } + + static const glm::vec3 GetRelativeRotation(const glm::vec3& defaultAngle) { + static glm::vec3 zero = glm::vec3(); + + if (!Input::IsPressed(Key::Modifier::Control) || Input::movement() == zero) + return defaultAngle; + + // If all 3 axes are modified then don't apply such rotation. + // Quaternion can't rotate around 3 axes. + if (Input::movement().x && Input::movement().y && Input::movement().z) + return defaultAngle; + + auto mouseThresholdMin = 0.8; + auto mouseThresholdMax = 1.25; + auto mouseAxe = Input::MouseAxe(); + auto maxAxe = 0; + + // Find non-zero axes + short t[2] = { 0,0 }; + short n = 0; + for (short i = 0; i < 3; i++) + if (mouseAxe[i] != 0) + t[n] = i; + + // Nullify weak axes (those with small values) + auto ratio = abs(mouseAxe[t[0]]) / abs(mouseAxe[t[1]]); + if (ratio < mouseThresholdMin) + mouseAxe[t[0]] = 0; + else if (ratio > mouseThresholdMax) + mouseAxe[t[1]] = 0; + // If 2 axes are used simultaneously it breaks the quaternion somehow. + else + mouseAxe = zero; + + mouseAxe *= Settings::MouseSensivity().Get() * Input::MouseSpeed(); + + auto na = (Input::ArrowAxe() + Input::NumpadAxe() + mouseAxe) * Settings::RotationStep().Get(); + return na; + } + static const glm::vec3 GetRelativeMovement(const glm::vec3& defaultMovement) { + static glm::vec3 zero = glm::vec3(); + + if (!Input::IsPressed(Key::Modifier::Alt) || Input::movement() == zero) + return defaultMovement; + + return Input::movement() * Settings::TranslationStep().Get(); + } + static const float GetNewScale(const float& currentScale) { + static glm::vec3 zero = glm::vec3(); + + if (!Input::IsPressed(Key::Modifier::Shift) || Input::movement() == zero) + return currentScale; + + return currentScale + Input::movement().x * Settings::ScalingStep().Get(); + } + }; class KeyBinding { diff --git a/StereoPlus2/Math.hpp b/StereoPlus2/Math.hpp index 2f57514..4705c14 100644 --- a/StereoPlus2/Math.hpp +++ b/StereoPlus2/Math.hpp @@ -78,7 +78,7 @@ class Transform { } public: - static void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list& targets) { + static void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::vector& targets) { for (auto& target : targets) { target->SetWorldPosition((target->GetWorldPosition() - center) / oldScale * scale + center); for (size_t i = 0; i < target->GetVertices().size(); i++) @@ -94,7 +94,7 @@ class Transform { cross->SetWorldPosition(cross->GetWorldPosition() + transformVector); } - static void Translate(const glm::vec3& transformVector, std::list& targets, SceneObject* cross) { + static void Translate(const glm::vec3& transformVector, std::vector& targets, SceneObject* cross) { // Need to calculate average rotation. // https://stackoverflow.com/questions/12374087/average-of-multiple-quaternions/27410865#27410865 if (Settings::SpaceMode().Get() == SpaceMode::Local) { @@ -136,7 +136,7 @@ class Transform { cross->SetLocalRotation(r * cross->GetLocalRotation()); } - static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list& targets, SceneObject* cross) { + static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::vector& targets, SceneObject* cross) { glm::vec3 axe; float angle; @@ -164,6 +164,8 @@ class Transform { target->SetWorldRotation(r * target->GetWorldRotation()); } } + + }; struct Convert { diff --git a/StereoPlus2/ToolPool.hpp b/StereoPlus2/ToolPool.hpp index d5a9154..cf51e9a 100644 --- a/StereoPlus2/ToolPool.hpp +++ b/StereoPlus2/ToolPool.hpp @@ -7,29 +7,22 @@ class ToolPool { static void Init(PenTool* tool) { tool->cross <<= Scene::cross(); - tool->keyBinding <<= KeyBinding(); } static void Init(SinePenTool* tool) { tool->cross <<= Scene::cross(); - tool->keyBinding <<= KeyBinding(); } static void Init(ExtrusionEditingTool* tool) { tool->destination <<= Scene::root(); tool->cross <<= Scene::cross(); - tool->keyBinding <<= KeyBinding(); } static void Init(TransformTool* tool) { - //tool->cross <<= Cross(); tool->cross <<= Scene::cross(); - tool->keyBinding <<= KeyBinding(); } public: - StaticProperty(::KeyBinding*, KeyBinding); - template static T* GetTool() { static T tool; @@ -44,7 +37,7 @@ class ToolPool { } static bool Init() { - if (KeyBinding().IsAssigned() && Scene::root().IsAssigned() && Scene::cross().IsAssigned()) + if (Scene::root().IsAssigned() && Scene::cross().IsAssigned()) return true; std::cout << "ToolPool could not be initialized because some fields were null" << std::endl; diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index d053cdf..7f83163 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -124,8 +124,6 @@ class EditingTool : Tool { Transform, }; - NonAssignProperty keyBinding; - EditingTool() { if (isBeingModifiedHandler() != 0) return; @@ -193,7 +191,6 @@ class PenTool : public EditingTool { const Log Logger = Log::For(); size_t inputHandlerId; - size_t spaceModeChangeHandlerId; size_t stateChangedHandlerId; size_t anyObjectChangedHandlerId; @@ -312,7 +309,7 @@ class PenTool : public EditingTool { UnbindSceneObjects(); return; } - + switch (mode) { case Mode::Immediate: return Immediate(); @@ -400,12 +397,6 @@ class PenTool : public EditingTool { if (inputHandlerId) ProcessInput(); }); - spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { - if (v == SpaceMode::Local) - cross->SetWorldRotation(target->GetWorldRotation()); - else - cross->SetWorldRotation(glm::quat()); - }; stateChangedHandlerId = StateBuffer::OnStateChange() += [&] { if (!target.HasValue()) { cross->SetWorldRotation(glm::quat()); @@ -417,9 +408,6 @@ class PenTool : public EditingTool { return; } - if (Settings::SpaceMode().Get() == SpaceMode::Local) - cross->SetWorldRotation(target.Get()->GetWorldRotation()); - if (target->GetVertices().empty()) return; @@ -461,12 +449,6 @@ class PenTool : public EditingTool { if (inputHandlerId) ProcessInput(); }); - spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { - if (v == SpaceMode::Local) - cross->SetWorldRotation(target.Get()->GetWorldRotation()); - else - cross->SetWorldRotation(glm::quat()); - }; stateChangedHandlerId = StateBuffer::OnStateChange() += [&] { if (!target.HasValue()) { cross->SetWorldRotation(glm::quat()); @@ -504,7 +486,6 @@ class PenTool : public EditingTool { } Input::RemoveHandler(inputHandlerId); - Settings::SpaceMode().OnChanged() -= spaceModeChangeHandlerId; StateBuffer::OnStateChange() -= stateChangedHandlerId; SceneObject::OnBeforeAnyElementChanged() -= anyObjectChangedHandlerId; @@ -848,11 +829,6 @@ class ExtrusionEditingTool : public EditingToolConfiguredGetType() != type) { Logger.Warning("Invalid Object passed to ExtrusionEditingTool"); return true; @@ -942,13 +918,12 @@ class TransformTool : public EditingTool { size_t inputHandlerId; size_t spaceModeChangeHandlerId; - size_t stateChangedHandlerId; size_t anyObjectChangedHandlerId; Mode mode; ObjectType type; - Scene::CategorizedPON targets; + std::vector targets; float minScale = 0.01; float oldScale = 1; @@ -960,66 +935,8 @@ class TransformTool : public EditingTool { bool wasCommitDone = false; - const glm::vec3 GetRelativeMovement() { - static glm::vec3 zero = glm::vec3(); - - if (!Input::IsPressed(Key::Modifier::Alt) || Input::movement() == zero) - return transformPos - transformOldPos; - - return Input::movement() * Settings::TranslationStep().Get(); - } - const glm::vec3 GetRelativeRotation() { - static glm::vec3 zero = glm::vec3(); - - if (!Input::IsPressed(Key::Modifier::Control) || Input::movement() == zero) - return angle - oldAngle; - - // If all 3 axes are modified then don't apply such rotation. - // Quaternion can't rotate around 3 axes. - if (Input::movement().x && Input::movement().y && Input::movement().z) - return angle - oldAngle; - - auto mouseThresholdMin = 0.8; - auto mouseThresholdMax = 1.25; - auto mouseAxe = Input::MouseAxe(); - auto maxAxe = 0; - - // Find non-zero axes - short t[2] = {0,0}; - short n = 0; - for (short i = 0; i < 3; i++) { - if (mouseAxe[i] != 0) - t[n] = i; - } - - // Nullify weak axes (those with small values) - auto ratio = abs(mouseAxe[t[0]]) / abs(mouseAxe[t[1]]); - if (ratio < mouseThresholdMin) - mouseAxe[t[0]] = 0; - else if (ratio > mouseThresholdMax) - mouseAxe[t[1]] = 0; - // If 2 axes are used simultaneously it breaks the quaternion somehow. - else - mouseAxe = zero; - - mouseAxe *= Settings::MouseSensivity().Get() * Input::MouseSpeed(); - - auto na = (Input::ArrowAxe() + Input::NumpadAxe() + mouseAxe) * Settings::RotationStep().Get(); - angle += na; - return na; - } - const float GetRelativeScale() { - static glm::vec3 zero = glm::vec3(); - - if (!Input::IsPressed(Key::Modifier::Shift) || Input::movement() == zero) - return scale; - - return scale + Input::movement().x * Settings::ScalingStep().Get(); - } void ProcessInput(const ObjectType& type, const Mode& mode) { - static glm::vec3 zero = glm::vec3(); - if (!Input::IsContinuousInputNoDelay()) { isBeingModified() = false; wasCommitDone = false; @@ -1027,55 +944,55 @@ class TransformTool : public EditingTool { // We can move cross without having any objects bind. if (!Input::IsContinuousInputNoDelay()) { - transformPos = transformOldPos = zero; - angle = oldAngle = zero; + transformPos = transformOldPos = glm::vec3(); + angle = oldAngle = glm::vec3(); scale = oldScale = 1; } - const auto relativeScale = GetRelativeScale(); - const auto relativeMovement = GetRelativeMovement(); - const auto relativeRotation = GetRelativeRotation(); + const auto newScale = Input::GetNewScale(scale); + const auto relativeMovement = Input::GetRelativeMovement(transformPos - transformOldPos); + const auto relativeRotation = Input::GetRelativeRotation(angle - oldAngle); // Check if we need to process tool. - if (targets.parentObjects.empty() || !targets.parentObjects.front().HasValue()) { - TransformCross(relativeMovement, relativeScale, relativeRotation); + if (targets.empty() || !targets.front().HasValue()) { + TransformCross(relativeMovement, newScale, relativeRotation); //TranslateCross(relativeMovement); return; } if (Input::IsDown(Key::Escape, true)) { - TransformCross(relativeMovement, relativeScale, relativeRotation); + TransformCross(relativeMovement, newScale, relativeRotation); //TranslateCross(relativeMovement); UnbindSceneObjects(); return; } if (Settings::TargetMode().Get() == TargetMode::Pivot) - TransformCross(relativeMovement, relativeScale, relativeRotation); + TransformCross(relativeMovement, newScale, relativeRotation); else - Transform(relativeMovement, relativeScale, relativeRotation); + Transform(relativeMovement, newScale, relativeRotation); transformOldPos = transformPos; } - void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list& targets) { + void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::vector& targets) { if (shouldTrace) Trace(targets); Transform::Scale(center, oldScale, scale, targets); } - void Translate(const glm::vec3& transformVector, std::list& targets) { + void Translate(const glm::vec3& transformVector, std::vector& targets) { if (shouldTrace) Trace(targets); Transform::Translate(transformVector, targets, &cross.Get()); } - void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list& targets) { + void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::vector& targets) { if (shouldTrace) Trace(targets); Transform::Rotate(center, rotation, targets, &cross.Get()); } - void Trace(std::list& targets) { + void Trace(std::vector& targets) { static int id = 0; for (auto& o : targets) { @@ -1115,52 +1032,38 @@ class TransformTool : public EditingTool { } } - void Transform(const glm::vec3& relativeMovement, const float relativeScale, const glm::vec3& relativeRotation) { + void Transform(const glm::vec3& relativeMovement, const float newScale, const glm::vec3& relativeRotation) { if (relativeMovement != glm::vec3()) - Translate(relativeMovement, targets.parentObjects); + Translate(relativeMovement, targets); if (relativeRotation != glm::vec3()) { - Rotate(cross->GetWorldPosition(), relativeRotation, targets.parentObjects); - nullifyUntouchedAngles(); + Rotate(cross->GetWorldPosition(), relativeRotation, targets); + nullifyUntouchedAngles(relativeRotation, angle, oldAngle); oldAngle = angle; } - if (relativeScale != oldScale) { - Scale(cross->GetWorldPosition(), oldScale, relativeScale, targets.parentObjects); - oldScale = scale = relativeScale; + if (newScale != oldScale) { + Scale(cross->GetWorldPosition(), oldScale, newScale, targets); + oldScale = scale = newScale; } } - void TransformCross(const glm::vec3& relativeMovement, const float relativeScale, const glm::vec3& relativeRotation) { + void TransformCross(const glm::vec3& relativeMovement, const float newScale, const glm::vec3& relativeRotation) { if (relativeMovement != glm::vec3()) - Transform::Translate(relativeMovement, &cross.Get()); + Transform::Translate(relativeMovement, &Scene::cross().Get()); if (relativeRotation != glm::vec3()) { - Transform::Rotate(cross->GetWorldPosition(), relativeRotation, &cross.Get()); - nullifyUntouchedAngles(); + Transform::Rotate(cross->GetWorldPosition(), relativeRotation, &Scene::cross().Get()); + nullifyUntouchedAngles(relativeRotation, angle, oldAngle); oldAngle = angle; } - if (relativeScale != oldScale) - oldScale = scale = relativeScale; + if (newScale != oldScale) + oldScale = scale = newScale; } - void TranslateCross(const glm::vec3& transformVector) { - Transform::Translate(transformVector, &cross.Get()); - } - - void nullifyUntouchedAngles() { - auto da = angle - oldAngle; + + void nullifyUntouchedAngles(const glm::vec3& relativeRotation, glm::vec3& angle, glm::vec3& oldAngle) { + auto da = angle + relativeRotation - oldAngle; for (auto i = 0; i < 3; i++) if (da[i] == 0.f) angle[i] = oldAngle[i] = 0.f; } - - static glm::vec3 Avg(std::vector vs) { - if (vs.empty()) - return glm::vec3(); - - glm::vec3 sum = glm::vec3(); - for (auto o : vs) - sum += o; - - return glm::vec3(sum.x / vs.size(), sum.y / vs.size(), sum.z / vs.size()); - } static std::vector GetWorldPositions(std::list& vs) { std::vector l; for (auto o : vs) @@ -1169,43 +1072,16 @@ class TransformTool : public EditingTool { return l; } - //static std::vector GetLocalRotations(std::list& vs) { - // std::vector l; - // for (auto o : vs) - // l.push_back(o->GetLocalRotation()); - // return l; - //} - //static glm::quat Avg(std::vector vs) { - // glm::mat<4, vs.size(), float> m; - //} - virtual void OnSelectionChanged(const ObjectSelection::Selection& v) override { UnbindTool(); if (v.empty()) return; - targets.childObjects.clear(); - targets.orphanedObjects.clear(); - targets.parentObjects.clear(); - - for (auto& o : v) - targets.parentObjects.push_back(o); + targets.clear(); + targets.insert(targets.end(), v.begin(), v.end()); - if (Settings::TargetMode().Get() == TargetMode::Object) { - cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); - if (Settings::SpaceMode().Get() == SpaceMode::World) - cross->SetWorldRotation(cross->unitQuat()); - else if (!targets.parentObjects.empty() && targets.parentObjects.front().HasValue()) - cross->SetLocalRotation(targets.parentObjects.front()->GetWorldRotation()); - } - Input::RemoveHandler(cross->keyboardBindingHandlerId); inputHandlerId = Input::AddHandler([this]{ ProcessInput(type, mode); }); - stateChangedHandlerId = StateBuffer::OnStateChange().AddHandler([&] { - if (Settings::TargetMode().Get() == TargetMode::Pivot) - return; - cross->SetLocalPosition(Avg(GetWorldPositions(targets.parentObjects))); - }); anyObjectChangedHandlerId = SceneObject::OnBeforeAnyElementChanged().AddHandler([&] { if (wasCommitDone) return; @@ -1224,6 +1100,7 @@ class TransformTool : public EditingTool { public: NonAssignProperty cross; + // These are modified via GUI float scale = 1; glm::vec3 angle; glm::vec3 transformPos; @@ -1239,7 +1116,7 @@ class TransformTool : public EditingTool { virtual void UnbindTool() override { - if (targets.parentObjects.empty()) + if (targets.empty()) return; scale = 1; @@ -1254,15 +1131,13 @@ class TransformTool : public EditingTool { cross->keyboardBindingHandlerId = Input::AddHandler(cross->keyboardBindingHandler); Settings::SpaceMode().OnChanged().RemoveHandler(spaceModeChangeHandlerId); - StateBuffer::OnStateChange().RemoveHandler(stateChangedHandlerId); SceneObject::OnBeforeAnyElementChanged().RemoveHandler(anyObjectChangedHandlerId); - //DeleteConfig(); } SceneObject* GetTarget() { - if (targets.parentObjects.empty() || !targets.parentObjects.front().HasValue()) + if (targets.empty() || !targets.front().HasValue()) return nullptr; else - return targets.parentObjects.front().Get(); + return targets.front().Get(); } void SetMode(Mode mode) { this->mode = mode; diff --git a/StereoPlus2/main.cpp b/StereoPlus2/main.cpp index 991c56c..7c73602 100644 --- a/StereoPlus2/main.cpp +++ b/StereoPlus2/main.cpp @@ -136,21 +136,19 @@ int main() { return false; cross.Name = "Cross"; - cross.GUIPositionEditHandler = [&cross, i = &gui.input]() { i->movement() += cross.GUIPositionEditDifference; }; + cross.GUIPositionEditHandler = [] { Input::movement() += Scene::cross()->GUIPositionEditDifference; }; cross.GUIPositionEditHandlerId = Input::AddHandler(cross.GUIPositionEditHandler); - cross.keyboardBindingHandler = [&cross, i = &gui.input]() { - if (!Input::IsPressed(Key::Modifier::Alt) && cross.GUIPositionEditDifference == glm::vec3()) - return; - - auto m = i->movement() * Settings::TranslationStep().Get(); - if (Settings::SpaceMode().Get() == SpaceMode::Local) - m = glm::rotate(cross.GetWorldRotation(), m); - - cross.SetWorldPosition(cross.GetWorldPosition() + m); + cross.keyboardBindingHandler = [] { + auto relativeRotation = Input::GetRelativeRotation(glm::vec3()); + auto relativeMovement = Input::GetRelativeMovement(Scene::cross()->GUIPositionEditDifference); + + if (relativeRotation != glm::vec3()) + Transform::Rotate(Scene::cross()->GetWorldPosition(), relativeRotation, &Scene::cross().Get()); + if (relativeMovement != glm::vec3()) + Transform::Translate(relativeMovement, &Scene::cross().Get()); }; cross.keyboardBindingHandlerId = Input::AddHandler(cross.keyboardBindingHandler); - ToolPool::KeyBinding() = &gui.keyBinding; if (!ToolPool::Init()) return false; diff --git a/docs/dev.doc.en.md b/docs/dev.doc.en.md index c69f12c..bbb37a8 100644 --- a/docs/dev.doc.en.md +++ b/docs/dev.doc.en.md @@ -115,4 +115,7 @@ Provides relevant localization as quickly as possible. Receives a collestion of scene objects and draw them either dim or bright depending on their selections status. ### Windows -Middlemen between GUI and tools/objects \ No newline at end of file +Middlemen between GUI and tools/objects. + +### Math +Contains main math functions that made this program possible. \ No newline at end of file diff --git a/docs/doc.en.md b/docs/doc.en.md index d178c29..f0b2edb 100644 --- a/docs/doc.en.md +++ b/docs/doc.en.md @@ -47,9 +47,10 @@ For more details see Tools. - Esc - exit text inputting mode. Remove focus from all widgets. When no widget is active - deactivates tools; - Ctrl+Z - undo; - Ctrl+Y - redo; -- Ctrl+Q - toggle discrete movement mode; -- Ctrl+W - switch space mode (Local/World); - Ctrl+D - deselect all scene objects; +- Q - toggle discrete movement mode; +- W - switch space mode (Local/World); +- C - switch target mode (Object/Pivot); - T - transformation tool; - P - pen tool; - E - extrusion tool; From 01c02fb42ef01d7c903f75b311a2454380397781 Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 18:11:04 +0300 Subject: [PATCH 09/10] removed rotation reset on space mode change in sine pen --- StereoPlus2/Tools.hpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index 7f83163..9987f50 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -1153,7 +1153,6 @@ class SinePenTool : public EditingTool { const Log Logger = Log::For(); size_t inputHandlerId; - size_t spaceModeChangeHandlerId; size_t stateChangedHandlerId; size_t anyObjectChangedHandlerId; size_t modeChangedHandlerId; @@ -1334,9 +1333,6 @@ class SinePenTool : public EditingTool { target = t; - if (Settings::SpaceMode().Get() == SpaceMode::Local) - cross->SetWorldRotation(target.Get()->GetWorldRotation()); - if (!target->GetVertices().empty()) cross->SetWorldPosition(target->GetVertices().back()); @@ -1345,12 +1341,6 @@ class SinePenTool : public EditingTool { if (inputHandlerId) ProcessInput(); }); - spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { - if (v == SpaceMode::Local) - cross->SetWorldRotation(target.Get()->GetWorldRotation()); - else - cross->SetWorldRotation(glm::quat()); - }; stateChangedHandlerId = StateBuffer::OnStateChange() += [&] { if (!target.HasValue()) { cross->SetWorldRotation(glm::quat()); @@ -1411,12 +1401,6 @@ class SinePenTool : public EditingTool { if (inputHandlerId) ProcessInput(); }); - spaceModeChangeHandlerId = Settings::SpaceMode().OnChanged() += [&](const SpaceMode& v) { - if (v == SpaceMode::Local) - cross->SetWorldRotation(target.Get()->GetWorldRotation()); - else - cross->SetWorldRotation(glm::quat()); - }; stateChangedHandlerId = StateBuffer::OnStateChange() += [&] { if (!target.HasValue()) { cross->SetWorldRotation(glm::quat()); @@ -1452,7 +1436,6 @@ class SinePenTool : public EditingTool { createdAdditionalPoints = false; Input::RemoveHandler(inputHandlerId); - Settings::SpaceMode().OnChanged() -= spaceModeChangeHandlerId; StateBuffer::OnStateChange() -= stateChangedHandlerId; SceneObject::OnBeforeAnyElementChanged() -= anyObjectChangedHandlerId; mode.OnChanged() -= modeChangedHandlerId; From cecef1d3cc3e4af3a33817b9b05a19c9559b378f Mon Sep 17 00:00:00 2001 From: Prizrak9 Date: Sun, 9 May 2021 18:32:21 +0300 Subject: [PATCH 10/10] fixed sine build when 2 points are at the same location. --- CHANGE_LOG.md | 3 ++- StereoPlus2/Math.hpp | 14 ++++++++++---- StereoPlus2/Settings.hpp | 2 ++ StereoPlus2/Tools.hpp | 22 +++++++++++++++------- StereoPlus2/Windows.hpp | 27 ++++++++++++++++----------- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/CHANGE_LOG.md b/CHANGE_LOG.md index 8d32635..db166df 100644 --- a/CHANGE_LOG.md +++ b/CHANGE_LOG.md @@ -51,4 +51,5 @@ Added Publish configuration that cleans output before build and copies only nece - property/event overhaul; # 0.14 - introduced independent cross movement and rotation; -- isolated main math in separate static classes; \ No newline at end of file +- isolated main math in separate static classes; +- fixed sine building when 2 points are at the same location; \ No newline at end of file diff --git a/StereoPlus2/Math.hpp b/StereoPlus2/Math.hpp index 4705c14..b0dd86d 100644 --- a/StereoPlus2/Math.hpp +++ b/StereoPlus2/Math.hpp @@ -304,6 +304,16 @@ class Build { auto ab = vertices[1] - vertices[0]; auto bc = vertices[2] - vertices[1]; + auto acLength = glm::length(ac); + auto abLength = glm::length(ab); + auto bcLength = glm::length(bc); + + static const auto E = glm::epsilon(); + + // Draw straight line if 2 vertices are at the same location. + if (bcLength < E || abLength < E || acLength < E) + return { vertices[0], vertices[1], vertices[2] }; + auto acUnit = glm::normalize(ac); auto abadScalarProjection = glm::dot(ab, acUnit); auto dbUnit = glm::normalize(ab - acUnit * abadScalarProjection); @@ -317,16 +327,12 @@ class Build { if (isnan(r.x) || isnan(r.y) || isnan(r.z) || isnan(r.w)) return { vertices[0], vertices[1], vertices[2] }; - auto acLength = glm::length(ac); - auto abLength = glm::length(ab); auto bdLength = abdbScalarProjection; auto adLength = abadScalarProjection; auto dcLength = acLength - adLength; static const auto hpi = glm::half_pi(); - auto bcLength = glm::length(bc); - int abNumber = abLength / 5 + 1; int bcNumber = bcLength / 5 + 1; diff --git a/StereoPlus2/Settings.hpp b/StereoPlus2/Settings.hpp index 0081686..fcb1060 100644 --- a/StereoPlus2/Settings.hpp +++ b/StereoPlus2/Settings.hpp @@ -53,6 +53,8 @@ class Settings { StaticProperty(::MoveCoordinateAction, MoveCoordinateAction) StaticProperty(bool, ShouldDetectPosition) + StaticProperty(bool, ShouldRestrictTargetModeToPivot) + // Settings StaticProperty(std::string, Language) StaticProperty(int, StateBufferLength) diff --git a/StereoPlus2/Tools.hpp b/StereoPlus2/Tools.hpp index 9987f50..b5f9916 100644 --- a/StereoPlus2/Tools.hpp +++ b/StereoPlus2/Tools.hpp @@ -420,6 +420,7 @@ class PenTool : public EditingTool { StateBuffer::Commit(); wasCommitDone = true; }; + Settings::ShouldRestrictTargetModeToPivot() = true; } @@ -470,12 +471,15 @@ class PenTool : public EditingTool { StateBuffer::Commit(); wasCommitDone = true; }; + Settings::ShouldRestrictTargetModeToPivot() = true; return true; } virtual bool UnbindSceneObjects() { if (!lockCreateNewObjectHandlerId) Input::RemoveHandler(createNewObjectHandlerId); + + Settings::ShouldRestrictTargetModeToPivot() = false; if (!target.HasValue()) return true; @@ -866,9 +870,13 @@ class ExtrusionEditingTool : public EditingToolConfiguredSetWorldPosition(pos); }; + Settings::ShouldRestrictTargetModeToPivot() = true; + return true; } virtual bool UnbindSceneObjects() { + Settings::ShouldRestrictTargetModeToPivot() = true; + switch (mode) { case Mode::Immediate: @@ -1372,7 +1380,7 @@ class SinePenTool : public EditingTool { if (Settings::ShouldMoveCrossOnSinePenModeChange().Get()) moveCrossToVertice(currentVertice); }; - + Settings::ShouldRestrictTargetModeToPivot() = true; } public: @@ -1422,13 +1430,19 @@ class SinePenTool : public EditingTool { StateBuffer::Commit(); wasCommitDone = true; }; + Settings::ShouldRestrictTargetModeToPivot() = true; return true; } virtual bool UnbindSceneObjects() { + // On unbinding objects the tool goes to + // creating new object awaiting state. + // But if the tool is unbind then it should be cancelled. if (!lockCreateNewObjectHandlerId) Input::RemoveHandler(createNewObjectHandlerId); + Settings::ShouldRestrictTargetModeToPivot() = false; + if (!target.HasValue()) return true; @@ -1449,12 +1463,6 @@ class SinePenTool : public EditingTool { } virtual void UnbindTool() override { UnbindSceneObjects(); - - // On unbinding objects the tool goes to - // creating new object awaiting state. - // But if the tool is unbind then it should be cancelled. - if (!lockCreateNewObjectHandlerId) - Input::RemoveHandler(createNewObjectHandlerId); } SceneObject* GetTarget() { diff --git a/StereoPlus2/Windows.hpp b/StereoPlus2/Windows.hpp index ba20a92..eebf299 100644 --- a/StereoPlus2/Windows.hpp +++ b/StereoPlus2/Windows.hpp @@ -1301,12 +1301,6 @@ class ToolWindow : Window { }; } - /*void Unbind() { - attributesWindow->UnbindTarget(); - attributesWindow->UnbindTool(); - }*/ - - virtual bool Init() { if (!AttributesWindow().IsAssigned()) { @@ -1360,11 +1354,22 @@ class ToolWindow : Window { } { ImGui::Separator(); - auto v = (int)Settings::TargetMode().Get(); - if (ImGui::RadioButton(LocaleProvider::GetC("object"), &v, (int)TargetMode::Object)) - Settings::TargetMode() = TargetMode::Object; - if (ImGui::RadioButton(LocaleProvider::GetC("pivot"), &v, (int)TargetMode::Pivot)) - Settings::TargetMode() = TargetMode::Pivot; + if (Settings::ShouldRestrictTargetModeToPivot().Get()) { + auto v = (int)TargetMode::Pivot; + ImGui::Extensions::PushActive(false); + if (ImGui::RadioButton(LocaleProvider::GetC("object"), &v, (int)TargetMode::Object)) + Settings::TargetMode() = TargetMode::Object; + if (ImGui::RadioButton(LocaleProvider::GetC("pivot"), &v, (int)TargetMode::Pivot)) + Settings::TargetMode() = TargetMode::Pivot; + ImGui::Extensions::PopActive(); + } + else { + auto v = (int)Settings::TargetMode().Get(); + if (ImGui::RadioButton(LocaleProvider::GetC("object"), &v, (int)TargetMode::Object)) + Settings::TargetMode() = TargetMode::Object; + if (ImGui::RadioButton(LocaleProvider::GetC("pivot"), &v, (int)TargetMode::Pivot)) + Settings::TargetMode() = TargetMode::Pivot; + } } ImGui::Separator();