diff --git a/BoundingBoxVisitor.cpp b/BoundingBoxVisitor.cpp index 7237719..0fb2225 100644 --- a/BoundingBoxVisitor.cpp +++ b/BoundingBoxVisitor.cpp @@ -24,8 +24,9 @@ GlmToolkit::AxisAlignedBoundingBox BoundingBoxVisitor::bbox() void BoundingBoxVisitor::visit(Node &n) { - // use the transform modified during update - modelview_ *= n.transform_; + // use the transform modified during update modelview_ *= n.transform_; + glm::mat4 transform_local = GlmToolkit::transform(n.translation_, n.rotation_, n.scale_); + modelview_ *= transform_local; } void BoundingBoxVisitor::visit(Group &n) diff --git a/GlmToolkit.cpp b/GlmToolkit.cpp index 663e517..098efb0 100644 --- a/GlmToolkit.cpp +++ b/GlmToolkit.cpp @@ -58,30 +58,36 @@ void GlmToolkit::AxisAlignedBoundingBox::extend(const AxisAlignedBoundingBox& bb } } -glm::vec3 GlmToolkit::AxisAlignedBoundingBox::center() const +glm::vec3 GlmToolkit::AxisAlignedBoundingBox::center(bool ignore_z) const { + glm::vec3 ret = glm::vec3(0.f); + if (!isNull()) { glm::vec3 d = mMax - mMin; - return mMin + (d * 0.5f); - } - else - { - return glm::vec3(0.f); + ret = mMin + (d * 0.5f); } + + if (ignore_z) + ret.z = 0.f; + + return ret; } -glm::vec3 GlmToolkit::AxisAlignedBoundingBox::scale() const +glm::vec3 GlmToolkit::AxisAlignedBoundingBox::scale(bool ignore_z) const { + glm::vec3 ret = glm::vec3(1.f); + if (!isNull()) { glm::vec3 d = mMax - mMin; - return d * 0.5f; - } - else - { - return glm::vec3(0.f); + ret = d * 0.5f; } + + if (ignore_z) + ret.z = 1.f; + + return ret; } bool GlmToolkit::AxisAlignedBoundingBox::intersect(const AxisAlignedBoundingBox& bb, bool ignore_z) const diff --git a/GlmToolkit.h b/GlmToolkit.h index 2ea7cf4..43c2bcc 100644 --- a/GlmToolkit.h +++ b/GlmToolkit.h @@ -28,8 +28,8 @@ public: inline bool isNull() const { return mMin.x > mMax.x || mMin.y > mMax.y || mMin.z > mMax.z;} inline glm::vec3 min() const { return mMin; } inline glm::vec3 max() const { return mMax; } - glm::vec3 center() const; - glm::vec3 scale() const; + glm::vec3 center(bool ignore_z = true) const; + glm::vec3 scale(bool ignore_z = true) const; bool intersect(const AxisAlignedBoundingBox& bb, bool ignore_z = true) const; bool contains(const AxisAlignedBoundingBox& bb, bool ignore_z = true) const; bool contains(glm::vec3 point, bool ignore_z = true) const; diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index b6b7df1..5257647 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -358,6 +358,7 @@ void UserInterface::handleMouse() ImGuiIO& io = ImGui::GetIO(); glm::vec2 mousepos(io.MousePos.x * io.DisplayFramebufferScale.y, io.MousePos.y* io.DisplayFramebufferScale.x); + mousepos = glm::clamp(mousepos, glm::vec2(0.f), glm::vec2(io.DisplaySize.x, io.DisplaySize.y)); static glm::vec2 mouseclic[2]; mouseclic[ImGuiMouseButton_Left] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Left].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Left].y* io.DisplayFramebufferScale.x); mouseclic[ImGuiMouseButton_Right] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Right].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Right].y* io.DisplayFramebufferScale.x); @@ -403,7 +404,7 @@ void UserInterface::handleMouse() } if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right) ) { - Mixer::manager().view()->restoreSettings(); + Mixer::manager().view()->recenter(); } // diff --git a/View.cpp b/View.cpp index 1343061..0ecdb4f 100644 --- a/View.cpp +++ b/View.cpp @@ -20,6 +20,7 @@ #include "Source.h" #include "SessionSource.h" #include "PickingVisitor.h" +#include "BoundingBoxVisitor.h" #include "DrawVisitor.h" #include "Mesh.h" #include "Mixer.h" @@ -117,6 +118,55 @@ void View::initiate() } } +void View::recenter() +{ + // restore default view + restoreSettings(); + + // calculate screen area visible in the default view + GlmToolkit::AxisAlignedBoundingBox view_box; + glm::mat4 modelview = GlmToolkit::transform(scene.root()->translation_, scene.root()->rotation_, scene.root()->scale_); + view_box.extend( Rendering::manager().unProject(glm::vec2(0.f, Rendering::manager().mainWindow().height()), modelview) ); + view_box.extend( Rendering::manager().unProject(glm::vec2(Rendering::manager().mainWindow().width(), 0.f), modelview) ); + + // calculate screen area required to see the entire scene + BoundingBoxVisitor scene_visitor_bbox; + scene.accept(scene_visitor_bbox); + GlmToolkit::AxisAlignedBoundingBox scene_box = scene_visitor_bbox.bbox(); + + // if the default view does not contains the entire scene + // we shall adjust the view to fit the scene + if ( !view_box.contains(scene_box)) { + + // drag view to move towards scene_box center (while remaining in limits of the view) + glm::vec2 from = Rendering::manager().project(-view_box.center(), modelview); + glm::vec2 to = Rendering::manager().project(-scene_box.center(), modelview); + drag(from, to); + + // recalculate the view bounding box + GlmToolkit::AxisAlignedBoundingBox updated_view_box; + glm::mat4 modelview = GlmToolkit::transform(scene.root()->translation_, scene.root()->rotation_, scene.root()->scale_); + updated_view_box.extend( Rendering::manager().unProject(glm::vec2(0.f, Rendering::manager().mainWindow().height()), modelview) ); + updated_view_box.extend( Rendering::manager().unProject(glm::vec2(Rendering::manager().mainWindow().width(), 0.f), modelview) ); + + // if the updated (translated) view does not contains the entire scene + // we shall scale the view to fit the scene + if ( !updated_view_box.contains(scene_box)) { + + glm::vec3 view_extend = updated_view_box.max() - updated_view_box.min(); + updated_view_box.extend(scene_box); + glm::vec3 scene_extend = scene_box.max() - scene_box.min(); + glm::vec3 scale = view_extend / scene_extend ; + + float z = scene.root()->scale_.x; + z = CLAMP( z * MIN(scale.x, scale.y), MIXING_MIN_SCALE, MIXING_MAX_SCALE); + scene.root()->scale_.x = z; + scene.root()->scale_.y = z; + + } + } +} + void View::selectAll() { Mixer::selection().clear(); @@ -244,6 +294,16 @@ View::Cursor MixingView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pai return Cursor(Cursor_ResizeAll, info.str() ); } +View::Cursor MixingView::drag (glm::vec2 from, glm::vec2 to) +{ + Cursor ret = View::drag(from, to); + + // Clamp translation to acceptable area + scene.root()->translation_ = glm::clamp(scene.root()->translation_, glm::vec3(-3.f, -2.f, 0.f), glm::vec3(3.f, 2.f, 0.f)); + + return ret; +} + void MixingView::setAlpha(Source *s) { if (!s) @@ -620,6 +680,16 @@ View::Cursor GeometryView::over (Source*, glm::vec2, std::pairtranslation_ = glm::clamp(scene.root()->translation_, glm::vec3(-3.f, -1.5f, 0.f), glm::vec3(3.f, 1.5f, 0.f)); + + return ret; +} + LayerView::LayerView() : View(LAYER), aspect_ratio(1.f) { // read default settings @@ -733,6 +803,18 @@ View::Cursor LayerView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair return Cursor(Cursor_ResizeAll, info.str() ); } + +View::Cursor LayerView::drag (glm::vec2 from, glm::vec2 to) +{ + Cursor ret = View::drag(from, to); + + // Clamp translation to acceptable area + scene.root()->translation_ = glm::clamp(scene.root()->translation_, glm::vec3(0.f), glm::vec3(4.f, 2.f, 0.f)); + + return ret; +} + + // TRANSITION TransitionView::TransitionView() : View(TRANSITION), transition_source_(nullptr) @@ -978,11 +1060,16 @@ void TransitionView::play(bool open) // if want to open session after play, target movement till end position, otherwise stop at 0 float target_x = open ? 0.4f : 0.f; - // calculate time remaining to reach target + // calculate how far to reach target float time = CLAMP(- transition_source_->group(View::TRANSITION)->translation_.x, 0.f, 1.f); - time += open ? 0.2f : 0.f;; // extra time to reach transition if want to open + // extra distance to reach transition if want to open + time += open ? 0.2f : 0.f; + // calculate remaining time on the total duration, in ms time *= Settings::application.transition.duration * 1000.f; + // cancel previous animation + transition_source_->group(View::TRANSITION)->update_callbacks_.clear(); + // if remaining time is more than 50ms if (time > 50.f) { // start animation @@ -1020,4 +1107,14 @@ View::Cursor TransitionView::grab (Source *s, glm::vec2 from, glm::vec2 to, std: return Cursor(Cursor_ResizeEW, info.str() ); } +View::Cursor TransitionView::drag (glm::vec2 from, glm::vec2 to) +{ + Cursor ret = View::drag(from, to); + + // Clamp translation to acceptable area + scene.root()->translation_ = glm::clamp(scene.root()->translation_, glm::vec3(1.f, -1.7f, 0.f), glm::vec3(2.f, 1.7f, 0.f)); + + return ret; +} + diff --git a/View.h b/View.h index f81aad3..44466ed 100644 --- a/View.h +++ b/View.h @@ -66,9 +66,7 @@ public: } virtual void initiate(); - - virtual void restoreSettings(); - virtual void saveSettings(); + virtual void recenter(); // accessible scene Scene scene; @@ -77,6 +75,10 @@ public: static bool need_deep_update_; protected: + + virtual void restoreSettings(); + virtual void saveSettings(); + Mode mode_; }; @@ -91,6 +93,7 @@ public: void selectAll() override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair) override; + Cursor drag (glm::vec2, glm::vec2) override; void setAlpha (Source *s); inline float limboScale() { return limbo_scale_; } @@ -131,6 +134,7 @@ public: std::pair pick(glm::vec2 P) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; Cursor over (Source *s, glm::vec2 pos, std::pair pick) override; + Cursor drag (glm::vec2, glm::vec2) override; // void select(glm::vec2, glm::vec2) override; // class Box *selection_box_; @@ -144,6 +148,7 @@ public: void update (float dt) override; void zoom (float factor) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; + Cursor drag (glm::vec2, glm::vec2) override; float setDepth (Source *, float d = -1.f); @@ -167,6 +172,7 @@ public: std::pair pick(glm::vec2 P) override; void selectAll() override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; + Cursor drag (glm::vec2, glm::vec2) override; private: class Surface *output_surface_;