diff --git a/src/command/video.cpp b/src/command/video.cpp index 40ffb977b..a262c0dcc 100644 --- a/src/command/video.cpp +++ b/src/command/video.cpp @@ -669,7 +669,7 @@ public: void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(1.); + c->videoDisplay->SetWindowZoom(1.); } }; @@ -700,7 +700,7 @@ public: void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(2.); + c->videoDisplay->SetWindowZoom(2.); } }; @@ -718,7 +718,7 @@ public: void operator()(agi::Context *c) override { c->videoController->Stop(); - c->videoDisplay->SetZoom(.5); + c->videoDisplay->SetWindowZoom(.5); } }; @@ -730,7 +730,7 @@ struct video_zoom_in final : public validator_video_attached { STR_HELP("Zoom video in") void operator()(agi::Context *c) override { - c->videoDisplay->SetZoom(c->videoDisplay->GetZoom() + .125); + c->videoDisplay->SetWindowZoom(c->videoDisplay->GetZoom() + .125); } }; @@ -742,7 +742,7 @@ struct video_zoom_out final : public validator_video_attached { STR_HELP("Zoom video out") void operator()(agi::Context *c) override { - c->videoDisplay->SetZoom(c->videoDisplay->GetZoom() - .125); + c->videoDisplay->SetWindowZoom(c->videoDisplay->GetZoom() - .125); } }; } diff --git a/src/frame_main.cpp b/src/frame_main.cpp index df115b27c..b37dafefc 100644 --- a/src/frame_main.cpp +++ b/src/frame_main.cpp @@ -276,9 +276,9 @@ void FrameMain::OnVideoOpen(AsyncVideoProvider *provider) { double zoom = context->videoDisplay->GetZoom(); wxSize windowSize = GetSize(); if (vidx*3*zoom > windowSize.GetX()*4 || vidy*4*zoom > windowSize.GetY()*6) - context->videoDisplay->SetZoom(zoom * .25); + context->videoDisplay->SetWindowZoom(zoom * .25); else if (vidx*3*zoom > windowSize.GetX()*2 || vidy*4*zoom > windowSize.GetY()*3) - context->videoDisplay->SetZoom(zoom * .5); + context->videoDisplay->SetWindowZoom(zoom * .5); SetDisplayMode(1,-1); diff --git a/src/project.cpp b/src/project.cpp index e01dd3749..26776b370 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -220,7 +220,7 @@ void Project::LoadUnloadFiles(ProjectProperties properties) { vc->SetAspectRatio(properties.ar_value); else vc->SetAspectRatio(ar_mode); - context->videoDisplay->SetZoom(properties.video_zoom); + context->videoDisplay->SetWindowZoom(properties.video_zoom); } } diff --git a/src/video_display.cpp b/src/video_display.cpp index 8c682799c..c1b1cfd28 100644 --- a/src/video_display.cpp +++ b/src/video_display.cpp @@ -82,19 +82,20 @@ VideoDisplay::VideoDisplay(wxToolBar *toolbar, bool freeSize, wxComboBox *zoomBo : wxGLCanvas(parent, -1, attribList) , autohideTools(OPT_GET("Tool/Visual/Autohide")) , con(c) -, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125) +, windowZoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125) +, videoZoomValue(1) , toolBar(toolbar) , zoomBox(zoomBox) , freeSize(freeSize) , retina_helper(agi::make_unique(this)) , scale_factor(retina_helper->GetScaleFactor()) , scale_factor_connection(retina_helper->AddScaleFactorListener([=](int new_scale_factor) { - double new_zoom = zoomValue * new_scale_factor / scale_factor; + double new_zoom = windowZoomValue * new_scale_factor / scale_factor; scale_factor = new_scale_factor; - SetZoom(new_zoom); + SetWindowZoom(new_zoom); })) { - zoomBox->SetValue(fmt_wx("%g%%", zoomValue * 100.)); + zoomBox->SetValue(fmt_wx("%g%%", windowZoomValue * 100.)); zoomBox->Bind(wxEVT_COMBOBOX, &VideoDisplay::SetZoomFromBox, this); zoomBox->Bind(wxEVT_TEXT_ENTER, &VideoDisplay::SetZoomFromBoxText, this); @@ -193,11 +194,14 @@ void VideoDisplay::Render() try { PositionVideo(); videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height); - E(glViewport(0, viewport_bottom_end, videoSize.GetWidth(), videoSize.GetHeight())); + + int client_w, client_h; + GetClientSize(&client_w, &client_h); + E(glViewport(0, 0, client_w, client_h)); E(glMatrixMode(GL_PROJECTION)); E(glLoadIdentity()); - E(glOrtho(0.0f, videoSize.GetWidth() / scale_factor, videoSize.GetHeight() / scale_factor, 0.0f, -1000.0f, 1000.0f)); + E(glOrtho(0.0f, client_w / scale_factor, client_h / scale_factor, 0.0f, -1000.0f, 1000.0f)); if (OPT_GET("Video/Overscan Mask")->GetBool()) { double ar = con->videoController->GetAspectRatioValue(); @@ -274,7 +278,7 @@ void VideoDisplay::PositionVideo() { GetClientSize(&client_w, &client_h); viewport_left = 0; - viewport_bottom_end = viewport_bottom = client_h * scale_factor - videoSize.GetHeight(); + viewport_bottom = client_h * scale_factor - videoSize.GetHeight(); viewport_top = 0; viewport_width = videoSize.GetWidth(); viewport_height = videoSize.GetHeight(); @@ -284,27 +288,26 @@ void VideoDisplay::PositionVideo() { int vidH = provider->GetHeight(); AspectRatio arType = con->videoController->GetAspectRatioType(); - double displayAr = double(viewport_width) / viewport_height; + double displayAr = double(client_w) / client_h; double videoAr = arType == AspectRatio::Default ? double(vidW) / vidH : con->videoController->GetAspectRatioValue(); // Window is wider than video, blackbox left/right if (displayAr - videoAr > 0.01) { - int delta = viewport_width - videoAr * viewport_height; + int delta = client_w - videoAr * client_h; viewport_left = delta / 2; - viewport_width -= delta; } // Video is wider than window, blackbox top/bottom else if (videoAr - displayAr > 0.01) { - int delta = viewport_height - viewport_width / videoAr; + int delta = client_h - client_w / videoAr; viewport_top = viewport_bottom = delta / 2; viewport_height -= delta; + viewport_width = viewport_height * videoAr; } } viewport_left += pan_x; viewport_top += pan_y; viewport_bottom -= pan_y; - viewport_bottom_end = std::min(viewport_bottom_end, 0); if (tool) { tool->SetClientSize(client_w * scale_factor, client_h * scale_factor); @@ -319,9 +322,7 @@ void VideoDisplay::UpdateSize() { if (!provider || !IsShownOnScreen()) return; videoSize.Set(provider->GetWidth(), provider->GetHeight()); - videoSize *= zoomValue; - if (con->videoController->GetAspectRatioType() != AspectRatio::Default) - videoSize.SetWidth(videoSize.GetHeight() * con->videoController->GetAspectRatioValue()); + videoSize *= videoZoomValue * windowZoomValue; wxEventBlocker blocker(this); if (freeSize) { @@ -329,13 +330,15 @@ void VideoDisplay::UpdateSize() { while (!top->IsTopLevel()) top = top->GetParent(); wxSize cs = GetClientSize(); + float csAr = (float)cs.GetWidth() / (float)cs.GetHeight(); wxSize oldSize = top->GetSize(); - top->SetSize(top->GetSize() + videoSize / scale_factor - cs); + top->SetSize(top->GetSize() + wxSize(provider->GetHeight() * csAr, provider->GetHeight()) * windowZoomValue / scale_factor - cs); SetClientSize(cs + top->GetSize() - oldSize); } else { - SetMinClientSize(videoSize / scale_factor); - SetMaxClientSize(videoSize / scale_factor); + wxSize newSize = wxSize(provider->GetWidth(), provider->GetHeight()) * windowZoomValue / scale_factor; + SetMinClientSize(newSize); + SetMaxClientSize(newSize); GetGrandParent()->Layout(); } @@ -345,11 +348,16 @@ void VideoDisplay::UpdateSize() { void VideoDisplay::OnSizeEvent(wxSizeEvent &event) { if (freeSize) { - videoSize = GetClientSize() * scale_factor; - PositionVideo(); - zoomValue = double(viewport_height) / con->project->VideoProvider()->GetHeight(); - zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.)); - con->ass->Properties.video_zoom = zoomValue; + /* If the video is not moved */ + if (videoZoomValue == 1.0f && pan_x == 0 && pan_y == 0) + videoSize = GetClientSize() * scale_factor; + /* If the video is moving, we only need to update the size in this case */ + else if (videoSize.GetWidth() == 0 && videoSize.GetHeight() == 0) + videoSize = GetClientSize() * videoZoomValue * scale_factor; + windowZoomValue = double(GetClientSize().GetHeight()) / con->project->VideoProvider()->GetHeight(); + zoomBox->ChangeValue(fmt_wx("%g%%", windowZoomValue * 100.)); + con->ass->Properties.video_zoom = windowZoomValue; + UpdateSize(); } else { PositionVideo(); @@ -387,7 +395,10 @@ void VideoDisplay::OnMouseLeave(wxMouseEvent& event) { void VideoDisplay::OnMouseWheel(wxMouseEvent& event) { if (int wheel = event.GetWheelRotation()) { if (ForwardMouseWheelEvent(this, event)) - SetZoom(zoomValue + .125 * (wheel / event.GetWheelDelta())); + if (event.ControlDown()) + SetWindowZoom(windowZoomValue + .125 * (wheel / event.GetWheelDelta())); + else + SetVideoZoom(videoZoomValue + .125 * (wheel / event.GetWheelDelta())); } } @@ -403,28 +414,42 @@ void VideoDisplay::OnKeyDown(wxKeyEvent &event) { void VideoDisplay::ResetPan() { pan_x = pan_y = 0; + videoZoomValue = 1; + UpdateSize(); PositionVideo(); } -void VideoDisplay::SetZoom(double value) { +void VideoDisplay::SetWindowZoom(double value) { if (value == 0) return; value = std::max(value, .125); - pan_x *= value / zoomValue; - pan_y *= value / zoomValue; - zoomValue = value; - size_t selIndex = zoomValue / .125 - 1; + pan_x *= value / windowZoomValue; + pan_y *= value / windowZoomValue; + windowZoomValue = value; + size_t selIndex = windowZoomValue / .125 - 1; if (selIndex < zoomBox->GetCount()) zoomBox->SetSelection(selIndex); - zoomBox->ChangeValue(fmt_wx("%g%%", zoomValue * 100.)); - con->ass->Properties.video_zoom = zoomValue; + zoomBox->ChangeValue(fmt_wx("%g%%", windowZoomValue * 100.)); + con->ass->Properties.video_zoom = windowZoomValue; + UpdateSize(); +} + +void VideoDisplay::SetVideoZoom(double value) { + if (value == 0) return; + value = std::max(value, .125); + Vector2D mp = tool->FromScriptCoords(GetMousePosition()); + wxSize cs = GetClientSize(); + pan_x *= value / videoZoomValue; + pan_y *= value / videoZoomValue; + + videoZoomValue = value; UpdateSize(); } void VideoDisplay::SetZoomFromBox(wxCommandEvent &) { int sel = zoomBox->GetSelection(); if (sel != wxNOT_FOUND) { - zoomValue = (sel + 1) * .125; - con->ass->Properties.video_zoom = zoomValue; + windowZoomValue = (sel + 1) * .125; + con->ass->Properties.video_zoom = windowZoomValue; UpdateSize(); } } @@ -436,7 +461,7 @@ void VideoDisplay::SetZoomFromBoxText(wxCommandEvent &) { double value; if (strValue.ToDouble(&value)) - SetZoom(value / 100.); + SetWindowZoom(value / 100.); } void VideoDisplay::SetTool(std::unique_ptr new_tool) { diff --git a/src/video_display.h b/src/video_display.h index 502442175..f9856d605 100644 --- a/src/video_display.h +++ b/src/video_display.h @@ -79,15 +79,15 @@ class VideoDisplay final : public wxGLCanvas { int viewport_width = 0; /// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport int viewport_bottom = 0; - /// The REAL bottom of the viewport; used only for glViewport - int viewport_bottom_end = 0; /// Screen pixels between the bottom of the canvas and the top of the video; used for coordinate space conversion int viewport_top = 0; /// The height of the video in screen pixels int viewport_height = 0; - /// The current zoom level, where 1.0 = 100% - double zoomValue; + /// The current window zoom level, where 1.0 = 100% + double windowZoomValue; + /// The current video zoom level, where 1.0 = 100% relative to the display window size + double videoZoomValue; /// The last position of the mouse, when dragging Vector2D pan_last_pos; @@ -167,9 +167,10 @@ public: /// @brief Set the zoom level /// @param value The new zoom level - void SetZoom(double value); + void SetWindowZoom(double value); + void SetVideoZoom(double value); /// @brief Get the current zoom level - double GetZoom() const { return zoomValue; } + double GetZoom() const { return windowZoomValue; } /// @brief Reset the video pan void ResetPan();