View navigation improvements: drag limits (per view type) and generic

recentering function to restore default view and adjust it to display
the entire scene (right mouse double clic).
This commit is contained in:
brunoherbelin
2020-07-12 00:30:32 +02:00
parent e43f56b123
commit bcc800e758
6 changed files with 133 additions and 22 deletions

View File

@@ -24,8 +24,9 @@ GlmToolkit::AxisAlignedBoundingBox BoundingBoxVisitor::bbox()
void BoundingBoxVisitor::visit(Node &n) void BoundingBoxVisitor::visit(Node &n)
{ {
// use the transform modified during update // use the transform modified during update modelview_ *= n.transform_;
modelview_ *= n.transform_; glm::mat4 transform_local = GlmToolkit::transform(n.translation_, n.rotation_, n.scale_);
modelview_ *= transform_local;
} }
void BoundingBoxVisitor::visit(Group &n) void BoundingBoxVisitor::visit(Group &n)

View File

@@ -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()) if (!isNull())
{ {
glm::vec3 d = mMax - mMin; glm::vec3 d = mMax - mMin;
return mMin + (d * 0.5f); ret = mMin + (d * 0.5f);
}
else
{
return glm::vec3(0.f);
} }
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()) if (!isNull())
{ {
glm::vec3 d = mMax - mMin; glm::vec3 d = mMax - mMin;
return d * 0.5f; ret = d * 0.5f;
}
else
{
return glm::vec3(0.f);
} }
if (ignore_z)
ret.z = 1.f;
return ret;
} }
bool GlmToolkit::AxisAlignedBoundingBox::intersect(const AxisAlignedBoundingBox& bb, bool ignore_z) const bool GlmToolkit::AxisAlignedBoundingBox::intersect(const AxisAlignedBoundingBox& bb, bool ignore_z) const

View File

@@ -28,8 +28,8 @@ public:
inline bool isNull() const { return mMin.x > mMax.x || mMin.y > mMax.y || mMin.z > mMax.z;} 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 min() const { return mMin; }
inline glm::vec3 max() const { return mMax; } inline glm::vec3 max() const { return mMax; }
glm::vec3 center() const; glm::vec3 center(bool ignore_z = true) const;
glm::vec3 scale() const; glm::vec3 scale(bool ignore_z = true) const;
bool intersect(const AxisAlignedBoundingBox& bb, 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(const AxisAlignedBoundingBox& bb, bool ignore_z = true) const;
bool contains(glm::vec3 point, bool ignore_z = true) const; bool contains(glm::vec3 point, bool ignore_z = true) const;

View File

@@ -358,6 +358,7 @@ void UserInterface::handleMouse()
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
glm::vec2 mousepos(io.MousePos.x * io.DisplayFramebufferScale.y, io.MousePos.y* io.DisplayFramebufferScale.x); 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]; 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_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); 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) ) if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right) )
{ {
Mixer::manager().view()->restoreSettings(); Mixer::manager().view()->recenter();
} }
// //

101
View.cpp
View File

@@ -20,6 +20,7 @@
#include "Source.h" #include "Source.h"
#include "SessionSource.h" #include "SessionSource.h"
#include "PickingVisitor.h" #include "PickingVisitor.h"
#include "BoundingBoxVisitor.h"
#include "DrawVisitor.h" #include "DrawVisitor.h"
#include "Mesh.h" #include "Mesh.h"
#include "Mixer.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() void View::selectAll()
{ {
Mixer::selection().clear(); 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() ); 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) void MixingView::setAlpha(Source *s)
{ {
if (!s) if (!s)
@@ -620,6 +680,16 @@ View::Cursor GeometryView::over (Source*, glm::vec2, std::pair<Node *, glm::vec2
return ret; return ret;
} }
View::Cursor GeometryView::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, -1.5f, 0.f), glm::vec3(3.f, 1.5f, 0.f));
return ret;
}
LayerView::LayerView() : View(LAYER), aspect_ratio(1.f) LayerView::LayerView() : View(LAYER), aspect_ratio(1.f)
{ {
// read default settings // 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() ); 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 // TRANSITION
TransitionView::TransitionView() : View(TRANSITION), transition_source_(nullptr) 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 // if want to open session after play, target movement till end position, otherwise stop at 0
float target_x = open ? 0.4f : 0.f; 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); 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; 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 remaining time is more than 50ms
if (time > 50.f) { if (time > 50.f) {
// start animation // 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() ); 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;
}

12
View.h
View File

@@ -66,9 +66,7 @@ public:
} }
virtual void initiate(); virtual void initiate();
virtual void recenter();
virtual void restoreSettings();
virtual void saveSettings();
// accessible scene // accessible scene
Scene scene; Scene scene;
@@ -77,6 +75,10 @@ public:
static bool need_deep_update_; static bool need_deep_update_;
protected: protected:
virtual void restoreSettings();
virtual void saveSettings();
Mode mode_; Mode mode_;
}; };
@@ -91,6 +93,7 @@ public:
void selectAll() override; void selectAll() override;
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2>) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2>) override;
Cursor drag (glm::vec2, glm::vec2) override;
void setAlpha (Source *s); void setAlpha (Source *s);
inline float limboScale() { return limbo_scale_; } inline float limboScale() { return limbo_scale_; }
@@ -131,6 +134,7 @@ public:
std::pair<Node *, glm::vec2> pick(glm::vec2 P) override; std::pair<Node *, glm::vec2> pick(glm::vec2 P) override;
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
Cursor over (Source *s, glm::vec2 pos, std::pair<Node *, glm::vec2> pick) override; Cursor over (Source *s, glm::vec2 pos, std::pair<Node *, glm::vec2> pick) override;
Cursor drag (glm::vec2, glm::vec2) override;
// void select(glm::vec2, glm::vec2) override; // void select(glm::vec2, glm::vec2) override;
// class Box *selection_box_; // class Box *selection_box_;
@@ -144,6 +148,7 @@ public:
void update (float dt) override; void update (float dt) override;
void zoom (float factor) override; void zoom (float factor) override;
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
Cursor drag (glm::vec2, glm::vec2) override;
float setDepth (Source *, float d = -1.f); float setDepth (Source *, float d = -1.f);
@@ -167,6 +172,7 @@ public:
std::pair<Node *, glm::vec2> pick(glm::vec2 P) override; std::pair<Node *, glm::vec2> pick(glm::vec2 P) override;
void selectAll() override; void selectAll() override;
Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair<Node *, glm::vec2> pick) override;
Cursor drag (glm::vec2, glm::vec2) override;
private: private:
class Surface *output_surface_; class Surface *output_surface_;