diff --git a/Decorations.cpp b/Decorations.cpp index a36821b..260bc31 100644 --- a/Decorations.cpp +++ b/Decorations.cpp @@ -355,55 +355,95 @@ void Symbol::accept(Visitor& v) v.visit(*this); } +Mesh *Disk::disk_ = nullptr; -SelectionBox::SelectionBox() +Disk::Disk() : Node() +{ + if (Disk::disk_ == nullptr) + Disk::disk_ = new Mesh("mesh/disk.ply"); + + color = glm::vec4( 1.f, 1.f, 1.f, 1.f); +} + +Disk::~Disk() { -// color = glm::vec4( 1.f, 1.f, 1.f, 1.f); - color = glm::vec4( 1.f, 0.f, 0.f, 1.f); - square_ = new LineSquare( 3 ); } -void SelectionBox::draw (glm::mat4 modelview, glm::mat4 projection) +void Disk::draw(glm::mat4 modelview, glm::mat4 projection) { if ( !initialized() ) { - square_->init(); + if (!Disk::disk_->initialized()) + Disk::disk_->init(); init(); } - if (visible_) { - - // use a visitor bounding box to calculate extend of all selected nodes - BoundingBoxVisitor vbox; - - // visit every child of the selection - for (NodeSet::iterator node = children_.begin(); - node != children_.end(); node++) { - // reset the transform before - vbox.setModelview(glm::identity()); - (*node)->accept(vbox); - } - - // get the bounding box - bbox_ = vbox.bbox(); - -// Log::Info(" -------- visitor box (%f, %f)-(%f, %f)", bbox_.min().x, bbox_.min().y, bbox_.max().x, bbox_.max().y); + if ( visible_ ) { // set color - square_->shader()->color = color; + Disk::disk_->shader()->color = color; - // compute transformation from bounding box -// glm::mat4 ctm = modelview * GlmToolkit::transform(glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f)); - glm::mat4 ctm = modelview * GlmToolkit::transform(bbox_.center(), glm::vec3(0.f), bbox_.scale()); + glm::mat4 ctm = modelview * transform_; + Disk::disk_->draw( ctm, projection); - // draw bbox -// square_->draw( modelview, projection); - square_->draw( ctm, projection); - - // DEBUG -// visible_=false; } +} +void Disk::accept(Visitor& v) +{ + Node::accept(v); + v.visit(*this); } +//SelectionBox::SelectionBox() +//{ +//// color = glm::vec4( 1.f, 1.f, 1.f, 1.f); +// color = glm::vec4( 1.f, 0.f, 0.f, 1.f); +// square_ = new LineSquare( 3 ); + +//} + +//void SelectionBox::draw (glm::mat4 modelview, glm::mat4 projection) +//{ +// if ( !initialized() ) { +// square_->init(); +// init(); +// } + +// if (visible_) { + +// // use a visitor bounding box to calculate extend of all selected nodes +// BoundingBoxVisitor vbox; + +// // visit every child of the selection +// for (NodeSet::iterator node = children_.begin(); +// node != children_.end(); node++) { +// // reset the transform before +// vbox.setModelview(glm::identity()); +// (*node)->accept(vbox); +// } + +// // get the bounding box +// bbox_ = vbox.bbox(); + +//// Log::Info(" -------- visitor box (%f, %f)-(%f, %f)", bbox_.min().x, bbox_.min().y, bbox_.max().x, bbox_.max().y); + +// // set color +// square_->shader()->color = color; + +// // compute transformation from bounding box +//// glm::mat4 ctm = modelview * GlmToolkit::transform(glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f)); +// glm::mat4 ctm = modelview * GlmToolkit::transform(bbox_.center(), glm::vec3(0.f), bbox_.scale()); + +// // draw bbox +//// square_->draw( modelview, projection); +// square_->draw( ctm, projection); + +// // DEBUG +//// visible_=false; +// } + +//} + + diff --git a/Decorations.h b/Decorations.h index 8acbeb2..b89bedd 100644 --- a/Decorations.h +++ b/Decorations.h @@ -72,20 +72,35 @@ protected: Type type_; }; -class SelectionBox : public Group +class Disk : public Node { public: - SelectionBox(); + Disk(); + ~Disk(); void draw (glm::mat4 modelview, glm::mat4 projection) override; + void accept (Visitor& v) override; glm::vec4 color; protected: - LineSquare *square_; - GlmToolkit::AxisAlignedBoundingBox bbox_; - + static Mesh *disk_; }; +//class SelectionBox : public Group +//{ +//public: +// SelectionBox(); + +// void draw (glm::mat4 modelview, glm::mat4 projection) override; + +// glm::vec4 color; + +//protected: +// LineSquare *square_; +// GlmToolkit::AxisAlignedBoundingBox bbox_; + +//}; + #endif // DECORATIONS_H diff --git a/Mesh.h b/Mesh.h index a08ac97..8ff4ae1 100644 --- a/Mesh.h +++ b/Mesh.h @@ -26,7 +26,7 @@ public: inline std::string meshPath() const { return mesh_resource_; } inline std::string texturePath() const { return texture_resource_; } -//protected: +protected: std::string mesh_resource_; std::string texture_resource_; uint textureindex_; diff --git a/Mixer.cpp b/Mixer.cpp index e766c62..6a8e1a5 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -231,9 +231,6 @@ void Mixer::draw() // draw the current view in the window current_view_->draw(); - // make sure we disable fading of session rendering - if (current_view_ != &transition_) - session_->fadeIn(); } // manangement of sources @@ -555,6 +552,7 @@ void Mixer::setView(View::Mode m) case View::MIXING: default: current_view_ = &mixing_; + mixing_.setFading( session_->fading() ); break; } diff --git a/PickingVisitor.cpp b/PickingVisitor.cpp index a9c21a6..26b2c57 100644 --- a/PickingVisitor.cpp +++ b/PickingVisitor.cpp @@ -58,10 +58,9 @@ void PickingVisitor::visit(Switch &n) modelview_ = mv; } -void PickingVisitor::visit(Primitive &n) +void PickingVisitor::visit(Primitive &) { - // TODO: generic visitor for primitive with random shape ? - + // by default, a Primitive is not interactive } void PickingVisitor::visit(Surface &n) @@ -97,10 +96,20 @@ void PickingVisitor::visit(Surface &n) } } -void PickingVisitor::visit(Frame &n) +void PickingVisitor::visit(Disk &n) { -// if (n.border()) -// n.border()->accept(*this); + // discard if not visible or if not exactly one point given for picking + if (!n.visible_ || points_.size() != 1) + return; + + // apply inverse transform to the point of interest + glm::vec4 P = glm::inverse(modelview_) * glm::vec4( points_[0], 1.f ); + + // test distance for picking from a single point + if ( glm::length(glm::vec2(P)) < 1.f ) + // add this surface to the nodes picked + nodes_.push_back( std::pair(&n, glm::vec2(P)) ); + } void PickingVisitor::visit(Handles &n) @@ -147,29 +156,6 @@ void PickingVisitor::visit(Handles &n) } -void PickingVisitor::visit(LineSquare &) -{ -// // apply inverse transform to the point of interest -// glm::vec4 P = glm::inverse(modelview_) * glm::vec4( point_A_, 0.f, 1.f ); - -// // lower left corner -// glm::vec3 LL = glm::vec3( -1.f, -1.f, 0.f ); -// // up right corner -// glm::vec3 UR = glm::vec3( 1.f, 1.f, 0.f ); - -// // if P is over a line [LL UR] rectangle: -// // TODO -} - -void PickingVisitor::visit(LineCircle &n) -{ -// // apply inverse transform to the point of interest -// glm::vec4 P = glm::inverse(modelview_) * glm::vec4( point_A_, 0.f, 1.f ); - -// float r = glm::length( glm::vec2(P) ); -// if ( r < 1.02 && r > 0.98) -// nodes_.push_back( std::pair(&n, glm::vec2(P)) ); -} void PickingVisitor::visit(Scene &n) { diff --git a/PickingVisitor.h b/PickingVisitor.h index 5ad1166..6c7d681 100644 --- a/PickingVisitor.h +++ b/PickingVisitor.h @@ -7,6 +7,15 @@ #include "Visitor.h" +/** + * @brief The PickingVisitor class is used to + * capture which objects of a scene are located at the screen + * coordinate. Typically at mouse cursor coordinates for + * user interaction. + * + * Only a subset of interactive objects (surface and Decorations) + * are interactive. + */ class PickingVisitor: public Visitor { std::vector points_; @@ -26,11 +35,21 @@ public: void visit(Switch& n) override; void visit(Primitive& n) override; + /** + * @brief visit Surface : picking source rendering surface + * @param n + */ void visit(Surface& n) override; - void visit(Frame& n) override; + /** + * @brief visit Handles : picking grabbers of source in geometry view + * @param n + */ void visit(Handles& n) override; - void visit(LineSquare&) override; - void visit(LineCircle& n) override; + /** + * @brief visit Disk : picking grabber for mixing view + * @param n + */ + void visit(Disk& n) override; }; diff --git a/Session.cpp b/Session.cpp index 055ef43..a0904e3 100644 --- a/Session.cpp +++ b/Session.cpp @@ -9,7 +9,7 @@ #include "Log.h" -Session::Session() : filename_(""), failedSource_(nullptr), active_(true) +Session::Session() : filename_(""), failedSource_(nullptr), active_(true), fading_target_(0.f) { config_[View::RENDERING] = new Group; config_[View::RENDERING]->scale_ = render_.resolution(); @@ -69,6 +69,12 @@ void Session::update(float dt) } } + // apply fading (smooth dicotomic reaching) + float f = render_.fading(); + if ( ABS_DIFF(f, fading_target_) > EPSILON) { + render_.setFading( f + ( fading_target_ - f ) / 2.f); + } + // update the scene tree render_.update(dt); @@ -152,20 +158,22 @@ void Session::setResolution(glm::vec3 resolution) void Session::setFading(float f) { - render_.setFading(f); + fading_target_ = CLAMP(f, 0.f, 1.f); } -void Session::fadeIn() { - float f = render_.fading(); - if ( f > EPSILON) - render_.setFading( f / 2.f); -} -void Session::fadeOut() { - float f = render_.fading(); - if ( f < 1.f - EPSILON) - render_.setFading( f * 2.f); -} + +//void Session::fadeIn() { +// float f = render_.fading(); +// if ( f > EPSILON) +// render_.setFading( f / 2.f); +//} + +//void Session::fadeOut() { +// float f = render_.fading(); +// if ( f < 1.f - EPSILON) +// render_.setFading( f * 2.f); +//} SourceList::iterator Session::begin() { diff --git a/Session.h b/Session.h index 742d580..524d97c 100644 --- a/Session.h +++ b/Session.h @@ -59,8 +59,7 @@ public: // manipulate fading of output void setFading(float f); - void fadeIn(); - void fadeOut(); + inline float fading() const { return fading_target_; } // configuration for group nodes of views inline Group *config (View::Mode m) const { return config_.at(m); } @@ -77,7 +76,7 @@ protected: std::map config_; bool active_; std::list recorders_; - + float fading_target_; }; #endif // SESSION_H diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 203ba21..de785cf 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -428,20 +428,16 @@ void UserInterface::handleMouse() // ask the view what was picked picked = Mixer::manager().view()->pick(mousepos); + bool clear_selection = false; // if nothing picked, if ( picked.first == nullptr ) { - // unset current - Mixer::manager().unsetCurrentSource(); - navigator.hidePannel(); - // clear selection - Mixer::selection().clear(); + clear_selection = true; } // something was picked else { // get if a source was picked Source *s = Mixer::manager().findSource(picked.first); if (s != nullptr) { - // CTRL + clic = multiple selection if (keyboard_modifier_active) { if ( !Mixer::selection().contains(s) ) @@ -455,14 +451,24 @@ void UserInterface::handleMouse() } } } - + // making the picked source the current one Mixer::manager().setCurrentSource( s ); if (navigator.pannelVisible()) navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); // indicate to view that an action can be initiated (e.g. grab) - Mixer::manager().view()->initiate(); + Mixer::manager().view()->storeStatus(); } + // no source is selected + else + clear_selection = true; + } + if (clear_selection) { + // unset current + Mixer::manager().unsetCurrentSource(); + navigator.hidePannel(); + // clear selection + Mixer::selection().clear(); } } } @@ -497,7 +503,7 @@ void UserInterface::handleMouse() view_drag = Mixer::manager().view(); // indicate to view that an action can be initiated (e.g. grab) - Mixer::manager().view()->initiate(); + Mixer::manager().view()->storeStatus(); } // only operate if the view didn't change @@ -513,6 +519,11 @@ void UserInterface::handleMouse() c = Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mousepos, picked); setMouseCursor(io.MousePos, c); } + else if ( picked.first != nullptr ) + { + View::Cursor c = Mixer::manager().view()->grab(nullptr, mouseclic[ImGuiMouseButton_Left], mousepos, picked); + setMouseCursor(io.MousePos, c); + } // Selection area else { ImGui::GetBackgroundDrawList()->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, @@ -527,6 +538,11 @@ void UserInterface::handleMouse() } } } + else { + // cancel all operations on view when interacting on GUI + view_drag = nullptr; + mousedown = false; + } } diff --git a/View.cpp b/View.cpp index 0c5a052..32a03fc 100644 --- a/View.cpp +++ b/View.cpp @@ -105,11 +105,12 @@ std::pair View::pick(glm::vec2 P) // select top-most Node picked pick = pv.picked().back(); + Log::Info("picked %d", pick.first->id()); } return pick; } -void View::initiate() +void View::storeStatus() { for (auto sit = Mixer::manager().session()->begin(); sit != Mixer::manager().session()->end(); sit++){ @@ -227,19 +228,40 @@ MixingView::MixingView() : View(MIXING), limbo_scale_(1.3f) restoreSettings(); // Mixing scene background - Mesh *disk = new Mesh("mesh/disk.ply"); - disk->scale_ = glm::vec3(limbo_scale_, limbo_scale_, 1.f); - disk->shader()->color = glm::vec4( COLOR_LIMBO_CIRCLE, 0.6f ); - scene.bg()->attach(disk); + Mesh *tmp = new Mesh("mesh/disk.ply"); + tmp->scale_ = glm::vec3(limbo_scale_, limbo_scale_, 1.f); + tmp->shader()->color = glm::vec4( COLOR_LIMBO_CIRCLE, 0.6f ); + scene.bg()->attach(tmp); - disk = new Mesh("mesh/disk.ply"); - disk->setTexture(textureMixingQuadratic()); - scene.bg()->attach(disk); + mixingCircle_ = new Mesh("mesh/disk.ply"); + mixingCircle_->setTexture(textureMixingQuadratic()); + mixingCircle_->shader()->color = glm::vec4( 1.f, 1.f, 1.f, 1.f ); + scene.bg()->attach(mixingCircle_); - Mesh *circle = new Mesh("mesh/circle.ply"); - circle->shader()->color = glm::vec4( COLOR_FRAME, 0.9f ); - scene.bg()->attach(circle); + Symbol *dot = new Symbol(Symbol::POINT, glm::vec3(0.f, 1.f, 0.1f)); + dot->scale_ = glm::vec3( 0.33f, 0.33f, 1.f); + dot->color = glm::vec4( COLOR_FRAME, 1.f ); + scene.bg()->attach(dot); + tmp = new Mesh("mesh/circle.ply"); + tmp->shader()->color = glm::vec4( COLOR_FRAME, 0.9f ); + scene.bg()->attach(tmp); + + // Mixing scene foreground + slider_root_ = new Group; + scene.fg()->attach(slider_root_); + + tmp = new Mesh("mesh/disk.ply"); + tmp->scale_ = glm::vec3(0.08f, 0.08f, 1.f); + tmp->translation_ = glm::vec3(0.0f, 1.0f, 0.f); + tmp->shader()->color = glm::vec4( COLOR_FRAME, 0.9f ); + slider_root_->attach(tmp); + + slider_ = new Disk(); + slider_->scale_ = glm::vec3(0.075f, 0.075f, 1.f); + slider_->translation_ = glm::vec3(0.0f, 1.0f, 0.f); + slider_->color = glm::vec4( COLOR_SLIDER_CIRCLE, 1.0f ); + slider_root_->attach(slider_); } @@ -275,7 +297,6 @@ void MixingView::centerSource(Source *s) } - void MixingView::selectAll() { for(auto sit = Mixer::manager().session()->begin(); @@ -284,15 +305,63 @@ void MixingView::selectAll() } } -View::Cursor MixingView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair) +void MixingView::setFading(float f) { - if (!s) - return Cursor(); + // reverse calculate angle from fading + float angle = SIGN(slider_root_->rotation_.z) * asin(f) * 2.f; + // move slider + slider_root_->rotation_.z = angle; + // visual feedback on mixing circle + f = 1.f - f; + mixingCircle_->shader()->color = glm::vec4(f, f, f, 1.f); +} +View::Cursor MixingView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) +{ // unproject glm::vec3 gl_Position_from = Rendering::manager().unProject(from, scene.root()->transform_); glm::vec3 gl_Position_to = Rendering::manager().unProject(to, scene.root()->transform_); + // No source is given + if (!s) { + + // if interaction with slider + if (pick.first == slider_) { + + // apply rotation to match angle with mouse cursor + float angle = glm::orientedAngle( glm::normalize(glm::vec2(0.f, 1.0)), glm::normalize(glm::vec2(gl_Position_to))); + + // snap on 0 and PI angles + if ( ABS_DIFF(angle, 0.f) < 0.05) + angle = 0.f; + else if ( ABS_DIFF(angle, M_PI) < 0.05) + angle = M_PI; + + // animate slider (rotation angle on its parent) + slider_root_->rotation_.z = angle; + + // calculate fading from angle + float fading = sin( ABS(angle) * 0.5f); + + // apply fading to session + Mixer::manager().session()->setFading(fading); + + // visual feedback on mixing circle + fading = 1.f - fading; + mixingCircle_->shader()->color = glm::vec4(fading, fading, fading, 1.f); + + // cursor feedback + std::ostringstream info; + info << "Global opacity " << int(fading * 100.0) << " %"; + return Cursor(Cursor_Hand, info.str() ); + } + + // nothing to do + return Cursor(); + } + // + // Interaction with source + // // compute delta translation s->group(mode_)->translation_ = s->stored_status_->translation_ + gl_Position_to - gl_Position_from; @@ -459,7 +528,6 @@ void RenderView::draw() frame_buffer_->end(); } - GeometryView::GeometryView() : View(GEOMETRY) { // read default settings @@ -585,8 +653,6 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p { View::Cursor ret = Cursor(); - std::ostringstream info; - // work on the given source if (!s) return ret; @@ -607,6 +673,7 @@ View::Cursor GeometryView::grab (Source *s, glm::vec2 from, glm::vec2 to, std::p // Log::Info(" ( %.1f, %.1f, %.1f ) ", S_to.x, S_to.y, S_to.z); // which manipulation to perform? + std::ostringstream info; if (pick.first) { // picking on the resizing handles in the corners if ( pick.first == s->handle_[Handles::RESIZE] ) { @@ -1112,14 +1179,13 @@ View::Cursor TransitionView::grab (Source *s, glm::vec2 from, glm::vec2 to, std: if (!s) return Cursor(); - std::ostringstream info; - // unproject glm::vec3 gl_Position_from = Rendering::manager().unProject(from, scene.root()->transform_); glm::vec3 gl_Position_to = Rendering::manager().unProject(to, scene.root()->transform_); // compute delta translation float d = s->stored_status_->translation_.x + gl_Position_to.x - gl_Position_from.x; + std::ostringstream info; if (d > 0.2) { s->group(View::TRANSITION)->translation_.x = 0.4; info << "Open session"; diff --git a/View.h b/View.h index c18a314..3450e2c 100644 --- a/View.h +++ b/View.h @@ -56,6 +56,7 @@ public: virtual Cursor drag (glm::vec2, glm::vec2); // grab a source provided a start and an end point in screen coordinates and the picking point + virtual void storeStatus(); virtual Cursor grab (Source*, glm::vec2, glm::vec2, std::pair) { return Cursor(); } @@ -65,7 +66,6 @@ public: return Cursor(); } - virtual void initiate(); virtual void recenter(); // accessible scene @@ -91,17 +91,23 @@ public: void draw () override; void zoom (float factor) override; void centerSource(Source *) override; - 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_; } + void setFading (float f); + private: uint textureMixingQuadratic(); float limbo_scale_; + + Group *slider_root_; + class Disk *slider_; + class Mesh *mixingCircle_; }; class RenderView : public View @@ -132,13 +138,12 @@ public: void draw () override; void update (float dt) override; void zoom (float factor) override; + 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_; }; class LayerView : public View @@ -148,6 +153,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; @@ -162,19 +168,19 @@ class TransitionView : public View public: TransitionView(); - void attach(SessionSource *ts); - class Session *detach(); - - void play(bool open); - void draw () override; void update (float dt) override; void zoom (float factor) override; - std::pair pick(glm::vec2 P) override; void selectAll() override; + + std::pair pick(glm::vec2 P) override; Cursor grab (Source *s, glm::vec2 from, glm::vec2 to, std::pair pick) override; Cursor drag (glm::vec2, glm::vec2) override; + void attach(SessionSource *ts); + class Session *detach(); + void play(bool open); + private: class Surface *output_surface_; class Mesh *mark_100ms_, *mark_1s_; diff --git a/Visitor.h b/Visitor.h index 11738a1..3624876 100644 --- a/Visitor.h +++ b/Visitor.h @@ -19,6 +19,7 @@ class LineCircle; class Mesh; class Frame; class Handles; +class Disk; class MediaPlayer; class Shader; class ImageShader; @@ -51,6 +52,7 @@ public: virtual void visit (Mesh&) {} virtual void visit (Frame&) {} virtual void visit (Handles&) {} + virtual void visit (Disk&) {} virtual void visit (MediaPlayer&) {} virtual void visit (Shader&) {} virtual void visit (ImageShader&) {} diff --git a/defines.h b/defines.h index d3679d8..df2b146 100644 --- a/defines.h +++ b/defines.h @@ -64,6 +64,7 @@ #define COLOR_TRANSITION_LINES 0.9f, 0.9f, 0.9f #define COLOR_FRAME 0.8f, 0.f, 0.8f #define COLOR_LIMBO_CIRCLE 0.16f, 0.16f, 0.16f +#define COLOR_SLIDER_CIRCLE 0.11f, 0.11f, 0.11f // from glmixer #define TEXTURE_REQUIRED_MAXIMUM 2048