New Distortion of output window in Displays view

Allows shape distortion of output rendering (e.g. for perspective correction of projection), added Grid snap cursor support in Displays view
This commit is contained in:
Bruno Herbelin
2023-12-31 18:34:48 +01:00
parent 6b1e298d43
commit 578a72f560
8 changed files with 456 additions and 253 deletions

View File

@@ -40,10 +40,12 @@
#include "Source.h" #include "Source.h"
#include "Settings.h" #include "Settings.h"
#include "PickingVisitor.h" #include "PickingVisitor.h"
#include "DrawVisitor.h"
#include "Decorations.h" #include "Decorations.h"
#include "UserInterfaceManager.h" #include "UserInterfaceManager.h"
#include "BoundingBoxVisitor.h" #include "BoundingBoxVisitor.h"
#include "RenderingManager.h" #include "RenderingManager.h"
#include "MousePointer.h"
#include "DisplaysView.h" #include "DisplaysView.h"
@@ -78,7 +80,7 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
for (auto w = windows_.begin(); w != windows_.end(); ++w){ for (auto w = windows_.begin(); w != windows_.end(); ++w){
// surface & buffer for render // surface & buffer for render
w->output_render_ = new Surface; w->output_render_ = new MeshSurface;
w->renderbuffer_ = new FrameBuffer(1024, 1024); w->renderbuffer_ = new FrameBuffer(1024, 1024);
// root node // root node
@@ -123,9 +125,9 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
w->mode_ = new Switch; w->mode_ = new Switch;
g->attach(w->mode_); g->attach(w->mode_);
// mode_ [0] is for WINDOWED // mode_ [0] is for WINDOWED
w->handles_ = new Handles(Handles::SCALE); w->resize_ = new Handles(Handles::SCALE);
w->handles_->color = glm::vec4( COLOR_WINDOW, 1.f ); w->resize_->color = glm::vec4( COLOR_WINDOW, 1.f );
w->mode_->attach(w->handles_); w->mode_->attach(w->resize_);
// mode_ [1] is for FULLSCREEN // mode_ [1] is for FULLSCREEN
w->fullscreen_ = new Symbol(Symbol::TELEVISION); w->fullscreen_ = new Symbol(Symbol::TELEVISION);
w->fullscreen_->scale_ = glm::vec3(2.f, 2.f, 1.f); w->fullscreen_->scale_ = glm::vec3(2.f, 2.f, 1.f);
@@ -134,12 +136,27 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
// Output frame // Output frame
w->output_group_ = new Group; w->output_group_ = new Group;
w->root_->attach(w->output_group_); w->root_->attach(w->output_group_);
w->output_frame_ = new Frame(Frame::SHARP, Frame::THIN, Frame::NONE); w->output_handles_[0] = new Handles(Handles::NODE_LOWER_LEFT);
w->output_frame_->color = glm::vec4( COLOR_FRAME, 1.f ); w->output_handles_[0]->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_group_->attach(w->output_frame_); w->output_group_->attach(w->output_handles_[0]);
w->output_handles_ = new Handles(Handles::RESIZE); w->output_handles_[1] = new Handles(Handles::NODE_UPPER_LEFT);
w->output_handles_->color = glm::vec4( COLOR_FRAME, 1.f ); w->output_handles_[1]->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_group_->attach(w->output_handles_); w->output_group_->attach(w->output_handles_[1]);
w->output_handles_[2] = new Handles(Handles::NODE_LOWER_RIGHT);
w->output_handles_[2]->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_group_->attach(w->output_handles_[2]);
w->output_handles_[3] = new Handles(Handles::NODE_UPPER_RIGHT);
w->output_handles_[3]->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_group_->attach(w->output_handles_[3]);
std::vector<glm::vec2> path;
path.push_back(glm::vec2(-1.f, -1.f));
path.push_back(glm::vec2(-1.f, 1.f));
path.push_back(glm::vec2( 1.f, 1.f));
path.push_back(glm::vec2( 1.f, -1.f));
w->output_lines_ = new LineLoop(path, 2.f);
w->output_lines_->shader()->color = glm::vec4(COLOR_FRAME, 0.96f);
w->output_group_->attach(w->output_lines_);
// default to not active & window overlay frame // default to not active & window overlay frame
w->output_group_->visible_ = false; w->output_group_->visible_ = false;
w->overlays_->setActive(0); w->overlays_->setActive(0);
@@ -153,6 +170,17 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
current_output_status_ = new Group; current_output_status_ = new Group;
draw_pending_ = false; draw_pending_ = false;
output_ar = 1.f; output_ar = 1.f;
// grid is attached to a transform group
// to adapt to windows geometry; see adaptGridToWindow()
gridroot_ = new Group;
gridroot_->visible_ = false;
scene.root()->attach(gridroot_);
// replace grid with appropriate one
if (grid) delete grid;
grid = new TranslationGrid(gridroot_);
grid->root()->visible_ = false;
} }
void DisplaysView::update(float dt) void DisplaysView::update(float dt)
@@ -164,49 +192,97 @@ void DisplaysView::update(float dt)
// update rendering of render frame // update rendering of render frame
for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i) { for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i) {
windows_[i].output_render_->setTextureIndex( Rendering::manager().outputWindow(i).texture() );
// update visible flag // ensure to update texture index
windows_[i].root_->visible_ = i < Settings::application.num_output_windows; windows_[i].output_render_->setTextureIndex(
windows_[i].icon_->visible_ = Settings::application.render.disabled; Rendering::manager().outputWindow(i).texture());
// Rendering of output is scaled to content and manipulated by output frame // avoid busy update
if (Settings::application.windows[i+1].scaled) { if (windows_[i].need_update_) {
windows_[i].output_render_->scale_ = windows_[i].output_group_->scale_; --windows_[i].need_update_;
windows_[i].output_render_->translation_ = windows_[i].output_group_->translation_;
// show output frame
windows_[i].output_group_->visible_ = true;
}
// Rendering of output is adjusted to match aspect ratio of framebuffer
else {
float out_ar = windows_[i].root_->scale_.x / windows_[i].root_->scale_.y;
if (output_ar < out_ar)
windows_[i].output_render_->scale_ = glm::vec3(output_ar / out_ar, 1.f, 1.f);
else
windows_[i].output_render_->scale_ = glm::vec3(1.f, out_ar / output_ar, 1.f);
// reset translation
windows_[i].output_render_->translation_ = glm::vec3(0.f);
// do not show output frame
windows_[i].output_group_->visible_ = false;
}
if ( current_window_ == i ) { // update visible flag
windows_[i].overlays_->setActive(1); windows_[i].root_->visible_ = i < Settings::application.num_output_windows;
windows_[i].output_handles_->visible_ = true; windows_[i].icon_->visible_ = Settings::application.render.disabled;
windows_[i].output_frame_->color = glm::vec4( COLOR_FRAME, 1.f );
windows_[i].title_->shader()->color = glm::vec4( COLOR_WINDOW, 1.f );
}
else {
windows_[i].overlays_->setActive(0);
windows_[i].output_handles_->visible_ = false;
windows_[i].output_frame_->color = glm::vec4( COLOR_FRAME, 0.3f );
windows_[i].title_->shader()->color = glm::vec4( COLOR_WINDOW, 0.8f );
}
// Rendering of output is distorted with custom fit
if (Settings::application.windows[i+1].custom) {
// reset scale
windows_[i].output_render_->scale_ = glm::vec3(1.f);
// update node distortion
windows_[i].output_group_->data_ = Settings::application.windows[i + 1].nodes;
for (int k = 0; k < 4; ++k) {
windows_[i].output_handles_[k]->translation_.x
= windows_[i].output_group_->data_[k].x;
windows_[i].output_handles_[k]->translation_.y
= windows_[i].output_group_->data_[k].y;
}
// update the shape of the distorted outline
std::vector<glm::vec2> path;
path.push_back(glm::vec2(-1.f, -1.f) + glm::vec2(windows_[i].output_handles_[0]->translation_));
path.push_back(glm::vec2(-1.f, 1.f) + glm::vec2(windows_[i].output_handles_[1]->translation_));
path.push_back(glm::vec2( 1.f, 1.f) + glm::vec2(windows_[i].output_handles_[3]->translation_));
path.push_back(glm::vec2( 1.f, -1.f) + glm::vec2(windows_[i].output_handles_[2]->translation_));
windows_[i].output_lines_->changePath(path);
// apply nodes distortion
ImageShader *is = dynamic_cast<ImageShader*>(windows_[i].output_render_->shader());
is->iNodes = windows_[i].output_group_->data_;
// show output frame
windows_[i].output_group_->visible_ = true;
}
// Rendering of output is adjusted to match aspect ratio of framebuffer
else {
// apply scaling
float out_ar = windows_[i].root_->scale_.x / windows_[i].root_->scale_.y;
if (output_ar < out_ar)
windows_[i].output_render_->scale_ = glm::vec3(output_ar / out_ar, 1.f, 1.f);
else
windows_[i].output_render_->scale_ = glm::vec3(1.f, out_ar / output_ar, 1.f);
// reset nodes distortion
ImageShader *is = dynamic_cast<ImageShader*>(windows_[i].output_render_->shader());
is->iNodes = glm::zero<glm::mat4>();
// do not show output frame
windows_[i].output_group_->visible_ = false;
}
// Highlight current window
if ( current_window_ == i ) {
windows_[i].overlays_->setActive(1);
for (int k = 0; k < 4; ++k)
windows_[i].output_handles_[k]->visible_ = true;
windows_[i].output_lines_->shader()->color = glm::vec4( COLOR_FRAME, 0.96f );
windows_[i].title_->shader()->color = glm::vec4( COLOR_WINDOW, 1.f );
}
else {
windows_[i].overlays_->setActive(0);
for (int k = 0; k < 4; ++k)
windows_[i].output_handles_[k]->visible_ = false;
windows_[i].output_lines_->shader()->color = glm::vec4( COLOR_FRAME, 0.3f );
windows_[i].title_->shader()->color = glm::vec4( COLOR_WINDOW, 0.8f );
}
}
} }
output_ar = Mixer::manager().session()->frame()->aspectRatio(); output_ar = Mixer::manager().session()->frame()->aspectRatio();
} }
// a more complete update is requested
if (View::need_deep_update_ > 0) {
// change grid color
ImVec4 c = ImGuiToolkit::HighlightColor();
grid->setColor( glm::vec4(c.x, c.y, c.z, 0.3) );
// force update
for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i)
++windows_[i].need_update_;
}
} }
@@ -310,6 +386,42 @@ int DisplaysView::size ()
return (int) ( sqrt(z) * 100.f); return (int) ( sqrt(z) * 100.f);
} }
void DisplaysView::adaptGridToWindow(int w)
{
// reset by default
gridroot_->scale_ = glm::vec3(1.f);
gridroot_->translation_ = glm::vec3(0.f);
grid->setAspectRatio(1.f);
// adapt grid scaling to given window if parameter is given
if (w > -1) {
gridroot_->scale_.x = windows_[w].root_->scale_.x;
gridroot_->scale_.y = windows_[w].root_->scale_.y;
gridroot_->translation_.x = windows_[w].root_->translation_.x;
gridroot_->translation_.y = windows_[w].root_->translation_.y;
if (!Settings::application.proportional_grid)
grid->setAspectRatio((float) windows_[w].root_->scale_.y / windows_[w].root_->scale_.x);
}
// set grid aspect ratio to display size otherwise
else if (current_window_ > -1) {
if (Settings::application.proportional_grid) {
std::string m = Rendering::manager()
.monitorNameAt(Settings::application.windows[current_window_ + 1].x,
Settings::application.windows[current_window_ + 1].y);
glm::ivec4 rect = Rendering::manager().monitors()[m];
gridroot_->translation_.x = rect.x * DISPLAYS_UNIT;
gridroot_->translation_.y = rect.y * -DISPLAYS_UNIT;
gridroot_->scale_.x = rect.p * 0.5f * DISPLAYS_UNIT;
gridroot_->scale_.y = rect.q * 0.5f * DISPLAYS_UNIT;
}
}
}
void DisplaysView::draw() void DisplaysView::draw()
{ {
// White ballance color button // White ballance color button
@@ -419,14 +531,19 @@ void DisplaysView::draw()
windows_[i].title_->translation_.y = 1.f + windows_[i].title_->scale_.y; windows_[i].title_->translation_.y = 1.f + windows_[i].title_->scale_.y;
} }
windows_[i].output_group_->scale_ = Settings::application.windows[i+1].scale;
windows_[i].output_group_->translation_ = Settings::application.windows[i+1].translation;
} }
} }
// main call to draw the view // main call to draw the view
View::draw(); View::draw();
// Display grid in overlay
if (grid->active() && current_action_ongoing_) {
const glm::mat4 projection = Rendering::manager().Projection();
DrawVisitor draw_grid(grid->root(), projection, true);
scene.accept(draw_grid);
}
// display interface // display interface
// Locate window at upper left corner // Locate window at upper left corner
glm::vec2 P = glm::vec2(0.01f, 0.01 ); glm::vec2 P = glm::vec2(0.01f, 0.01 );
@@ -463,6 +580,7 @@ void DisplaysView::draw()
if (ImGuiToolkit::IconButton(18, 4, "More windows")) { if (ImGuiToolkit::IconButton(18, 4, "More windows")) {
++Settings::application.num_output_windows; ++Settings::application.num_output_windows;
current_window_ = Settings::application.num_output_windows-1; current_window_ = Settings::application.num_output_windows-1;
windows_[current_window_].need_update_ += 2;
} }
} }
else else
@@ -488,10 +606,12 @@ void DisplaysView::draw()
// Output options // Output options
ImGui::SameLine(0, 2.f * g.Style.FramePadding.x); ImGui::SameLine(0, 2.f * g.Style.FramePadding.x);
ImGuiToolkit::ButtonIconToggle(9,5, &Settings::application.windows[1+current_window_].scaled, "Custom fit"); if ( ImGuiToolkit::ButtonIconToggle(9,5, &Settings::application.windows[1+current_window_].custom, "Custom fit") )
++windows_[current_window_].need_update_;
ImGui::SameLine(0, g.Style.FramePadding.x); ImGui::SameLine(0, g.Style.FramePadding.x);
ImGuiToolkit::ButtonIconToggle(11,1, &Settings::application.windows[1+current_window_].show_pattern, "Test pattern"); if ( ImGuiToolkit::ButtonIconToggle(11,1, &Settings::application.windows[1+current_window_].show_pattern, "Test pattern") )
++windows_[current_window_].need_update_;
ImGui::SameLine(0, 1.5f * g.Style.FramePadding.x); ImGui::SameLine(0, 1.5f * g.Style.FramePadding.x);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_DEFAULT); ImGuiToolkit::PushFont(ImGuiToolkit::FONT_DEFAULT);
@@ -548,7 +668,6 @@ void DisplaysView::draw()
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::PopStyleColor(8); ImGui::PopStyleColor(8);
ImGui::End(); ImGui::End();
} }
@@ -584,6 +703,7 @@ void DisplaysView::draw()
if (ImGui::MenuItem( menutext.c_str(), nullptr, _fullscreen )){ if (ImGui::MenuItem( menutext.c_str(), nullptr, _fullscreen )){
windows_[current_window_].monitor_ = monitor_iter->first; windows_[current_window_].monitor_ = monitor_iter->first;
Rendering::manager().outputWindow(current_window_).setFullscreen( windows_[current_window_].monitor_ ); Rendering::manager().outputWindow(current_window_).setFullscreen( windows_[current_window_].monitor_ );
windows_[current_window_].need_update_ += 2;
} }
} }
@@ -593,16 +713,17 @@ void DisplaysView::draw()
Rendering::manager().outputWindow(current_window_).exitFullscreen(); Rendering::manager().outputWindow(current_window_).exitFullscreen();
// not fullscreen on a monitor // not fullscreen on a monitor
windows_[current_window_].monitor_ = ""; windows_[current_window_].monitor_ = "";
windows_[current_window_].need_update_ += 2;
} }
ImGui::Separator(); ImGui::Separator();
bool _borderless = !Settings::application.windows[current_window_+1].decorated; bool _borderless = !Settings::application.windows[current_window_+1].decorated;
if (ImGui::MenuItem( ICON_FA_SQUARE_FULL " Borderless", nullptr, &_borderless, _windowed)){ if (ImGui::MenuItem( ICON_FA_SQUARE_FULL " Borderless", nullptr, &_borderless, _windowed)){
Rendering::manager().outputWindow(current_window_).setDecoration(!_borderless); Rendering::manager().outputWindow(current_window_).setDecoration(!_borderless);
++windows_[current_window_].need_update_;
} }
if (ImGui::MenuItem( ICON_FA_EXPAND " Fit all Displays", nullptr, false, _windowed )){ if (ImGui::MenuItem( ICON_FA_EXPAND " Fit all Displays", nullptr, false, _windowed )){
Rendering::manager().outputWindow(current_window_).setDecoration(false); Rendering::manager().outputWindow(current_window_).setDecoration(false);
glm::ivec4 rect (INT_MAX, INT_MAX, 0, 0); glm::ivec4 rect (INT_MAX, INT_MAX, 0, 0);
std::map<std::string, glm::ivec4> _monitors = Rendering::manager().monitors(); std::map<std::string, glm::ivec4> _monitors = Rendering::manager().monitors();
@@ -614,6 +735,7 @@ void DisplaysView::draw()
rect.q = MAX(rect.q, monitor_iter->second.y+monitor_iter->second.q); rect.q = MAX(rect.q, monitor_iter->second.y+monitor_iter->second.q);
} }
Rendering::manager().outputWindow(current_window_).setCoordinates( rect ); Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
windows_[current_window_].need_update_ += 2;
} }
if (ImGui::MenuItem( ICON_FA_EXPAND_ALT " Restore aspect ratio" , nullptr, false, _windowed )){ if (ImGui::MenuItem( ICON_FA_EXPAND_ALT " Restore aspect ratio" , nullptr, false, _windowed )){
@@ -625,6 +747,7 @@ void DisplaysView::draw()
else else
rect.q = rect.p / ar; rect.q = rect.p / ar;
Rendering::manager().outputWindow(current_window_).setCoordinates( rect ); Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
windows_[current_window_].need_update_ += 2;
} }
if (ImGui::MenuItem( ICON_FA_RULER_COMBINED " Rescale to pixel size", nullptr, false, _windowed )){ if (ImGui::MenuItem( ICON_FA_RULER_COMBINED " Rescale to pixel size", nullptr, false, _windowed )){
@@ -633,6 +756,7 @@ void DisplaysView::draw()
rect.p = Mixer::manager().session()->frame()->width(); rect.p = Mixer::manager().session()->frame()->width();
rect.q = Mixer::manager().session()->frame()->height(); rect.q = Mixer::manager().session()->frame()->height();
Rendering::manager().outputWindow(current_window_).setCoordinates( rect ); Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
windows_[current_window_].need_update_ += 2;
} }
ImGui::Separator(); ImGui::Separator();
@@ -642,24 +766,21 @@ void DisplaysView::draw()
rect.q = Mixer::manager().session()->frame()->height(); rect.q = Mixer::manager().session()->frame()->height();
Rendering::manager().outputWindow(current_window_).setDecoration(true); Rendering::manager().outputWindow(current_window_).setDecoration(true);
Settings::application.windows[1+current_window_].show_pattern = false; Settings::application.windows[1+current_window_].show_pattern = false;
Settings::application.windows[1+current_window_].scaled = false; Settings::application.windows[1+current_window_].custom = false;
Settings::application.windows[1+current_window_].scale = glm::vec3(1.f);
Settings::application.windows[1+current_window_].translation = glm::vec3(0.f);
Settings::application.windows[1+current_window_].whitebalance = glm::vec4(1.f, 1.f, 1.f, 0.5f); Settings::application.windows[1+current_window_].whitebalance = glm::vec4(1.f, 1.f, 1.f, 0.5f);
if (Settings::application.windows[current_window_+1].fullscreen) if (Settings::application.windows[current_window_+1].fullscreen)
Rendering::manager().outputWindow(current_window_).exitFullscreen(); Rendering::manager().outputWindow(current_window_).exitFullscreen();
else else
Rendering::manager().outputWindow(current_window_).setCoordinates( rect ); Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
windows_[current_window_].need_update_ += 2;
} }
if ( Settings::application.windows[current_window_+1].scaled ) { if ( Settings::application.windows[current_window_+1].custom ) {
ImGui::PopStyleColor(1); ImGui::PopStyleColor(1);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_FRAME, 1.f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_FRAME, 1.f));
if ( ImGui::MenuItem( ICON_FA_VECTOR_SQUARE " Reset custom fit") )
if ( ImGui::MenuItem( ICON_FA_VECTOR_SQUARE " Reset custom fit") ) { Settings::application.windows[current_window_+1].nodes = glm::zero<glm::mat4>();
Settings::application.windows[1+current_window_].scale = glm::vec3(1.f); windows_[current_window_].need_update_ += 2;
Settings::application.windows[1+current_window_].translation = glm::vec3(0.f);
}
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
@@ -692,11 +813,19 @@ std::pair<Node *, glm::vec2> DisplaysView::pick(glm::vec2 P)
show_window_menu_ = true; show_window_menu_ = true;
// activate / deactivate window if clic on any element of it // activate / deactivate window if clic on any element of it
if ( (pick.first == windows_[i].surface_) || if ((pick.first == windows_[i].surface_) ||
(pick.first == windows_[i].handles_) || (pick.first == windows_[i].resize_) ||
(pick.first == windows_[i].output_handles_) || (pick.first == windows_[i].menu_) ) {
(pick.first == windows_[i].menu_) ) {
current_window_ = i; current_window_ = i;
adaptGridToWindow();
}
if ((pick.first == windows_[i].output_handles_[0]) ||
(pick.first == windows_[i].output_handles_[1]) ||
(pick.first == windows_[i].output_handles_[2]) ||
(pick.first == windows_[i].output_handles_[3]) ) {
current_window_ = i;
adaptGridToWindow(current_window_);
} }
} }
@@ -704,6 +833,10 @@ std::pair<Node *, glm::vec2> DisplaysView::pick(glm::vec2 P)
if (current_window_ < 0) if (current_window_ < 0)
pick.first = nullptr; pick.first = nullptr;
// request update
for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i)
++windows_[i].need_update_;
return pick; return pick;
} }
@@ -725,20 +858,22 @@ void DisplaysView::select(glm::vec2 A, glm::vec2 B)
// TODO Multiple window selection? // TODO Multiple window selection?
if (!pv.empty()) { if (!pv.empty()) {
// find which window was picked // find which window was picked
auto itp = pv.rbegin(); auto itp = pv.rbegin();
for (; itp != pv.rend(); ++itp){ for (; itp != pv.rend(); ++itp){
// search for WindowPreview // search for WindowPreview
auto w = std::find_if(windows_.begin(), windows_.end(), WindowPreview::hasNode(itp->first)); auto w = std::find_if(windows_.begin(), windows_.end(), WindowPreview::hasNode(itp->first));
if (w != windows_.end()) if (w != windows_.end()) {
// set current // set current
current_window_ = (int) std::distance(windows_.begin(), w); current_window_ = (int) std::distance(windows_.begin(), w);
++windows_[current_window_].need_update_;
}
} }
} }
} }
int _prev_mouse_pointer = 0;
void DisplaysView::initiate() void DisplaysView::initiate()
{ {
// initiate pending action // initiate pending action
@@ -756,6 +891,7 @@ void DisplaysView::initiate()
// initiated // initiated
current_action_ = ""; current_action_ = "";
current_action_ongoing_ = true; current_action_ongoing_ = true;
++windows_[current_window_].need_update_;
} }
} }
@@ -780,21 +916,24 @@ void DisplaysView::terminate(bool force)
GlmToolkit::AxisAlignedBoundingBox _bb; GlmToolkit::AxisAlignedBoundingBox _bb;
_bb.extend(glm::vec3(-1.f, -1.f, 0.f)); _bb.extend(glm::vec3(-1.f, -1.f, 0.f));
_bb.extend(glm::vec3(1.f, 1.f, 0.f)); _bb.extend(glm::vec3(1.f, 1.f, 0.f));
GlmToolkit::AxisAlignedBoundingBox output_bb = _bb.transformed( windows_[current_window_].output_group_->transform_ );
_bb = _bb.scaled(glm::vec3(0.9f)); _bb = _bb.scaled(glm::vec3(0.9f));
if ( !_bb.intersect(output_bb) || output_bb.area() < 0.1f ) { GlmToolkit::AxisAlignedBoundingBox output_bb;
output_bb.extend(glm::vec3(-1.f, -1.f, 0.f)
+ windows_[current_window_].output_handles_[0]->translation_);
output_bb.extend(glm::vec3(-1.f, 1.f, 0.f)
+ windows_[current_window_].output_handles_[1]->translation_);
output_bb.extend(glm::vec3(1.f, -1.f, 0.f)
+ windows_[current_window_].output_handles_[2]->translation_);
output_bb.extend(glm::vec3(1.f, 1.f, 0.f)
+ windows_[current_window_].output_handles_[3]->translation_);
if (!_bb.intersect(output_bb) || output_bb.area() < 0.05f) {
// No intersection of output bounding box with window area : revert to previous // No intersection of output bounding box with window area : revert to previous
windows_[current_window_].output_group_->scale_ = Settings::application.windows[current_window_+1].scale; Settings::application.windows[current_window_ + 1].nodes = current_output_status_->data_;
windows_[current_window_].output_group_->translation_ = Settings::application.windows[current_window_+1].translation; Log::Notify("Custom window output area outside window or too small");
}
else {
// Apply output area recentering to actual output window
Settings::application.windows[current_window_+1].scale = windows_[current_window_].output_group_->scale_;
Settings::application.windows[current_window_+1].translation = windows_[current_window_].output_group_->translation_;
} }
// reset overlay of grab corner // ensures update
windows_[current_window_].output_handles_->overlayActiveCorner(glm::vec2(0.f)); ++windows_[current_window_].need_update_;
} }
// terminated // terminated
@@ -811,8 +950,8 @@ glm::ivec4 DisplaysView::windowCoordinates(int index) const
{ {
glm::ivec4 rect; glm::ivec4 rect;
rect.x = (windows_[index].root_->translation_.x - windows_[index].root_->scale_.x) / DISPLAYS_UNIT; rect.x = ceil( (windows_[index].root_->translation_.x - windows_[index].root_->scale_.x) / DISPLAYS_UNIT );
rect.y = (windows_[index].root_->translation_.y + windows_[index].root_->scale_.y) / - DISPLAYS_UNIT; rect.y = ceil( (windows_[index].root_->translation_.y + windows_[index].root_->scale_.y) / - DISPLAYS_UNIT );
rect.p = 2.f * windows_[index].root_->scale_.x / DISPLAYS_UNIT; rect.p = 2.f * windows_[index].root_->scale_.x / DISPLAYS_UNIT;
rect.q = 2.f * windows_[index].root_->scale_.y / DISPLAYS_UNIT; rect.q = 2.f * windows_[index].root_->scale_.y / DISPLAYS_UNIT;
@@ -835,73 +974,71 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
glm::vec3 scene_translation = scene_to - scene_from; glm::vec3 scene_translation = scene_to - scene_from;
// a window is currently selected // a window is currently selected
if ( current_window_ > -1 ) { if (current_window_ > -1) {
// which window is grabbed ?
Group *w = windows_[current_window_].root_;
// which handle is grabbed ?
size_t picked_handle_ = 4;
if (pick.first == windows_[current_window_].output_handles_[0])
picked_handle_ = 0;
else if (pick.first == windows_[current_window_].output_handles_[1])
picked_handle_ = 1;
else if (pick.first == windows_[current_window_].output_handles_[2])
picked_handle_ = 2;
else if (pick.first == windows_[current_window_].output_handles_[3])
picked_handle_ = 3;
// Grab handles of the output frame to adjust // Grab handles of the output frame to adjust
if ( pick.first == windows_[current_window_].output_handles_ ) { if (picked_handle_ < 4) {
// which corner was picked ? // which corner was picked ?
glm::vec2 corner = glm::round(pick.second); glm::vec2 corner = glm::round(pick.second);
// inform on which corner should be overlayed (opposite)
windows_[current_window_].output_handles_->overlayActiveCorner(-corner);
// transform from center to corner // transform from center to corner
glm::mat4 T = GlmToolkit::transform(glm::vec3(corner.x, corner.y, 0.f), glm::vec3(0.f, 0.f, 0.f), glm::mat4 T = GlmToolkit::transform(glm::vec3(corner.x, corner.y, 0.f), glm::vec3(0.f, 0.f, 0.f),
glm::vec3(1.f, 1.f, 1.f)); glm::vec3(1.f, 1.f, 1.f));
glm::mat4 root_to_corner_transform = T * glm::inverse(current_output_status_->transform_); glm::mat4 root_to_corner_transform = T * glm::inverse(current_output_status_->transform_);
glm::mat4 corner_to_root_transform = glm::inverse(root_to_corner_transform); glm::mat4 corner_to_root_transform = glm::inverse(root_to_corner_transform);
// transformation from scene to corner: // transformation from scene to corner:
glm::mat4 scene_to_corner_transform = root_to_corner_transform * glm::inverse( current_window_status_->transform_); glm::mat4 scene_to_corner_transform = root_to_corner_transform * glm::inverse( current_window_status_->transform_);
// compute cursor movement in corner reference frame // compute cursor movement in corner reference frame
glm::vec4 corner_from = scene_to_corner_transform * glm::vec4( scene_from, 1.f ); glm::vec4 corner_from = scene_to_corner_transform * glm::vec4( scene_from, 1.f );
glm::vec4 corner_to = scene_to_corner_transform * glm::vec4( scene_to, 1.f ); glm::vec4 corner_to = scene_to_corner_transform * glm::vec4( scene_to, 1.f );
// get stored status
glm::vec3 node_pos = glm::vec3(current_output_status_->data_[picked_handle_].x,
current_output_status_->data_[picked_handle_].y,
0.f);
// Compute target coordinates of manipulated handle into CORNER reference frame
node_pos = root_to_corner_transform * glm::vec4(node_pos, 1.f);
// apply translation of target in CORNER
node_pos = glm::translate(glm::identity<glm::mat4>(), glm::vec3(corner_to - corner_from)) * glm::vec4(node_pos, 1.f);
// snap handle coordinates to grid (if active)
if ( grid->active() )
node_pos = grid->snap(node_pos);
// Diagonal SCALING with SHIFT
if (UserInterface::manager().shiftModifier())
node_pos.y = (corner.x * corner.y) * node_pos.x;
// Compute handle coordinates back in ROOT reference frame
node_pos = corner_to_root_transform * glm::vec4(node_pos, 1.f);
// operation of scaling in corner reference frame // apply to output
glm::vec3 corner_scaling = glm::vec3(corner_to) / glm::vec3(corner_from); Settings::application.windows[current_window_+1].nodes[picked_handle_].x = node_pos.x;
Settings::application.windows[current_window_+1].nodes[picked_handle_].y = node_pos.y;
// proportional SCALING with SHIFT // show cursor hand
if (UserInterface::manager().shiftModifier()) { ret.type = Cursor_Hand;
// calculate proportional scaling factor // show info depending on corner picked
float factor = glm::length( glm::vec2( corner_to ) ) / glm::length( glm::vec2( corner_from ) ); if (picked_handle_ == 0)
// scale node info << "Bottom-left";
windows_[current_window_].output_group_->scale_ = current_output_status_->scale_ * glm::vec3(factor, factor, 1.f); else if (picked_handle_ == 1)
} info << "Top-left";
// non-proportional CORNER RESIZE (normal case) else if (picked_handle_ == 3)
else { info << "Top-right";
// scale node else
windows_[current_window_].output_group_->scale_ = current_output_status_->scale_ * corner_scaling; info << "Bottom-right";
} node_pos.x *= (float) Settings::application.windows[current_window_ + 1].w;
node_pos.y *= -1.f * (float) Settings::application.windows[current_window_ + 1].h;
// update corner scaling to apply to center coordinates info << " +(" << std::fixed << std::setprecision(0) << node_pos.x << "," << node_pos.y << ")";
corner_scaling = windows_[current_window_].output_group_->scale_ / current_output_status_->scale_;
// TRANSLATION CORNER
// convert source position in corner reference frame
glm::vec4 center = root_to_corner_transform * glm::vec4( current_output_status_->translation_, 1.f);
// transform source center (in corner reference frame)
center = glm::scale(glm::identity<glm::mat4>(), corner_scaling) * center;
// convert center back into scene reference frame
center = corner_to_root_transform * center;
// apply to node
windows_[current_window_].output_group_->translation_ = glm::vec3(center);
// discretized scaling with ALT
if (UserInterface::manager().altModifier()) {
windows_[current_window_].output_group_->scale_ = glm::round( windows_[current_window_].output_group_->scale_ * 20.f) * 0.05f;
windows_[current_window_].output_group_->translation_ = glm::round( windows_[current_window_].output_group_->translation_ * 20.f) * 0.05f;
}
// show cursor depending on diagonal (corner picked)
T = glm::rotate(glm::identity<glm::mat4>(), current_output_status_->rotation_.z, glm::vec3(0.f, 0.f, 1.f));
T = glm::scale(T, current_output_status_->scale_);
corner = T * glm::vec4( corner, 0.f, 0.f );
ret.type = corner.x * corner.y > 0.f ? Cursor_ResizeNESW : Cursor_ResizeNWSE;
info << "Output resized " << std::fixed << std::setprecision(1) << 100.f * windows_[current_window_].output_group_->scale_.x;
info << " x " << 100.f * windows_[current_window_].output_group_->scale_.y << " %";
} }
// grab window not fullscreen : move or resizes // grab window not fullscreen : move or resizes
@@ -911,23 +1048,29 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
if ( pick.first == windows_[current_window_].surface_ ){ if ( pick.first == windows_[current_window_].surface_ ){
// apply translation // apply translation
windows_[current_window_].root_->translation_ = current_window_status_->translation_ + scene_translation; w->translation_ = current_window_status_->translation_ + scene_translation;
glm::ivec4 r = windowCoordinates(current_window_);
// discretized translation with ALT // snap coordinates to grid (if active)
if (UserInterface::manager().altModifier()) { if (grid->active()) {
r.x = ROUND(r.x, 0.01f); // get top left corner
r.y = ROUND(r.y, 0.01f); glm::vec2 sc = glm::vec2(w->scale_) * glm::vec2(1.f, -1.f);
windows_[current_window_].root_->translation_.x = (r.x * DISPLAYS_UNIT) + windows_[current_window_].root_->scale_.x; glm::vec2 top_left = glm::vec2(w->translation_) - sc;
windows_[current_window_].root_->translation_.y = (r.y * - DISPLAYS_UNIT) - windows_[current_window_].root_->scale_.y; top_left -= glm::vec2(gridroot_->translation_);
// snap to grid
top_left = grid->snap(top_left / glm::vec2(gridroot_->scale_))
* glm::vec2(gridroot_->scale_);
top_left += glm::vec2(gridroot_->translation_);
// revert to center coordinates
w->translation_ = glm::vec3(top_left, 0.f) + glm::vec3(sc, 0.f);
} }
// Show move cursor // Show move cursor
ret.type = Cursor_ResizeAll; ret.type = Cursor_ResizeAll;
glm::ivec4 r = windowCoordinates(current_window_);
info << "Window position " << r.x << ", " << r.y << " px"; info << "Window position " << r.x << ", " << r.y << " px";
} }
// grab handle to resize // grab handle to resize
else if ( pick.first == windows_[current_window_].handles_ ){ else if ( pick.first == windows_[current_window_].resize_ ){
// which corner was picked ? // which corner was picked ?
glm::vec2 corner = glm::round(pick.second); glm::vec2 corner = glm::round(pick.second);
@@ -942,7 +1085,8 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
// compute cursor movement in corner reference frame // compute cursor movement in corner reference frame
glm::vec4 corner_from = scene_to_corner_transform * glm::vec4( scene_from, 1.f ); glm::vec4 corner_from = scene_to_corner_transform * glm::vec4( scene_from, 1.f );
glm::vec4 corner_to = scene_to_corner_transform * glm::vec4( scene_to, 1.f ); glm::vec4 corner_to = scene_to_corner_transform * glm::vec4(scene_to, 1.f);
// operation of scaling in corner reference frame // operation of scaling in corner reference frame
glm::vec3 corner_scaling = glm::vec3(corner_to) / glm::vec3(corner_from); glm::vec3 corner_scaling = glm::vec3(corner_to) / glm::vec3(corner_from);
@@ -952,30 +1096,16 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
// proportional SCALING with SHIFT // proportional SCALING with SHIFT
if (UserInterface::manager().shiftModifier()) { if (UserInterface::manager().shiftModifier()) {
// calculate proportional scaling factor // calculate proportional scaling factor
float factor = glm::length( glm::vec2( corner_to ) ) / glm::length( glm::vec2( corner_from ) ); float factor = glm::length(glm::vec2(corner_to)) / glm::length(glm::vec2(corner_from));
// scale node w->scale_ = current_window_status_->scale_ * glm::vec3(factor, factor, 1.f);
windows_[current_window_].root_->scale_ = current_window_status_->scale_ * glm::vec3(factor, factor, 1.f);
} }
// non-proportional CORNER RESIZE (normal case) // non-proportional CORNER RESIZE (normal case)
else { else {
// scale node w->scale_ = current_window_status_->scale_ * corner_scaling;
windows_[current_window_].root_->scale_ = current_window_status_->scale_ * corner_scaling;
} }
// discretized scaling with ALT
if (UserInterface::manager().altModifier()) {
// calculate ratio of scaling modulo the output resolution
glm::vec3 outputsize = windows_[current_window_].root_->scale_ / DISPLAYS_UNIT;
glm::vec3 framesize = Mixer::manager().session()->frame()->resolution();
glm::vec3 ra = outputsize / framesize;
ra.x = ROUND(ra.x, 20.f);
ra.y = ROUND(ra.y, 20.f);
outputsize = ra * framesize;
windows_[current_window_].root_->scale_.x = outputsize.x * DISPLAYS_UNIT;
windows_[current_window_].root_->scale_.y = outputsize.y * DISPLAYS_UNIT;
}
// update corner scaling to apply to center coordinates // update corner scaling to apply to center coordinates
corner_scaling = windows_[current_window_].root_->scale_ / current_window_status_->scale_; corner_scaling = w->scale_ / current_window_status_->scale_;
// TRANSLATION CORNER // TRANSLATION CORNER
// convert source position in corner reference frame // convert source position in corner reference frame
@@ -985,10 +1115,28 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
// convert center back into scene reference frame // convert center back into scene reference frame
center = corner_to_scene_transform * center; center = corner_to_scene_transform * center;
// apply to node // apply to node
windows_[current_window_].root_->translation_ = glm::vec3(center); w->translation_ = glm::vec3(center);
// snap coordinates to grid (if active)
if (grid->active()) {
// get bottom right corner
glm::vec2 sc = glm::vec2(w->scale_) * glm::vec2(1.f, -1.f);
glm::vec2 bottom_right = glm::vec2(w->translation_) + sc;
bottom_right -= glm::vec2(gridroot_->translation_);
// snap corner to grid
bottom_right = grid->snap(bottom_right / glm::vec2(gridroot_->scale_))
* glm::vec2(gridroot_->scale_);
bottom_right += glm::vec2(gridroot_->translation_);
// recalculate center coordinates and scale
sc = glm::vec2(current_window_status_->scale_) * glm::vec2(1.f, -1.f);
glm::vec2 top_left = glm::vec2(current_window_status_->translation_) - sc;
glm::vec2 middle = top_left + (bottom_right - top_left) * 0.5f;
w->translation_ = glm::vec3(middle, 0.f);
w->scale_ = glm::vec3((bottom_right - top_left) * glm::vec2(0.5f, -0.5f), 1.f);
}
// rescale title bar // rescale title bar
windows_[current_window_].title_->scale_.y = WINDOW_TITLEBAR_HEIGHT / windows_[current_window_].root_->scale_.y; windows_[current_window_].title_->scale_.y = WINDOW_TITLEBAR_HEIGHT / w->scale_.y;
windows_[current_window_].title_->translation_.y = 1.f + windows_[current_window_].title_->scale_.y; windows_[current_window_].title_->translation_.y = 1.f + windows_[current_window_].title_->scale_.y;
// show cursor // show cursor
@@ -1017,10 +1165,10 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
&& scene_to.y > r.y && scene_to.y < r.y + r.q) { && scene_to.y > r.y && scene_to.y < r.y + r.q) {
// show output frame on top of that monitor // show output frame on top of that monitor
windows_[current_window_].root_->scale_.x = r.p * 0.5f * DISPLAYS_UNIT; w->scale_.x = r.p * 0.5f * DISPLAYS_UNIT;
windows_[current_window_].root_->scale_.y = r.q * 0.5f * DISPLAYS_UNIT; w->scale_.y = r.q * 0.5f * DISPLAYS_UNIT;
windows_[current_window_].root_->translation_.x = r.x * DISPLAYS_UNIT + windows_[current_window_].root_->scale_.x; w->translation_.x = r.x * DISPLAYS_UNIT + w->scale_.x;
windows_[current_window_].root_->translation_.y = -r.y * DISPLAYS_UNIT - windows_[current_window_].root_->scale_.y; w->translation_.y = -r.y * DISPLAYS_UNIT - w->scale_.y;
// remember the output monitor selected // remember the output monitor selected
windows_[current_window_].monitor_ = monitor_iter->first; windows_[current_window_].monitor_ = monitor_iter->first;
@@ -1033,6 +1181,9 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
} }
} }
} }
// request update
++windows_[current_window_].need_update_;
} }
// update cursor // update cursor
@@ -1121,7 +1272,7 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
bool DisplaysView::doubleclic (glm::vec2 P) bool DisplaysView::doubleclic (glm::vec2 P)
{ {
// TODO find which window? // bring window forward
if ( pick(P).first != nullptr) { if ( pick(P).first != nullptr) {
Rendering::manager().outputWindow(current_window_).show(); Rendering::manager().outputWindow(current_window_).show();
return true; return true;
@@ -1130,58 +1281,82 @@ bool DisplaysView::doubleclic (glm::vec2 P)
return false; return false;
} }
#define MAX_DURATION 1000.f #define TIME_STEP 500
#define MIN_SPEED_D 0.1f
#define MAX_SPEED_D 2.f
void DisplaysView::arrow (glm::vec2 movement) void DisplaysView::arrow (glm::vec2 movement)
{ {
static float _duration = 0.f; static uint _time = 0;
static glm::vec2 _from(0.f);
static glm::vec2 _displacement(0.f);
// grab only works on current window if not fullscreen // grab only works on current window if not fullscreen
if (current_window_ > -1 && !Settings::application.windows[current_window_+1].fullscreen) { if (current_window_ > -1 && !Settings::application.windows[current_window_+1].fullscreen) {
// operate in pixel coordinates // first time pressed: initialize and initiate
static glm::vec2 p;
// initiate movement (only once)
if (!current_action_ongoing_) { if (!current_action_ongoing_) {
if (UserInterface::manager().altModifier() || Settings::application.mouse_pointer_lock)
MousePointer::manager().setActiveMode(Pointer::POINTER_GRID);
else
MousePointer::manager().setActiveMode(Pointer::POINTER_DEFAULT);
// initial position // reset
p.x = (windows_[current_window_].root_->translation_.x - windows_[current_window_].root_->scale_.x) / DISPLAYS_UNIT; _time = 0;
p.y = (windows_[current_window_].root_->translation_.y + windows_[current_window_].root_->scale_.y) / - DISPLAYS_UNIT; _displacement = glm::vec2(0.f);
// initiate (terminated at key release) // initiate view action and store status
current_action_ongoing_ = true; initiate();
_duration = 0.f;
// get coordinates of window and set this as start of mouse position
_from = glm::vec2(
Rendering::manager().project(windows_[current_window_].root_->translation_,
scene.root()->transform_));
// Initiate mouse pointer action
MousePointer::manager().active()->initiate(_from);
} }
// add movement vector to position (pixel precision) // if initialized
_duration += dt_; if (current_action_ongoing_) {
const float speed = MIN_SPEED_D + (MAX_SPEED_D - MIN_SPEED_D) * glm::min(1.f,_duration / MAX_DURATION); // move on first press, and then every TIME_STEP milisecond
p += movement * dt_ * speed; //* (dt_ * 0.5f); if (_time < 1 || _time > TIME_STEP) {
_time = 0;
// discretized translation with ALT // move by step size if grid is active
if (UserInterface::manager().altModifier()) { if (MousePointer::manager().activeMode() == Pointer::POINTER_GRID) {
glm::vec2 q; // calculate step size in monitor coordinates (simulate mouse movement)
q.x = ROUND(p.x, 0.05f); // 20 pix precision glm::vec2 step = grid->step() * glm::vec2(gridroot_->scale_);
q.y = ROUND(p.y, 0.05f); step = glm::vec2(Rendering::manager().project(glm::vec3(step.x, -step.y, 0.f),
// convert back to output-frame coordinates scene.root()->transform_));
windows_[current_window_].root_->translation_.x = (q.x * DISPLAYS_UNIT) + windows_[current_window_].root_->scale_.x; step -= glm::vec2(Rendering::manager().project(glm::vec3(0.f),
windows_[current_window_].root_->translation_.y = (q.y * - DISPLAYS_UNIT) - windows_[current_window_].root_->scale_.y; scene.root()->transform_));
} // multiply movement by step size
else movement *= step;
{ }
// convert back to output-frame coordinates
windows_[current_window_].root_->translation_.x = (p.x * DISPLAYS_UNIT) + windows_[current_window_].root_->scale_.x;
windows_[current_window_].root_->translation_.y = (p.y * - DISPLAYS_UNIT) - windows_[current_window_].root_->scale_.y;
}
// increment displacement by movement
_displacement += movement;
// update mouse pointer action
MousePointer::manager().active()->update(_from + _displacement, dt_ / 1000.f);
// simulate mouse grab
grab(nullptr, _from, MousePointer::manager().active()->target(),
std::make_pair(windows_[current_window_].surface_, glm::vec2(0.f) ) );
}
// draw mouse pointer effect
MousePointer::manager().active()->draw();
// increment time counter
_time += static_cast<uint>(dt_);
}
}
else {
// reset
_from = glm::vec2(0.f);
_displacement = glm::vec2(0.f);
terminate(true);
} }
} }
bool WindowPreview::hasNode::operator()(const WindowPreview &elem) const bool WindowPreview::hasNode::operator()(const WindowPreview &elem) const
{ {
if (_n) if (_n)

View File

@@ -9,19 +9,20 @@ struct WindowPreview
class FrameBuffer *renderbuffer_; class FrameBuffer *renderbuffer_;
class ImageFilteringShader *shader_; class ImageFilteringShader *shader_;
class FrameBufferSurface *surface_; class FrameBufferSurface *surface_;
Surface *output_render_; class MeshSurface *output_render_;
Group *root_; Group *root_;
Group *output_group_; Group *output_group_;
Frame *output_frame_; class LineLoop *output_lines_;
Handles *output_handles_; Handles *output_handles_[4];
Switch *overlays_; Switch *overlays_;
Switch *mode_; Switch *mode_;
Handles *handles_; Handles *resize_;
Handles *menu_; Handles *menu_;
Handles *icon_; Handles *icon_;
Surface *title_; Surface *title_;
Symbol *fullscreen_; Symbol *fullscreen_;
std::string monitor_; std::string monitor_;
int need_update_;
WindowPreview() { WindowPreview() {
renderbuffer_ = nullptr; renderbuffer_ = nullptr;
@@ -30,15 +31,19 @@ struct WindowPreview
output_render_ = nullptr; output_render_ = nullptr;
root_ = nullptr; root_ = nullptr;
output_group_ = nullptr; output_group_ = nullptr;
output_handles_ = nullptr; output_handles_[0] = nullptr;
output_handles_[1] = nullptr;
output_handles_[2] = nullptr;
output_handles_[3] = nullptr;
overlays_ = nullptr; overlays_ = nullptr;
mode_ = nullptr; mode_ = nullptr;
handles_ = nullptr; resize_ = nullptr;
menu_ = nullptr; menu_ = nullptr;
icon_ = nullptr; icon_ = nullptr;
title_ = nullptr; title_ = nullptr;
fullscreen_ = nullptr; fullscreen_ = nullptr;
monitor_ = ""; monitor_ = "";
need_update_ = 2;
} }
~WindowPreview(); ~WindowPreview();
@@ -89,8 +94,8 @@ private:
Group *current_output_status_; Group *current_output_status_;
bool show_window_menu_; bool show_window_menu_;
Group *gridroot_;
// bool get_UV_window_render_from_pick(const glm::vec3 &pos, glm::vec2 *uv); void adaptGridToWindow(int w = -1);
}; };

View File

@@ -23,7 +23,7 @@ public:
Surface(Shader *s = new ImageShader); Surface(Shader *s = new ImageShader);
virtual ~Surface(); virtual ~Surface();
void init () override; virtual void init () override;
void draw (glm::mat4 modelview, glm::mat4 projection) override; void draw (glm::mat4 modelview, glm::mat4 projection) override;
void accept (Visitor& v) override; void accept (Visitor& v) override;
@@ -36,7 +36,6 @@ public:
protected: protected:
uint textureindex_; uint textureindex_;
bool mirror_; bool mirror_;
void generate_mesh(size_t w, size_t h);
}; };
class MeshSurface : public Surface { class MeshSurface : public Surface {
@@ -44,7 +43,7 @@ class MeshSurface : public Surface {
public: public:
MeshSurface(Shader *s = new ImageShader); MeshSurface(Shader *s = new ImageShader);
void init () override; virtual void init () override;
protected: protected:
void generate_mesh(size_t w, size_t h); void generate_mesh(size_t w, size_t h);

View File

@@ -70,6 +70,7 @@
#include "UserInterfaceManager.h" #include "UserInterfaceManager.h"
#include "ControlManager.h" #include "ControlManager.h"
#include "ImageFilter.h" #include "ImageFilter.h"
#include "Primitives.h"
#include "RenderingManager.h" #include "RenderingManager.h"
@@ -265,6 +266,10 @@ GLFWmonitor *Rendering::monitorAt(int x, int y)
return mo; return mo;
} }
std::string Rendering::monitorNameAt(int x, int y)
{
return glfwGetMonitorName(monitorAt(x, y));
}
GLFWmonitor *Rendering::monitorNamed(const std::string &name) GLFWmonitor *Rendering::monitorNamed(const std::string &name)
{ {
@@ -696,24 +701,18 @@ bool Rendering::shouldHaveEnoughMemory(glm::vec3 resolution, int flags)
// custom surface with a new VAO // custom surface with a new VAO
class WindowSurface : public Primitive { class WindowSurface : public MeshSurface
public:
WindowSurface(Shader *s = new ImageShader);
};
WindowSurface::WindowSurface(Shader *s) : Primitive(s)
{ {
points_ = std::vector<glm::vec3> { glm::vec3( -1.f, -1.f, 0.f ), glm::vec3( -1.f, 1.f, 0.f ), public:
glm::vec3( 1.f, -1.f, 0.f ), glm::vec3( 1.f, 1.f, 0.f ) }; WindowSurface(Shader *s = new ImageShader)
colors_ = std::vector<glm::vec4> { glm::vec4( 1.f, 1.f, 1.f , 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ), : MeshSurface(s)
glm::vec4( 1.f, 1.f, 1.f, 1.f ), glm::vec4( 1.f, 1.f, 1.f, 1.f ) }; {}
texCoords_ = std::vector<glm::vec2> { glm::vec2( 0.f, 1.f ), glm::vec2( 0.f, 0.f ), void init () override
glm::vec2( 1.f, 1.f ), glm::vec2( 1.f, 0.f ) }; {
indices_ = std::vector<uint> { 0, 1, 2, 3 }; generate_mesh(32, 32);
drawMode_ = GL_TRIANGLE_STRIP; Primitive::init();
} }
};
RenderingWindow::RenderingWindow() : window_(NULL), master_(NULL), RenderingWindow::RenderingWindow() : window_(NULL), master_(NULL),
index_(-1), dpi_scale_(1.f), textureid_(0), fbo_(0), surface_(nullptr), request_change_fullscreen_(false) index_(-1), dpi_scale_(1.f), textureid_(0), fbo_(0), surface_(nullptr), request_change_fullscreen_(false)
@@ -1177,12 +1176,20 @@ bool RenderingWindow::draw(FrameBuffer *fb)
shader_->uniforms_["Green"] = Settings::application.windows[index_].whitebalance.y; shader_->uniforms_["Green"] = Settings::application.windows[index_].whitebalance.y;
shader_->uniforms_["Blue"] = Settings::application.windows[index_].whitebalance.z; shader_->uniforms_["Blue"] = Settings::application.windows[index_].whitebalance.z;
shader_->uniforms_["Temperature"] = Settings::application.windows[index_].whitebalance.w; shader_->uniforms_["Temperature"] = Settings::application.windows[index_].whitebalance.w;
if (Settings::application.windows[index_].custom)
shader_->iNodes = Settings::application.windows[index_].nodes;
else
shader_->iNodes = glm::zero<glm::mat4>();
} }
// Display option: scaled or corrected aspect ratio // Display option: scaled or corrected aspect ratio
if (Settings::application.windows[index_].scaled) { if (Settings::application.windows[index_].custom) {
surface_->scale_ = Settings::application.windows[index_].scale; // surface_->scale_ = Settings::application.windows[index_].scale;
surface_->translation_ = Settings::application.windows[index_].translation; // surface_->translation_ = Settings::application.windows[index_].translation;
surface_->scale_ = glm::vec3(1.f);
surface_->translation_ = glm::vec3(0.f);
} }
else{ else{
// calculate scaling factor of frame buffer inside window // calculate scaling factor of frame buffer inside window
@@ -1196,7 +1203,7 @@ bool RenderingWindow::draw(FrameBuffer *fb)
} }
// Display option: draw calibration pattern // Display option: draw calibration pattern
if ( Settings::application.windows[index_].show_pattern) { if (Settings::application.windows[index_].show_pattern) {
// (re) create pattern at frame buffer resolution // (re) create pattern at frame buffer resolution
if ( pattern_->width() != fb->width() || pattern_->height() != fb->height()) { if ( pattern_->width() != fb->width() || pattern_->height() != fb->height()) {
if (GstToolkit::has_feature("frei0r-src-test-pat-b") ) if (GstToolkit::has_feature("frei0r-src-test-pat-b") )
@@ -1215,14 +1222,13 @@ bool RenderingWindow::draw(FrameBuffer *fb)
textureid_ = fb->texture(); textureid_ = fb->texture();
// actual render of the textured surface // actual render of the textured surface
glBindTexture(GL_TEXTURE_2D, textureid_);
static glm::mat4 projection = glm::ortho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f); static glm::mat4 projection = glm::ortho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f);
surface_->setTextureIndex(textureid_);
surface_->update(0.f); surface_->update(0.f);
surface_->draw(glm::identity<glm::mat4>(), projection); surface_->draw(glm::identity<glm::mat4>(), projection);
// done drawing (unload shader from this glcontext) // done drawing (unload shader from this glcontext)
ShadingProgram::enduse(); ShadingProgram::enduse();
glBindTexture(GL_TEXTURE_2D, 0);
} }
// restore attribs // restore attribs

View File

@@ -163,6 +163,7 @@ public:
inline std::map<std::string, glm::ivec4> monitors() { return monitors_geometry_; } inline std::map<std::string, glm::ivec4> monitors() { return monitors_geometry_; }
// get which monitor contains this point // get which monitor contains this point
GLFWmonitor *monitorAt(int x, int y); GLFWmonitor *monitorAt(int x, int y);
std::string monitorNameAt(int x, int y);
// get which monitor has this name // get which monitor has this name
GLFWmonitor *monitorNamed(const std::string &name); GLFWmonitor *monitorNamed(const std::string &name);

View File

@@ -109,17 +109,14 @@ void Settings::Save(uint64_t runtime)
window->SetAttribute("w", w.w); window->SetAttribute("w", w.w);
window->SetAttribute("h", w.h); window->SetAttribute("h", w.h);
window->SetAttribute("f", w.fullscreen); window->SetAttribute("f", w.fullscreen);
window->SetAttribute("s", w.scaled); window->SetAttribute("s", w.custom);
window->SetAttribute("d", w.decorated); window->SetAttribute("d", w.decorated);
window->SetAttribute("m", w.monitor.c_str()); window->SetAttribute("m", w.monitor.c_str());
XMLElement *tmp = xmlDoc.NewElement("whitebalance"); XMLElement *tmp = xmlDoc.NewElement("whitebalance");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.whitebalance) ); tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.whitebalance) );
window->InsertEndChild( tmp ); window->InsertEndChild( tmp );
tmp = xmlDoc.NewElement("scale"); tmp = xmlDoc.NewElement("nodes");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.scale) ); tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.nodes) );
window->InsertEndChild( tmp );
tmp = xmlDoc.NewElement("translation");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.translation) );
window->InsertEndChild( tmp ); window->InsertEndChild( tmp );
windowsNode->InsertEndChild(window); windowsNode->InsertEndChild(window);
} }
@@ -550,7 +547,7 @@ void Settings::Load()
windowNode->QueryIntAttribute("w", &w.w); windowNode->QueryIntAttribute("w", &w.w);
windowNode->QueryIntAttribute("h", &w.h); windowNode->QueryIntAttribute("h", &w.h);
windowNode->QueryBoolAttribute("f", &w.fullscreen); windowNode->QueryBoolAttribute("f", &w.fullscreen);
windowNode->QueryBoolAttribute("s", &w.scaled); windowNode->QueryBoolAttribute("s", &w.custom);
windowNode->QueryBoolAttribute("d", &w.decorated); windowNode->QueryBoolAttribute("d", &w.decorated);
const char *text = windowNode->Attribute("m"); const char *text = windowNode->Attribute("m");
if (text) if (text)
@@ -562,16 +559,36 @@ void Settings::Load()
w.name = "Output " + std::to_string(i) + " - " APP_NAME; w.name = "Output " + std::to_string(i) + " - " APP_NAME;
else else
w.name = APP_TITLE; w.name = APP_TITLE;
// vec4 values for white balance correction
XMLElement *tmp = windowNode->FirstChildElement("whitebalance"); XMLElement *tmp = windowNode->FirstChildElement("whitebalance");
if (tmp) if (tmp)
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec4"), w.whitebalance); tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec4"), w.whitebalance);
tmp = windowNode->FirstChildElement("scale"); // mat4 values for custom fit distortion
w.nodes = glm::zero<glm::mat4>();
tmp = windowNode->FirstChildElement("nodes");
if (tmp) if (tmp)
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec3"), w.scale); tinyxml2::XMLElementToGLM( tmp->FirstChildElement("mat4"), w.nodes);
tmp = windowNode->FirstChildElement("translation"); else {
if (tmp) // backward compatibility
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec3"), w.translation); glm::vec3 scale, translation;
tmp = windowNode->FirstChildElement("scale");
if (tmp) {
tinyxml2::XMLElementToGLM(tmp->FirstChildElement("vec3"), scale);
tmp = windowNode->FirstChildElement("translation");
if (tmp) {
tinyxml2::XMLElementToGLM(tmp->FirstChildElement("vec3"), translation);
// calculate nodes with scale and translation
w.nodes[0].x = 1.f - ( 1.f * scale.x - translation.x );
w.nodes[0].y = 1.f - ( 1.f * scale.y - translation.y );
w.nodes[1].x = 1.f - ( 1.f * scale.x - translation.x );
w.nodes[1].y = -1.f - (-1.f * scale.y - translation.y );
w.nodes[2].x = -1.f - (-1.f * scale.x - translation.x );
w.nodes[2].y = 1.f - ( 1.f * scale.y - translation.y );
w.nodes[3].x = -1.f - (-1.f * scale.x - translation.x );
w.nodes[3].y = -1.f - (-1.f * scale.y - translation.y );
}
}
}
application.windows[i] = w; application.windows[i] = w;
} }

