diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index 1bd6f5f..f1a32a3 100644 Binary files a/rsc/images/icons.dds and b/rsc/images/icons.dds differ diff --git a/src/DisplaysView.cpp b/src/DisplaysView.cpp index d513f4a..04ec268 100644 --- a/src/DisplaysView.cpp +++ b/src/DisplaysView.cpp @@ -21,11 +21,14 @@ #include #include + #include #include #include #include #include +//#include +//#include #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(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(), 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 DisplaysView::pick(glm::vec2 P) // prepare empty return value std::pair 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(), 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(), 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(), 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; diff --git a/src/DisplaysView.h b/src/DisplaysView.h index 3178cf4..b44f046 100644 --- a/src/DisplaysView.h +++ b/src/DisplaysView.h @@ -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 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); diff --git a/src/GlmToolkit.cpp b/src/GlmToolkit.cpp index 04e5916..5fab992 100644 --- a/src/GlmToolkit.cpp +++ b/src/GlmToolkit.cpp @@ -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()) diff --git a/src/GlmToolkit.h b/src/GlmToolkit.h index 62241f6..75c8b65 100644 --- a/src/GlmToolkit.h +++ b/src/GlmToolkit.h @@ -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; diff --git a/src/RenderingManager.cpp b/src/RenderingManager.cpp index 29391a5..721776d 100644 --- a/src/RenderingManager.cpp +++ b/src/RenderingManager.cpp @@ -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(), scale), projection); + surface_->update(0.f); + surface_->draw(glm::identity(), projection); // done drawing (unload shader from this glcontext) ShadingProgram::enduse(); diff --git a/src/Settings.cpp b/src/Settings.cpp index 9ef54a9..1511737 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -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); } diff --git a/src/Settings.h b/src/Settings.h index 6192894..1882e64 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -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)) { } };