Implementation of Custom Output area in Window Displays View

Changed the 'Scaled' mode of window draw to allow custom centering and scaling of the output framebuffer in the window. Use DisplaysView to grab handles of the output frame. Save all windows custom output scaling in Settings.
This commit is contained in:
Bruno Herbelin
2023-03-12 00:31:41 +01:00
parent 7870e3cfce
commit 811b270bae
8 changed files with 328 additions and 151 deletions

Binary file not shown.

View File

@@ -21,11 +21,14 @@
#include <sstream>
#include <iomanip>
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/matrix_access.hpp>
#include <glm/gtx/vector_angle.hpp>
//#include <iostream>
//#include <glm/gtx/io.hpp>
#include "ImGuiToolkit.h"
#include "imgui_internal.h"
@@ -64,18 +67,25 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
// create and attach all window manipulation objects
windows_ = std::vector<WindowPreview>(MAX_OUTPUT_WINDOW);
for (auto w = windows_.begin(); w != windows_.end(); ++w){
// root node
w->root_ = new Group;
scene.ws()->attach(w->root_);
w->root_->visible_ = false;
// title bar
w->title_ = new Surface (new Shader);
w->title_->shader()->color = glm::vec4( COLOR_WINDOW, 1.f );
w->title_->scale_ = glm::vec3(1.002f, WINDOW_TITLEBAR_HEIGHT, 1.f);
w->title_->translation_ = glm::vec3(0.f, 1.f + WINDOW_TITLEBAR_HEIGHT, 0.f);
w->root_->attach(w->title_);
// surface background and texture
w->surface_ = new Surface;
w->root_->attach(w->surface_);
w->renderbuffer_ = new FrameBuffer(1024, 1024); // TODO delete on close
w->shader_ = new ImageFilteringShader;
w->shader_->setCode( _whitebalance.code().first );
w->render_ = new Surface(w->shader_);
w->root_->attach(w->render_);
w->surface_ = new FrameBufferSurface(w->renderbuffer_, w->shader_);
w->root_->attach(w->surface_);
w->output_render_ = new Surface;
// icon if disabled
w->icon_ = new Handles(Handles::EYESLASHED);
w->icon_->visible_ = false;
@@ -91,6 +101,15 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
// overlays_ [1] is for active frame
Group *g = new Group;
w->overlays_->attach(g);
// Output frame
w->output_frame_ = new Group;
w->output_frame_->visible_ = false;
frame = new Frame(Frame::SHARP, Frame::THIN, Frame::NONE);
frame->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_frame_->attach(frame);
w->output_handles_ = new Handles(Handles::RESIZE);
w->output_handles_->color = glm::vec4( COLOR_FRAME, 1.f );
w->output_frame_->attach(w->output_handles_);
// Overlay menu icon
w->menu_ = new Handles(Handles::MENU);
w->menu_->color = glm::vec4( COLOR_WINDOW, 1.f );
@@ -99,6 +118,7 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
frame = new Frame(Frame::SHARP, Frame::LARGE, Frame::NONE);
frame->color = glm::vec4( COLOR_WINDOW, 1.f );
g->attach(frame);
g->attach(w->output_frame_);
// Overlay has two modes : window or fullscreen
w->mode_ = new Switch;
g->attach(w->mode_);
@@ -111,12 +131,12 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
w->fullscreen_->scale_ = glm::vec3(2.f, 2.f, 1.f);
w->fullscreen_->color = glm::vec4( COLOR_WINDOW, 1.f );
w->mode_->attach(w->fullscreen_);
// title bar
w->title_ = new Surface (new Shader);
w->title_->shader()->color = glm::vec4( COLOR_WINDOW, 1.f );
w->title_->scale_ = glm::vec3(1.002f, WINDOW_TITLEBAR_HEIGHT, 1.f);
w->title_->translation_ = glm::vec3(0.f, 1.f + WINDOW_TITLEBAR_HEIGHT, 0.f);
w->root_->attach(w->title_);
// // title bar
// w->title_ = new Surface (new Shader);
// w->title_->shader()->color = glm::vec4( COLOR_WINDOW, 1.f );
// w->title_->scale_ = glm::vec3(1.002f, WINDOW_TITLEBAR_HEIGHT, 1.f);
// w->title_->translation_ = glm::vec3(0.f, 1.f + WINDOW_TITLEBAR_HEIGHT, 0.f);
// w->root_->attach(w->title_);
// default to not active & window overlay frame
w->overlays_->setActive(0);
w->mode_->setActive(0);
@@ -125,11 +145,9 @@ DisplaysView::DisplaysView() : View(DISPLAYS)
// initial behavior: no window selected, no menu
show_window_menu_ = false;
current_window_ = -1;
current_window_status_ = new Group;
current_window_status_ = new Group;
current_output_status_ = new Group;
draw_pending_ = false;
// display actions : 0 = move output, 1 paint, 2 erase
display_action_ = 0;
output_ar = 1.f;
}
@@ -141,8 +159,34 @@ void DisplaysView::update(float dt)
if ( Mixer::manager().view() == this ) {
// update rendering of render frame
for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i)
windows_[i].render_->setTextureIndex( Rendering::manager().outputWindow(i).texture() );
for (int i = 0; i < MAX_OUTPUT_WINDOW; ++i) {
windows_[i].output_render_->setTextureIndex( Rendering::manager().outputWindow(i).texture() );
// update visible flag
windows_[i].root_->visible_ = i < Settings::application.num_output_windows;
windows_[i].icon_->visible_ = Settings::application.render.disabled;
// Rendering of output is scaled to content and manipulated by output frame
if (Settings::application.windows[i+1].scaled) {
windows_[i].output_render_->scale_ = windows_[i].output_frame_->scale_;
windows_[i].output_render_->translation_ = windows_[i].output_frame_->translation_;
// show output frame
windows_[i].output_frame_->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_frame_->visible_ = false;
}
}
output_ar = Mixer::manager().session()->frame()->aspectRatio();
}
@@ -178,7 +222,7 @@ void DisplaysView::recenter ()
Surface *surf = new Surface( new Shader);
surf->shader()->color = glm::vec4( 0.1f, 0.1f, 0.1f, 1.f );
m->attach(surf);
// cyan color frame
// Monitor color frame
Frame *frame = new Frame(Frame::SHARP, Frame::THIN, Frame::GLOW);
frame->color = glm::vec4( COLOR_MONITOR, 1.f);
m->attach(frame);
@@ -255,29 +299,17 @@ void DisplaysView::draw()
int i = 0;
for (; i < Settings::application.num_output_windows; ++i) {
// update visible flag
windows_[i].root_->visible_ = true;
windows_[i].icon_->visible_ = Settings::application.render.disabled;
// Render the output into the render buffer (displayed on the FrameBufferSurface surface_)
windows_[i].output_render_->update(0.f);
windows_[i].renderbuffer_->begin();
windows_[i].output_render_->draw(glm::identity<glm::mat4>(), windows_[i].renderbuffer_->projection());
windows_[i].renderbuffer_->end();
if (windows_[i].render_->visible_) {
// rendering of framebuffer in window
if (Settings::application.windows[i+1].scaled) {
windows_[i].render_->scale_ = glm::vec3(1.f, 1.f, 1.f);
}
else {
float out_ar = windows_[i].root_->scale_.x / windows_[i].root_->scale_.y;
if (output_ar < out_ar)
windows_[i].render_->scale_ = glm::vec3(output_ar / out_ar, 1.f, 1.f);
else
windows_[i].render_->scale_ = glm::vec3(1.f, out_ar / output_ar, 1.f);
}
if (windows_[i].shader_) {
windows_[i].shader_->uniforms_["Red"] = Settings::application.windows[i+1].whitebalance.x;
windows_[i].shader_->uniforms_["Green"] = Settings::application.windows[i+1].whitebalance.y;
windows_[i].shader_->uniforms_["Blue"] = Settings::application.windows[i+1].whitebalance.z;
windows_[i].shader_->uniforms_["Temperature"] = Settings::application.windows[i+1].whitebalance.w;
}
}
// ensure the shader of the surface_ is configured
windows_[i].shader_->uniforms_["Red"] = Settings::application.windows[i+1].whitebalance.x;
windows_[i].shader_->uniforms_["Green"] = Settings::application.windows[i+1].whitebalance.y;
windows_[i].shader_->uniforms_["Blue"] = Settings::application.windows[i+1].whitebalance.z;
windows_[i].shader_->uniforms_["Temperature"] = Settings::application.windows[i+1].whitebalance.w;
// update overlay
if ( Settings::application.windows[i+1].fullscreen ) {
@@ -308,7 +340,6 @@ void DisplaysView::draw()
ImGui::End();
}
}
else {
// output overlay for window
@@ -367,6 +398,9 @@ void DisplaysView::draw()
windows_[i].title_->scale_.y = WINDOW_TITLEBAR_HEIGHT / windows_[i].root_->scale_.y;
windows_[i].title_->translation_.y = 1.f + windows_[i].title_->scale_.y;
}
windows_[i].output_frame_->scale_ = Settings::application.windows[i+1].scale;
windows_[i].output_frame_->translation_ = Settings::application.windows[i+1].translation;
}
}
@@ -405,7 +439,9 @@ void DisplaysView::draw()
//
// Disable output
ImGuiToolkit::ButtonToggle(ICON_FA_EYE_SLASH, &Settings::application.render.disabled, MENU_OUTPUTDISABLE);
ImGuiToolkit::ButtonToggle(ICON_FA_EYE_SLASH, &Settings::application.render.disabled);
if (ImGui::IsItemHovered())
ImGuiToolkit::ToolTip(MENU_OUTPUTDISABLE, SHORTCUT_OUTPUTDISABLE);
// Add / Remove windows
ImGui::SameLine();
@@ -438,10 +474,10 @@ void DisplaysView::draw()
// Output options
ImGui::SameLine(0, 2.f * g.Style.FramePadding.x);
ImGuiToolkit::ButtonIconToggle(8,5,9,5, &Settings::application.windows[1+current_window_].scaled, "Window fit");
ImGuiToolkit::ButtonIconToggle(9,5,9,5, &Settings::application.windows[1+current_window_].scaled, "Custom fit");
ImGui::SameLine(0, g.Style.FramePadding.x);
ImGuiToolkit::ButtonIconToggle(10,1,11,1, &Settings::application.windows[1+current_window_].show_pattern, "Test pattern");
ImGuiToolkit::ButtonIconToggle(11,1,11,1, &Settings::application.windows[1+current_window_].show_pattern, "Test pattern");
// White ballance color button
static DialogToolkit::ColorPickerDialog whitebalancedialog;
@@ -523,8 +559,8 @@ void DisplaysView::draw()
}
if (ImGui::BeginPopup("DisplaysOutputContextMenu")) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_WINDOW, 1.f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(COLOR_MENU_HOVERED, 0.5f));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_WINDOW, 1.f));
// FULLSCREEN selection: list of monitors
int index = 1;
@@ -555,25 +591,6 @@ void DisplaysView::draw()
Rendering::manager().outputWindow(current_window_).setDecoration(!_borderless);
}
if (ImGui::MenuItem( ICON_FA_EXPAND_ALT " Reset aspect ratio" , nullptr, false, _windowed )){
// reset aspect ratio
glm::ivec4 rect = windowCoordinates(current_window_);
float ar = Mixer::manager().session()->frame()->aspectRatio();
if ( rect.p / rect.q > ar)
rect.p = ar * rect.q;
else
rect.q = rect.p / ar;
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
if (ImGui::MenuItem( ICON_FA_RULER_COMBINED " Reset to pixel size", nullptr, false, _windowed )){
// reset resolution to 1:1
glm::ivec4 rect = windowCoordinates(current_window_);
rect.p = Mixer::manager().session()->frame()->width();
rect.q = Mixer::manager().session()->frame()->height();
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
if (ImGui::MenuItem( ICON_FA_EXPAND " Fit all Displays", nullptr, false, _windowed )){
Rendering::manager().outputWindow(current_window_).setDecoration(false);
@@ -589,6 +606,25 @@ void DisplaysView::draw()
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
if (ImGui::MenuItem( ICON_FA_EXPAND_ALT " Restore aspect ratio" , nullptr, false, _windowed )){
// reset aspect ratio
glm::ivec4 rect = windowCoordinates(current_window_);
float ar = Mixer::manager().session()->frame()->aspectRatio();
if ( rect.p / rect.q > ar)
rect.p = ar * rect.q;
else
rect.q = rect.p / ar;
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
if (ImGui::MenuItem( ICON_FA_RULER_COMBINED " Rescale to pixel size", nullptr, false, _windowed )){
// reset resolution to 1:1
glm::ivec4 rect = windowCoordinates(current_window_);
rect.p = Mixer::manager().session()->frame()->width();
rect.q = Mixer::manager().session()->frame()->height();
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
ImGui::Separator();
if ( ImGui::MenuItem( ICON_FA_REPLY " Reset") ) {
glm::ivec4 rect (0, 0, 800, 600);
@@ -597,6 +633,8 @@ void DisplaysView::draw()
Rendering::manager().outputWindow(current_window_).setDecoration(true);
Settings::application.windows[1+current_window_].show_pattern = false;
Settings::application.windows[1+current_window_].scaled = 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);
if (Settings::application.windows[current_window_+1].fullscreen)
Rendering::manager().outputWindow(current_window_).exitFullscreen();
@@ -604,6 +642,16 @@ void DisplaysView::draw()
Rendering::manager().outputWindow(current_window_).setCoordinates( rect );
}
if ( Settings::application.windows[current_window_+1].scaled ) {
ImGui::PopStyleColor(1);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(COLOR_FRAME, 1.f));
if ( ImGui::MenuItem( ICON_FA_VECTOR_SQUARE " Reset custom fit") ) {
Settings::application.windows[1+current_window_].scale = glm::vec3(1.f);
Settings::application.windows[1+current_window_].translation = glm::vec3(0.f);
}
}
ImGui::PopStyleColor(2);
ImGui::EndPopup();
}
@@ -616,47 +664,39 @@ std::pair<Node *, glm::vec2> DisplaysView::pick(glm::vec2 P)
// prepare empty return value
std::pair<Node *, glm::vec2> pick = { nullptr, glm::vec2(0.f) };
// mode placement output window
if ( display_action_ == 0 ) {
// get picking from generic View
pick = View::pick(P);
// get picking from generic View
pick = View::pick(P);
// test all windows
current_window_ = -1;
// test all windows
current_window_ = -1;
for (int i = 0; i < Settings::application.num_output_windows; ++i) {
for (int i = 0; i < Settings::application.num_output_windows; ++i) {
// ignore pick on render surface: it's the same as output surface
if (pick.first == windows_[i].render_ ||
pick.first == windows_[i].fullscreen_ ||
pick.first == windows_[i].title_ )
pick.first = windows_[i].surface_;
// ignore pick on title: it's the same as output surface
if (pick.first == windows_[i].title_ ||
pick.first == windows_[i].fullscreen_ )
pick.first = windows_[i].surface_;
// detect clic on menu
if (pick.first == windows_[i].menu_)
show_window_menu_ = true;
// activate / deactivate window if clic on any element of it
if ( (pick.first == windows_[i].surface_) ||
(pick.first == windows_[i].handles_) ||
(pick.first == windows_[i].menu_) ) {
current_window_ = i;
windows_[i].overlays_->setActive(1);
}
else
windows_[i].overlays_->setActive(0);
// detect clic on menu
if (pick.first == windows_[i].menu_)
show_window_menu_ = true;
// activate / deactivate window if clic on any element of it
if ( (pick.first == windows_[i].surface_) ||
(pick.first == windows_[i].handles_) ||
(pick.first == windows_[i].output_handles_) ||
(pick.first == windows_[i].menu_) ) {
current_window_ = i;
windows_[i].overlays_->setActive(1);
}
else {
windows_[i].overlays_->setActive(0);
}
// ignore anything else than selected window
if (current_window_ < 0)
pick.first = nullptr;
}
// mode other
else // if ( display_action_ == 1 )
{
}
// ignore anything else than selected window
if (current_window_ < 0)
pick.first = nullptr;
return pick;
}
@@ -672,36 +712,34 @@ void DisplaysView::select(glm::vec2 A, glm::vec2 B)
glm::vec3 scene_point_A = Rendering::manager().unProject(A);
glm::vec3 scene_point_B = Rendering::manager().unProject(B);
// select area in window placement mode
if ( display_action_ == 0 ) {
// picking visitor traverses the scene
PickingVisitor pv(scene_point_A, scene_point_B, true);
scene.accept(pv);
// picking visitor traverses the scene
PickingVisitor pv(scene_point_A, scene_point_B, true);
scene.accept(pv);
// TODO Multiple window selection?
// TODO Multiple window selection?
if (!pv.empty()) {
if (!pv.empty()) {
// find which window was picked
auto itp = pv.rbegin();
for (; itp != pv.rend(); ++itp){
// search for WindowPreview
auto w = std::find_if(windows_.begin(), windows_.end(), WindowPreview::hasNode(itp->first));
if (w != windows_.end()) {
// cancel previous current
if (current_window_>-1)
windows_[current_window_].overlays_->setActive(0);
// set current
current_window_ = (int) std::distance(windows_.begin(), w);
windows_[current_window_].overlays_->setActive(1);
// find which window was picked
auto itp = pv.rbegin();
for (; itp != pv.rend(); ++itp){
// search for WindowPreview
auto w = std::find_if(windows_.begin(), windows_.end(), WindowPreview::hasNode(itp->first));
if (w != windows_.end()) {
// cancel previous current
if (current_window_>-1) {
windows_[current_window_].overlays_->setActive(0);
windows_[current_window_].output_frame_->visible_ = false;
}
// set current
current_window_ = (int) std::distance(windows_.begin(), w);
windows_[current_window_].overlays_->setActive(1);
windows_[current_window_].output_frame_->visible_ = true;
}
}
}
}
void DisplaysView::initiate()
@@ -709,8 +747,14 @@ void DisplaysView::initiate()
// initiate pending action
if (!current_action_ongoing_ && current_window_ > -1) {
// store status
// store status current window
// & make sure matrix transform of stored status is updated
current_window_status_->copyTransform(windows_[current_window_].root_);
current_window_status_->update(0.f);
// store status current output frame in current window
current_output_status_->copyTransform(windows_[current_window_].output_frame_);
current_output_status_->update(0.f);
// initiated
current_action_ = "";
@@ -735,6 +779,25 @@ void DisplaysView::terminate(bool force)
Rendering::manager().outputWindow(current_window_).setCoordinates( windowCoordinates(current_window_) );
}
// test if output area is inside the Window (with a margin of 10%)
GlmToolkit::AxisAlignedBoundingBox _bb;
_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_frame_->transform_ );
_bb = _bb.scaled(glm::vec3(0.9f));
if ( !_bb.intersect(output_bb) || output_bb.area() < 0.1f ) {
// No intersection of output bounding box with window area : revert to previous
windows_[current_window_].output_frame_->scale_ = Settings::application.windows[current_window_+1].scale;
windows_[current_window_].output_frame_->translation_ = Settings::application.windows[current_window_+1].translation;
}
else {
// Apply output area recentering to actual output window
Settings::application.windows[current_window_+1].scale = windows_[current_window_].output_frame_->scale_;
Settings::application.windows[current_window_+1].translation = windows_[current_window_].output_frame_->translation_;
}
// reset overlay of grab corner
windows_[current_window_].output_handles_->overlayActiveCorner(glm::vec2(0.f));
}
// terminated
@@ -774,8 +837,89 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
glm::vec3 scene_to = Rendering::manager().unProject(to, scene.root()->transform_);
glm::vec3 scene_translation = scene_to - scene_from;
// a window is currently selected
if ( current_window_ > -1 ) {
// Grab handles of the output frame to adjust
if ( pick.first == windows_[current_window_].output_handles_ ) {
// which corner was picked ?
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
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::mat4 root_to_corner_transform = T * glm::inverse(current_output_status_->transform_);
glm::mat4 corner_to_root_transform = glm::inverse(root_to_corner_transform);
// transformation from scene to corner:
glm::mat4 scene_to_corner_transform = root_to_corner_transform * glm::inverse( current_window_status_->transform_);
// compute cursor movement in corner reference frame
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 );
// operation of scaling in corner reference frame
glm::vec3 corner_scaling = glm::vec3(corner_to) / glm::vec3(corner_from);
// proportional SCALING with SHIFT
if (UserInterface::manager().shiftModifier()) {
// calculate proportional scaling factor
float factor = glm::length( glm::vec2( corner_to ) ) / glm::length( glm::vec2( corner_from ) );
// scale node
windows_[current_window_].output_frame_->scale_ = current_output_status_->scale_ * glm::vec3(factor, factor, 1.f);
}
// non-proportional CORNER RESIZE (normal case)
else {
// scale node
windows_[current_window_].output_frame_->scale_ = current_output_status_->scale_ * corner_scaling;
}
// update corner scaling to apply to center coordinates
corner_scaling = windows_[current_window_].output_frame_->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_frame_->translation_ = glm::vec3(center);
// discretized scaling with ALT
if (UserInterface::manager().altModifier()) {
windows_[current_window_].output_frame_->scale_ = glm::round( windows_[current_window_].output_frame_->scale_ * 20.f) * 0.05f;
windows_[current_window_].output_frame_->translation_ = glm::round( windows_[current_window_].output_frame_->translation_ * 20.f) * 0.05f;
}
if (corner.x > 0.f) {
if (corner.y > 0.f)
info << "Top Right";
else
info << "Bottom Right";
}
else {
if (corner.y > 0.f)
info << "Top Left";
else
info << "Bottom Left";
}
// 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_frame_->scale_.x;
// info << " x " << 100.f * windows_[current_window_].output_frame_->scale_.y << " %";
}
// grab window not fullscreen : move or resizes
if (!Settings::application.windows[current_window_+1].fullscreen) {
@@ -863,12 +1007,8 @@ View::Cursor DisplaysView::grab (Source *, glm::vec2 from, glm::vec2 to, std::pa
windows_[current_window_].title_->scale_.y = WINDOW_TITLEBAR_HEIGHT / windows_[current_window_].root_->scale_.y;
windows_[current_window_].title_->translation_.y = 1.f + windows_[current_window_].title_->scale_.y;
// show cursor depending on diagonal (corner picked)
T = glm::rotate(glm::identity<glm::mat4>(), current_window_status_->rotation_.z, glm::vec3(0.f, 0.f, 1.f));
T = glm::scale(T, current_window_status_->scale_);
corner = T * glm::vec4( corner, 0.f, 0.f );
ret.type = corner.x * corner.y > 0.f ? Cursor_ResizeNESW : Cursor_ResizeNWSE;
// show cursor
ret.type = Cursor_ResizeNWSE;
rect = windowCoordinates(current_window_);
info << "Window size " << rect.p << " x " << rect.q << " px";
}
@@ -1053,7 +1193,7 @@ bool WindowPreview::hasNode::operator()(WindowPreview elem) const
{
if (_n)
{
if (_n == elem.render_ ||
if (_n == elem.fullscreen_ ||
_n == elem.surface_ ||
_n == elem.title_)
return true;

View File

@@ -6,11 +6,13 @@
struct WindowPreview
{
Group *root_;
Group *status_;
Surface *surface_;
Surface *render_;
class FrameBuffer *renderbuffer_;
class ImageFilteringShader *shader_;
class FrameBufferSurface *surface_;
Surface *output_render_;
Group *root_;
Group *output_frame_;
Handles *output_handles_;
Switch *overlays_;
Switch *mode_;
Handles *handles_;
@@ -21,12 +23,14 @@ struct WindowPreview
std::string monitor_;
WindowPreview() {
root_ = nullptr;
status_ = nullptr;
renderbuffer_ = nullptr;
shader_ = nullptr;
surface_ = nullptr;
render_ = nullptr;
output_render_ = nullptr;
root_ = nullptr;
output_frame_ = nullptr;
output_handles_ = nullptr;
overlays_ = nullptr;
status_ = nullptr;
mode_ = nullptr;
handles_ = nullptr;
menu_ = nullptr;
@@ -81,10 +85,9 @@ private:
std::vector<WindowPreview> windows_;
int current_window_;
Group *current_window_status_;
Group *current_output_status_;
bool show_window_menu_;
int display_action_;
// bool get_UV_window_render_from_pick(const glm::vec3 &pos, glm::vec2 *uv);

View File

@@ -238,6 +238,14 @@ GlmToolkit::AxisAlignedBoundingBox GlmToolkit::AxisAlignedBoundingBox::transform
return bb;
}
float GlmToolkit::AxisAlignedBoundingBox::area() const
{
if (isNull())
return 0.f;
return (mMax.x - mMin.x) * (mMax.y - mMin.y) ;
}
bool GlmToolkit::operator< (const GlmToolkit::AxisAlignedBoundingBox& A, const GlmToolkit::AxisAlignedBoundingBox& B )
{
if (A.isNull())

View File

@@ -24,6 +24,7 @@ public:
inline glm::vec3 max() const { return mMax; }
glm::vec3 center(bool ignore_z = true) const;
glm::vec3 scale(bool ignore_z = true) const;
float area() 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;

View File

@@ -1133,17 +1133,20 @@ bool RenderingWindow::draw(FrameBuffer *fb)
shader_->uniforms_["Temperature"] = Settings::application.windows[index_].whitebalance.w;
}
// calculate scaling factor of frame buffer inside window
const float windowAspectRatio = aspectRatio();
const float renderingAspectRatio = fb->aspectRatio();
glm::vec3 scale = glm::vec3(1.f, 1.f, 1.f);
// Display option: scaled or corrected aspect ratio
if (!Settings::application.windows[index_].scaled) {
if (Settings::application.windows[index_].scaled) {
surface_->scale_ = Settings::application.windows[index_].scale;
surface_->translation_ = Settings::application.windows[index_].translation;
}
else{
// calculate scaling factor of frame buffer inside window
const float windowAspectRatio = aspectRatio();
const float renderingAspectRatio = fb->aspectRatio();
if (windowAspectRatio < renderingAspectRatio)
scale = glm::vec3(1.f, windowAspectRatio / renderingAspectRatio, 1.f);
surface_->scale_ = glm::vec3(1.f, windowAspectRatio / renderingAspectRatio, 1.f);
else
scale = glm::vec3(renderingAspectRatio / windowAspectRatio, 1.f, 1.f);
surface_->scale_ = glm::vec3(renderingAspectRatio / windowAspectRatio, 1.f, 1.f);
surface_->translation_ = glm::vec3(0.f);
}
// Display option: draw calibration pattern
@@ -1168,7 +1171,8 @@ bool RenderingWindow::draw(FrameBuffer *fb)
// 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);
surface_->draw(glm::scale(glm::identity<glm::mat4>(), scale), projection);
surface_->update(0.f);
surface_->draw(glm::identity<glm::mat4>(), projection);
// done drawing (unload shader from this glcontext)
ShadingProgram::enduse();

View File

@@ -110,8 +110,16 @@ void Settings::Save(uint64_t runtime)
window->SetAttribute("f", w.fullscreen);
window->SetAttribute("s", w.scaled);
window->SetAttribute("d", w.decorated);
window->SetAttribute("m", w.monitor.c_str());
window->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.whitebalance) );
window->SetAttribute("m", w.monitor.c_str());
XMLElement *tmp = xmlDoc.NewElement("whitebalance");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.whitebalance) );
window->InsertEndChild( tmp );
tmp = xmlDoc.NewElement("scale");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.scale) );
window->InsertEndChild( tmp );
tmp = xmlDoc.NewElement("translation");
tmp->InsertEndChild( XMLElementFromGLM(&xmlDoc, w.translation) );
window->InsertEndChild( tmp );
windowsNode->InsertEndChild(window);
}
@@ -515,11 +523,19 @@ void Settings::Load()
int i = 0;
windowNode->QueryIntAttribute("id", &i);
if (i > 0)
w.name = APP_NAME " output " + std::to_string(i);
w.name = "Output " + std::to_string(i) + " - " APP_NAME;
else
w.name = APP_TITLE;
tinyxml2::XMLElementToGLM( windowNode->FirstChildElement("vec4"), w.whitebalance);
XMLElement *tmp = windowNode->FirstChildElement("whitebalance");
if (tmp)
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec4"), w.whitebalance);
tmp = windowNode->FirstChildElement("scale");
if (tmp)
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec3"), w.scale);
tmp = windowNode->FirstChildElement("translation");
if (tmp)
tinyxml2::XMLElementToGLM( tmp->FirstChildElement("vec3"), w.translation);
application.windows[i] = w;
}
@@ -549,11 +565,13 @@ void Settings::Load()
application.views[id].name = viewNode->Attribute("name");
XMLElement* scaleNode = viewNode->FirstChildElement("default_scale");
tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"),
if (scaleNode)
tinyxml2::XMLElementToGLM( scaleNode->FirstChildElement("vec3"),
application.views[id].default_scale);
XMLElement* translationNode = viewNode->FirstChildElement("default_translation");
tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"),
if (translationNode)
tinyxml2::XMLElementToGLM( translationNode->FirstChildElement("vec3"),
application.views[id].default_translation);
}

View File

@@ -65,10 +65,13 @@ struct WindowConfig
std::string monitor;
bool show_pattern;
glm::vec4 whitebalance;
glm::vec3 scale;
glm::vec3 translation;
WindowConfig() : name(APP_TITLE), x(15), y(15), w(1280), h(720),
fullscreen(false), scaled(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))
{ }
};