View File

@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "defines.h" #include "defines.h"
@@ -66,18 +67,17 @@ struct WindowConfig
std::string name; std::string name;
int x,y,w,h; int x,y,w,h;
bool fullscreen; bool fullscreen;
bool scaled; bool custom;
bool decorated; bool decorated;
std::string monitor; std::string monitor;
bool show_pattern; bool show_pattern;
glm::vec4 whitebalance; glm::vec4 whitebalance;
glm::vec3 scale; glm::mat4 nodes;
glm::vec3 translation;
WindowConfig() : name(APP_TITLE), x(15), y(15), w(1280), h(720), WindowConfig() : name(APP_TITLE), x(15), y(15), w(1280), h(720),
fullscreen(false), scaled(false), decorated(true), fullscreen(false), custom(false), decorated(true),
monitor(""), show_pattern(false), whitebalance(glm::vec4(1.f, 1.f, 1.f, 0.5f)), monitor(""), show_pattern(false), whitebalance(glm::vec4(1.f, 1.f, 1.f, 0.5f)),
scale(glm::vec3(1.f)), translation(glm::vec3(0.f)) nodes(glm::zero<glm::mat4>())
{ } { }
}; };

View File

@@ -4166,7 +4166,7 @@ void Navigator::RenderMousePointerSelector(const ImVec2 &size)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImVec2 top = ImGui::GetCursorPos(); ImVec2 top = ImGui::GetCursorPos();
bool enabled = Settings::application.current_view < View::TRANSITION; bool enabled = Settings::application.current_view != View::TRANSITION;
/// ///
/// interactive button of the given size: show menu if clic or mouse over /// interactive button of the given size: show menu if clic or mouse over
/// ///