2010-05-13 20:37:41 +02:00
|
|
|
// Copyright (c) 2005-2010, Rodrigo Braz Monteiro
|
2006-01-16 22:02:54 +01:00
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
|
|
// may be used to endorse or promote products derived from this software
|
|
|
|
// without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
2006-01-16 22:02:54 +01:00
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// $Id$
|
|
|
|
|
|
|
|
/// @file video_display.cpp
|
|
|
|
/// @brief Control displaying a video frame obtained from the video context
|
|
|
|
/// @ingroup video main_ui
|
|
|
|
///
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
// Includes
|
2009-01-04 07:31:48 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-09-10 15:06:40 +02:00
|
|
|
#ifndef AGI_PRE
|
|
|
|
#include <wx/clipbrd.h>
|
|
|
|
#include <wx/dataobj.h>
|
|
|
|
#include <wx/dcclient.h>
|
2007-01-23 21:50:41 +01:00
|
|
|
#include <wx/glcanvas.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#include <wx/menu.h>
|
|
|
|
#endif
|
|
|
|
|
2007-09-12 01:22:26 +02:00
|
|
|
#ifdef __APPLE__
|
2007-04-22 04:24:27 +02:00
|
|
|
#include <OpenGL/GL.h>
|
|
|
|
#include <OpenGL/glu.h>
|
|
|
|
#else
|
2007-01-22 23:57:45 +01:00
|
|
|
#include <GL/gl.h>
|
|
|
|
#include <GL/glu.h>
|
2007-04-22 04:24:27 +02:00
|
|
|
#endif
|
2009-09-10 15:06:40 +02:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "ass_dialogue.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "hotkeys.h"
|
2006-01-16 22:02:54 +01:00
|
|
|
#include "options.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "utils.h"
|
2009-10-05 06:22:28 +02:00
|
|
|
#include "video_out_gl.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "vfr.h"
|
2007-01-11 04:53:20 +01:00
|
|
|
#include "video_box.h"
|
2009-09-10 03:41:34 +02:00
|
|
|
#include "video_context.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "video_display.h"
|
|
|
|
#include "video_provider_manager.h"
|
2009-10-05 06:22:28 +02:00
|
|
|
#include "video_slider.h"
|
2007-07-01 02:19:55 +02:00
|
|
|
#include "visual_tool.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "visual_tool_clip.h"
|
2007-07-01 02:19:55 +02:00
|
|
|
#include "visual_tool_cross.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "visual_tool_drag.h"
|
2007-07-01 04:46:12 +02:00
|
|
|
#include "visual_tool_rotatexy.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "visual_tool_rotatez.h"
|
2007-07-01 05:17:56 +02:00
|
|
|
#include "visual_tool_scale.h"
|
2007-07-05 06:32:46 +02:00
|
|
|
#include "visual_tool_vector_clip.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2009-09-10 03:41:34 +02:00
|
|
|
// Menu item IDs
|
2006-01-16 22:02:54 +01:00
|
|
|
enum {
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Copy mouse coordinates to clipboard
|
2007-04-08 00:03:06 +02:00
|
|
|
VIDEO_MENU_COPY_COORDS = 1230,
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Copy frame to clipboard with subtitles
|
2007-04-08 00:03:06 +02:00
|
|
|
VIDEO_MENU_COPY_TO_CLIPBOARD,
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Copy frame to clipboard without subtitles
|
2007-04-08 00:03:06 +02:00
|
|
|
VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Save frame with subtitles
|
2006-01-16 22:02:54 +01:00
|
|
|
VIDEO_MENU_SAVE_SNAPSHOT,
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Save frame without subtitles
|
2007-04-08 00:03:06 +02:00
|
|
|
VIDEO_MENU_SAVE_SNAPSHOT_RAW
|
2006-01-16 22:02:54 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Event table
|
2007-01-21 07:30:19 +01:00
|
|
|
BEGIN_EVENT_TABLE(VideoDisplay, wxGLCanvas)
|
|
|
|
EVT_MOUSE_EVENTS(VideoDisplay::OnMouseEvent)
|
2007-01-23 21:50:41 +01:00
|
|
|
EVT_KEY_DOWN(VideoDisplay::OnKey)
|
2007-01-21 07:30:19 +01:00
|
|
|
EVT_PAINT(VideoDisplay::OnPaint)
|
2007-01-23 05:42:08 +01:00
|
|
|
EVT_SIZE(VideoDisplay::OnSizeEvent)
|
2007-01-21 07:30:19 +01:00
|
|
|
EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground)
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2007-04-08 00:03:06 +02:00
|
|
|
EVT_MENU(VIDEO_MENU_COPY_COORDS,VideoDisplay::OnCopyCoords)
|
2006-01-16 22:02:54 +01:00
|
|
|
EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard)
|
|
|
|
EVT_MENU(VIDEO_MENU_SAVE_SNAPSHOT,VideoDisplay::OnSaveSnapshot)
|
2007-04-08 00:03:06 +02:00
|
|
|
EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,VideoDisplay::OnCopyToClipboardRaw)
|
|
|
|
EVT_MENU(VIDEO_MENU_SAVE_SNAPSHOT_RAW,VideoDisplay::OnSaveSnapshotRaw)
|
2006-01-16 22:02:54 +01:00
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
2009-09-10 03:41:34 +02:00
|
|
|
/// Attribute list for gl canvases; set the canvases to doublebuffered rgba with an 8 bit stencil buffer
|
2007-07-05 06:32:46 +02:00
|
|
|
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
|
2007-01-22 23:57:45 +01:00
|
|
|
|
2009-10-05 06:22:28 +02:00
|
|
|
VideoDisplay::VideoDisplay(VideoBox *box, VideoSlider *ControlSlider, wxTextCtrl *PositionDisplay, wxTextCtrl *SubsPosition, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
|
|
|
|
: wxGLCanvas (parent, id, attribList, pos, size, style, name)
|
|
|
|
, visualMode(-1)
|
|
|
|
, origSize(size)
|
|
|
|
, currentFrame(-1)
|
|
|
|
, w(8), h(8), dx1(0), dx2(8), dy1(0), dy2(8)
|
2010-05-01 03:45:16 +02:00
|
|
|
, mouse_x(INT_MIN), mouse_y(INT_MIN)
|
2009-10-05 06:22:28 +02:00
|
|
|
, locked(false)
|
|
|
|
, zoomValue(1.0)
|
|
|
|
, ControlSlider(ControlSlider)
|
|
|
|
, SubsPosition(SubsPosition)
|
|
|
|
, PositionDisplay(PositionDisplay)
|
|
|
|
, visual(NULL)
|
2009-10-13 19:28:39 +02:00
|
|
|
, videoOut(new VideoOutGL())
|
2009-10-05 06:22:28 +02:00
|
|
|
, box(box)
|
|
|
|
, freeSize(false)
|
2006-01-16 22:02:54 +01:00
|
|
|
{
|
2007-01-21 07:30:19 +01:00
|
|
|
SetCursor(wxNullCursor);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
VideoDisplay::~VideoDisplay () {
|
2009-10-05 06:22:28 +02:00
|
|
|
if (visual) delete visual;
|
2007-07-01 02:19:55 +02:00
|
|
|
visual = NULL;
|
2007-01-21 07:30:19 +01:00
|
|
|
VideoContext::Get()->RemoveDisplay(this);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2007-04-18 06:51:17 +02:00
|
|
|
void VideoDisplay::ShowCursor(bool show) {
|
|
|
|
if (show) SetCursor(wxNullCursor);
|
|
|
|
else {
|
|
|
|
wxCursor cursor(wxCURSOR_BLANK);
|
|
|
|
SetCursor(cursor);
|
|
|
|
}
|
|
|
|
}
|
2009-10-05 06:22:28 +02:00
|
|
|
void VideoDisplay::SetFrame(int frameNumber) {
|
2009-10-27 15:27:39 +01:00
|
|
|
VideoContext *context = VideoContext::Get();
|
2009-10-05 06:22:28 +02:00
|
|
|
ControlSlider->SetValue(frameNumber);
|
|
|
|
|
|
|
|
// Get time for frame
|
|
|
|
int time = VFR_Output.GetTimeAtFrame(frameNumber, true, true);
|
|
|
|
int h = time / 3600000;
|
|
|
|
int m = time % 3600000 / 60000;
|
|
|
|
int s = time % 60000 / 1000;
|
|
|
|
int ms = time % 1000;
|
|
|
|
|
|
|
|
// Set the text box for frame number and time
|
|
|
|
PositionDisplay->SetValue(wxString::Format(_T("%01i:%02i:%02i.%03i - %i"), h, m, s, ms, frameNumber));
|
2009-10-27 15:27:39 +01:00
|
|
|
if (context->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) {
|
2009-10-05 06:22:28 +02:00
|
|
|
// Set the background color to indicate this is a keyframe
|
|
|
|
PositionDisplay->SetBackgroundColour(Options.AsColour(_T("Grid selection background")));
|
|
|
|
PositionDisplay->SetForegroundColour(Options.AsColour(_T("Grid selection foreground")));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PositionDisplay->SetBackgroundColour(wxNullColour);
|
|
|
|
PositionDisplay->SetForegroundColour(wxNullColour);
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString startSign;
|
|
|
|
wxString endSign;
|
|
|
|
int startOff = 0;
|
|
|
|
int endOff = 0;
|
|
|
|
|
2009-10-27 15:27:39 +01:00
|
|
|
if (AssDialogue *curLine = context->curLine) {
|
2009-10-05 06:22:28 +02:00
|
|
|
startOff = time - curLine->Start.GetMS();
|
|
|
|
endOff = time - curLine->End.GetMS();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Positive signs
|
|
|
|
if (startOff > 0) startSign = _T("+");
|
|
|
|
if (endOff > 0) endSign = _T("+");
|
2009-06-01 17:26:26 +02:00
|
|
|
|
2009-10-05 06:22:28 +02:00
|
|
|
// Set the text box for time relative to active subtitle line
|
|
|
|
SubsPosition->SetValue(wxString::Format(_T("%s%ims; %s%ims"), startSign.c_str(), startOff, endSign.c_str(), endOff));
|
|
|
|
|
2009-10-13 19:28:39 +02:00
|
|
|
if (IsShownOnScreen() && visual) visual->Refresh();
|
2009-10-05 06:22:28 +02:00
|
|
|
|
2009-10-13 19:28:39 +02:00
|
|
|
// Render the new frame
|
2009-10-27 15:27:39 +01:00
|
|
|
if (context->IsLoaded()) {
|
2009-12-01 01:32:43 +01:00
|
|
|
AegiVideoFrame frame;
|
|
|
|
try {
|
|
|
|
frame = context->GetFrame(frameNumber);
|
|
|
|
}
|
|
|
|
catch (const wxChar *err) {
|
|
|
|
wxLogError(
|
|
|
|
_T("Failed seeking video. The video file may be corrupt or incomplete.\n")
|
|
|
|
_T("Error message reported: %s"),
|
|
|
|
err);
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
wxLogError(
|
|
|
|
_T("Failed seeking video. The video file may be corrupt or incomplete.\n")
|
|
|
|
_T("No further error message given."));
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
videoOut->UploadFrameData(frame);
|
|
|
|
}
|
|
|
|
catch (const VideoOutInitException& err) {
|
|
|
|
wxLogError(
|
|
|
|
L"Failed to initialize video display. Closing other running programs and updating your video card drivers may fix this.\n"
|
|
|
|
L"Error message reported: %s",
|
2009-12-13 20:27:45 +01:00
|
|
|
err.GetMessage().c_str());
|
2009-12-01 01:32:43 +01:00
|
|
|
context->Reset();
|
|
|
|
}
|
|
|
|
catch (const VideoOutRenderException& err) {
|
|
|
|
wxLogError(
|
|
|
|
L"Could not upload video frame to graphics card.\n"
|
|
|
|
L"Error message reported: %s",
|
2009-12-13 20:27:45 +01:00
|
|
|
err.GetMessage().c_str());
|
2009-12-01 01:32:43 +01:00
|
|
|
}
|
2009-10-27 15:27:39 +01:00
|
|
|
}
|
|
|
|
Render();
|
2009-10-05 06:22:28 +02:00
|
|
|
|
|
|
|
currentFrame = frameNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDisplay::SetFrameRange(int from, int to) {
|
|
|
|
ControlSlider->SetRange(from, to);
|
|
|
|
}
|
|
|
|
|
2009-10-27 15:27:39 +01:00
|
|
|
void VideoDisplay::Render() try {
|
2007-01-23 05:42:08 +01:00
|
|
|
if (!IsShownOnScreen()) return;
|
2010-01-24 20:05:20 +01:00
|
|
|
wxASSERT(wxIsMainThread());
|
2007-01-21 07:30:19 +01:00
|
|
|
|
|
|
|
VideoContext *context = VideoContext::Get();
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(context);
|
2007-04-02 01:07:29 +02:00
|
|
|
if (!context->IsLoaded()) return;
|
|
|
|
|
|
|
|
// Set GL context
|
2007-01-21 07:30:19 +01:00
|
|
|
SetCurrent(*context->GetGLContext(this));
|
|
|
|
|
|
|
|
// Get sizes
|
2009-10-05 06:22:28 +02:00
|
|
|
int w, h, sw, sh, pw, ph;
|
|
|
|
GetClientSize(&w, &h);
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(w > 0);
|
|
|
|
wxASSERT(h > 0);
|
2009-10-05 06:22:28 +02:00
|
|
|
context->GetScriptSize(sw, sh);
|
2007-01-21 07:30:19 +01:00
|
|
|
pw = context->GetWidth();
|
|
|
|
ph = context->GetHeight();
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(pw > 0);
|
|
|
|
wxASSERT(ph > 0);
|
2007-01-21 07:30:19 +01:00
|
|
|
|
2007-01-23 07:32:16 +01:00
|
|
|
// Freesized transform
|
|
|
|
dx1 = 0;
|
|
|
|
dy1 = 0;
|
|
|
|
dx2 = w;
|
|
|
|
dy2 = h;
|
|
|
|
if (freeSize) {
|
2007-03-30 01:04:26 +02:00
|
|
|
// Set aspect ratio
|
2007-01-23 07:32:16 +01:00
|
|
|
float thisAr = float(w)/float(h);
|
2009-10-05 06:22:28 +02:00
|
|
|
float vidAr = context->GetAspectRatioType() == 0 ? float(pw)/float(ph) : context->GetAspectRatioValue();
|
2007-01-23 07:32:16 +01:00
|
|
|
|
|
|
|
// Window is wider than video, blackbox left/right
|
|
|
|
if (thisAr - vidAr > 0.01f) {
|
2007-04-04 22:42:44 +02:00
|
|
|
int delta = int(w-vidAr*h);
|
2007-01-23 07:32:16 +01:00
|
|
|
dx1 += delta/2;
|
|
|
|
dx2 -= delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Video is wider than window, blackbox top/bottom
|
|
|
|
else if (vidAr - thisAr > 0.01f) {
|
2007-04-04 22:42:44 +02:00
|
|
|
int delta = int(h-w/vidAr);
|
2007-01-23 07:32:16 +01:00
|
|
|
dy1 += delta/2;
|
|
|
|
dy2 -= delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-24 20:05:20 +01:00
|
|
|
videoOut->SetViewport(dx1, dy1, dx2, dy2);
|
2009-10-27 15:27:39 +01:00
|
|
|
videoOut->Render(sw, sh);
|
2009-10-05 06:22:28 +02:00
|
|
|
|
2007-06-28 22:29:56 +02:00
|
|
|
DrawTVEffects();
|
2007-01-02 21:07:52 +01:00
|
|
|
|
2009-10-05 06:22:28 +02:00
|
|
|
if (visualMode == -1) SetVisualMode(0, false);
|
2010-05-01 03:45:10 +02:00
|
|
|
if (visual && (visual->mouseX > INT_MIN || visual->mouseY > INT_MIN || Options.AsBool(L"Always show visual tools"))) {
|
|
|
|
visual->Draw();
|
|
|
|
}
|
2007-01-02 21:07:52 +01:00
|
|
|
|
2007-04-13 02:44:46 +02:00
|
|
|
glFinish();
|
2007-01-21 07:30:19 +01:00
|
|
|
SwapBuffers();
|
2007-01-02 21:07:52 +01:00
|
|
|
}
|
2009-10-05 06:22:28 +02:00
|
|
|
catch (const VideoOutException &err) {
|
2009-12-01 01:32:43 +01:00
|
|
|
wxLogError(
|
|
|
|
_T("An error occurred trying to render the video frame on the screen.\n")
|
2009-10-05 06:22:28 +02:00
|
|
|
_T("Error message reported: %s"),
|
2009-12-13 20:27:45 +01:00
|
|
|
err.GetMessage().c_str());
|
2009-10-05 06:22:28 +02:00
|
|
|
VideoContext::Get()->Reset();
|
|
|
|
}
|
2010-04-30 05:00:15 +02:00
|
|
|
catch (const wchar_t *err) {
|
|
|
|
wxLogError(
|
|
|
|
L"An error occurred trying to render the video frame on the screen.\n"
|
|
|
|
L"Error message reported: %s",
|
|
|
|
err);
|
|
|
|
VideoContext::Get()->Reset();
|
|
|
|
}
|
2009-06-01 17:26:26 +02:00
|
|
|
catch (...) {
|
|
|
|
wxLogError(
|
|
|
|
_T("An error occurred trying to render the video frame to screen.\n")
|
|
|
|
_T("No further error message given."));
|
|
|
|
VideoContext::Get()->Reset();
|
|
|
|
}
|
2007-01-02 21:07:52 +01:00
|
|
|
|
2007-06-28 22:29:56 +02:00
|
|
|
void VideoDisplay::DrawTVEffects() {
|
|
|
|
int sw,sh;
|
|
|
|
VideoContext *context = VideoContext::Get();
|
|
|
|
context->GetScriptSize(sw,sh);
|
2007-06-28 23:35:37 +02:00
|
|
|
bool drawOverscan = Options.AsBool(_T("Show Overscan Mask"));
|
2007-06-28 22:29:56 +02:00
|
|
|
|
|
|
|
if (drawOverscan) {
|
2009-09-10 03:41:34 +02:00
|
|
|
// Get aspect ratio
|
2007-06-29 01:27:37 +02:00
|
|
|
double ar = context->GetAspectRatioValue();
|
|
|
|
|
|
|
|
// Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
|
|
|
|
// 16:9 or wider
|
|
|
|
if (ar > 1.75) {
|
|
|
|
DrawOverscanMask(int(sw * 0.1),int(sh * 0.05),wxColour(30,70,200),0.5);
|
|
|
|
DrawOverscanMask(int(sw * 0.035),int(sh * 0.035),wxColour(30,70,200),0.5);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Less wide than 16:9 (use 4:3 standard)
|
|
|
|
else {
|
|
|
|
DrawOverscanMask(int(sw * 0.067),int(sh * 0.05),wxColour(30,70,200),0.5);
|
|
|
|
DrawOverscanMask(int(sw * 0.033),int(sh * 0.035),wxColour(30,70,200),0.5);
|
|
|
|
}
|
2007-06-28 22:29:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDisplay::DrawOverscanMask(int sizeH,int sizeV,wxColour colour,double alpha) {
|
|
|
|
int sw,sh;
|
|
|
|
VideoContext *context = VideoContext::Get();
|
|
|
|
context->GetScriptSize(sw,sh);
|
2007-06-28 23:35:37 +02:00
|
|
|
int rad1 = int(sh * 0.05);
|
2007-06-28 22:29:56 +02:00
|
|
|
int gapH = sizeH+rad1;
|
|
|
|
int gapV = sizeV+rad1;
|
|
|
|
int rad2 = (int)sqrt(double(gapH*gapH + gapV*gapV))+1;
|
|
|
|
|
|
|
|
// Set up GL wrapper
|
|
|
|
OpenGLWrapper gl;
|
|
|
|
gl.SetFillColour(colour,alpha);
|
|
|
|
gl.SetLineColour(wxColour(0,0,0),0.0,1);
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
// Draw sides
|
2007-06-28 22:29:56 +02:00
|
|
|
gl.DrawRectangle(gapH,0,sw-gapH,sizeV); // Top
|
|
|
|
gl.DrawRectangle(sw-sizeH,gapV,sw,sh-gapV); // Right
|
|
|
|
gl.DrawRectangle(gapH,sh-sizeV,sw-gapH,sh); // Bottom
|
|
|
|
gl.DrawRectangle(0,gapV,sizeH,sh-gapV); // Left
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
// Draw rounded corners
|
2007-06-28 22:29:56 +02:00
|
|
|
gl.DrawRing(gapH,gapV,rad1,rad2,1.0,180.0,270.0); // Top-left
|
|
|
|
gl.DrawRing(sw-gapH,gapV,rad1,rad2,1.0,90.0,180.0); // Top-right
|
|
|
|
gl.DrawRing(sw-gapH,sh-gapV,rad1,rad2,1.0,0.0,90.0); // Bottom-right
|
|
|
|
gl.DrawRing(gapH,sh-gapV,rad1,rad2,1.0,270.0,360.0); // Bottom-left
|
|
|
|
|
|
|
|
// Done
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
|
|
|
|
2007-01-21 07:30:19 +01:00
|
|
|
void VideoDisplay::UpdateSize() {
|
2007-01-23 07:32:16 +01:00
|
|
|
VideoContext *con = VideoContext::Get();
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(con);
|
2007-01-23 07:32:16 +01:00
|
|
|
if (!con->IsLoaded()) return;
|
2007-01-23 21:50:41 +01:00
|
|
|
if (!IsShownOnScreen()) return;
|
2007-01-22 00:16:03 +01:00
|
|
|
|
2008-01-11 06:44:00 +01:00
|
|
|
if (freeSize) {
|
|
|
|
GetClientSize(&w,&h);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (con->GetAspectRatioType() == 0) w = int(con->GetWidth() * zoomValue);
|
|
|
|
else w = int(con->GetHeight() * zoomValue * con->GetAspectRatioValue());
|
|
|
|
h = int(con->GetHeight() * zoomValue);
|
2010-01-31 19:49:37 +01:00
|
|
|
|
|
|
|
// Sizers ignore SetClientSize/SetSize, so only use them to calculate
|
|
|
|
// what size is required after including the borders
|
|
|
|
SetClientSize(w,h);
|
|
|
|
GetSize(&w,&h);
|
|
|
|
wxSize size(w,h);
|
|
|
|
SetMinSize(size);
|
|
|
|
SetMaxSize(size);
|
2009-10-09 04:21:30 +02:00
|
|
|
|
|
|
|
locked = true;
|
|
|
|
box->VideoSizer->Fit(box);
|
|
|
|
box->GetParent()->Layout();
|
2010-01-31 19:49:37 +01:00
|
|
|
|
|
|
|
// The sizer makes us use the full width, which at very low zoom levels
|
|
|
|
// results in stretched video, so after using the sizer to update the
|
|
|
|
// parent window sizes, reset our size to the correct value
|
|
|
|
SetSize(w,h);
|
|
|
|
|
2009-10-09 04:21:30 +02:00
|
|
|
locked = false;
|
2008-01-11 06:44:00 +01:00
|
|
|
}
|
2007-01-21 07:30:19 +01:00
|
|
|
Refresh(false);
|
2006-01-22 13:44:53 +01:00
|
|
|
}
|
2006-01-16 22:02:54 +01:00
|
|
|
|
2007-01-21 07:30:19 +01:00
|
|
|
void VideoDisplay::Reset() {
|
2007-03-30 01:04:26 +02:00
|
|
|
// Only calculate sizes if it's visible
|
|
|
|
if (!IsShownOnScreen()) return;
|
2007-01-21 07:30:19 +01:00
|
|
|
int w = origSize.GetX();
|
|
|
|
int h = origSize.GetY();
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(w > 0);
|
|
|
|
wxASSERT(h > 0);
|
2007-01-21 07:30:19 +01:00
|
|
|
SetClientSize(w,h);
|
|
|
|
int _w,_h;
|
|
|
|
GetSize(&_w,&_h);
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(_w > 0);
|
|
|
|
wxASSERT(_h > 0);
|
2007-01-21 07:30:19 +01:00
|
|
|
SetSizeHints(_w,_h,_w,_h);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnPaint(wxPaintEvent&) {
|
2006-01-16 22:02:54 +01:00
|
|
|
wxPaintDC dc(this);
|
2007-01-21 07:30:19 +01:00
|
|
|
Render();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2007-01-23 05:42:08 +01:00
|
|
|
void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
|
2009-09-10 03:41:34 +02:00
|
|
|
if (freeSize) UpdateSize();
|
2007-01-23 21:50:41 +01:00
|
|
|
event.Skip();
|
2007-01-23 05:42:08 +01:00
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
2007-01-23 21:50:41 +01:00
|
|
|
if (locked) return;
|
|
|
|
|
2008-03-07 00:27:54 +01:00
|
|
|
mouse_x = event.GetX();
|
|
|
|
mouse_y = event.GetY();
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
// Disable when playing
|
2007-01-21 07:30:19 +01:00
|
|
|
if (VideoContext::Get()->IsPlaying()) return;
|
2006-01-16 22:02:54 +01:00
|
|
|
|
|
|
|
if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) {
|
|
|
|
wxMenu menu;
|
|
|
|
menu.Append(VIDEO_MENU_SAVE_SNAPSHOT,_("Save PNG snapshot"));
|
|
|
|
menu.Append(VIDEO_MENU_COPY_TO_CLIPBOARD,_("Copy image to Clipboard"));
|
2007-04-08 00:03:06 +02:00
|
|
|
menu.AppendSeparator();
|
2009-05-15 14:44:36 +02:00
|
|
|
menu.Append(VIDEO_MENU_SAVE_SNAPSHOT_RAW,_("Save PNG snapshot (no subtitles)"));
|
|
|
|
menu.Append(VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,_("Copy image to Clipboard (no subtitles)"));
|
2007-04-08 00:03:06 +02:00
|
|
|
menu.AppendSeparator();
|
2006-01-16 22:02:54 +01:00
|
|
|
menu.Append(VIDEO_MENU_COPY_COORDS,_("Copy coordinates to Clipboard"));
|
2007-04-18 06:51:17 +02:00
|
|
|
|
|
|
|
// Show cursor and popup
|
|
|
|
ShowCursor(true);
|
2006-01-16 22:02:54 +01:00
|
|
|
PopupMenu(&menu);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-04-18 06:51:17 +02:00
|
|
|
// Enforce correct cursor display
|
2007-07-01 02:19:55 +02:00
|
|
|
ShowCursor(visualMode != 0);
|
2007-04-18 06:51:17 +02:00
|
|
|
|
2007-01-09 02:52:30 +01:00
|
|
|
// Click?
|
|
|
|
if (event.ButtonDown(wxMOUSE_BTN_ANY)) {
|
|
|
|
SetFocus();
|
|
|
|
}
|
2010-05-13 20:37:35 +02:00
|
|
|
int wheel = event.GetWheelRotation();
|
|
|
|
if (wheel) {
|
|
|
|
SetZoom (zoomValue + .125 * (wheel / event.GetWheelDelta()));
|
|
|
|
}
|
2007-01-09 02:52:30 +01:00
|
|
|
|
2007-01-08 22:11:06 +01:00
|
|
|
// Send to visual
|
2007-07-01 02:19:55 +02:00
|
|
|
if (visual) visual->OnMouseEvent(event);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2007-01-09 02:52:30 +01:00
|
|
|
void VideoDisplay::OnKey(wxKeyEvent &event) {
|
2009-08-14 00:07:43 +02:00
|
|
|
int key = event.GetKeyCode();
|
|
|
|
#ifdef __APPLE__
|
|
|
|
Hotkeys.SetPressed(key,event.m_metaDown,event.m_altDown,event.m_shiftDown);
|
|
|
|
#else
|
|
|
|
Hotkeys.SetPressed(key,event.m_controlDown,event.m_altDown,event.m_shiftDown);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (Hotkeys.IsPressed(_T("Visual Tool Default"))) SetVisualMode(0);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Drag"))) SetVisualMode(1);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Rotate Z"))) SetVisualMode(2);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Rotate X/Y"))) SetVisualMode(3);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Scale"))) SetVisualMode(4);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Rectangular Clip"))) SetVisualMode(5);
|
|
|
|
else if (Hotkeys.IsPressed(_T("Visual Tool Vector Clip"))) SetVisualMode(6);
|
2007-07-27 06:05:18 +02:00
|
|
|
event.Skip();
|
2007-01-09 02:52:30 +01:00
|
|
|
}
|
|
|
|
|
2006-01-16 22:02:54 +01:00
|
|
|
void VideoDisplay::SetZoom(double value) {
|
2010-05-01 03:07:05 +02:00
|
|
|
using std::max;
|
|
|
|
zoomValue = max(value, .125);
|
2010-05-13 20:37:35 +02:00
|
|
|
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
2007-01-21 07:30:19 +01:00
|
|
|
UpdateSize();
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
2010-05-01 03:07:05 +02:00
|
|
|
void VideoDisplay::SetZoomFromBox() {
|
|
|
|
wxString strValue = zoomBox->GetValue();
|
|
|
|
strValue.EndsWith(L"%", &strValue);
|
|
|
|
double value;
|
|
|
|
if (strValue.ToDouble(&value)) {
|
|
|
|
zoomValue = value / 100.;
|
|
|
|
UpdateSize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
double VideoDisplay::GetZoom() {
|
|
|
|
return zoomValue;
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &) {
|
2006-01-16 22:02:54 +01:00
|
|
|
if (wxTheClipboard->Open()) {
|
2007-01-21 07:30:19 +01:00
|
|
|
wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(-1).GetImage(),24)));
|
2006-01-16 22:02:54 +01:00
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnCopyToClipboardRaw(wxCommandEvent &) {
|
2007-04-08 00:03:06 +02:00
|
|
|
if (wxTheClipboard->Open()) {
|
|
|
|
wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(-1,true).GetImage(),24)));
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnSaveSnapshot(wxCommandEvent &) {
|
2007-04-08 00:03:06 +02:00
|
|
|
VideoContext::Get()->SaveSnapshot(false);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnSaveSnapshotRaw(wxCommandEvent &) {
|
2007-04-08 00:03:06 +02:00
|
|
|
VideoContext::Get()->SaveSnapshot(true);
|
2006-01-16 22:02:54 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:37:46 +02:00
|
|
|
void VideoDisplay::OnCopyCoords(wxCommandEvent &) {
|
2006-01-16 22:02:54 +01:00
|
|
|
if (wxTheClipboard->Open()) {
|
|
|
|
int sw,sh;
|
2007-01-21 07:30:19 +01:00
|
|
|
VideoContext::Get()->GetScriptSize(sw,sh);
|
2008-03-07 00:27:54 +01:00
|
|
|
int vx = (sw * mouse_x + w/2) / w;
|
|
|
|
int vy = (sh * mouse_y + h/2) / h;
|
2006-01-16 22:02:54 +01:00
|
|
|
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%i,%i"),vx,vy)));
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-23 07:32:16 +01:00
|
|
|
void VideoDisplay::ConvertMouseCoords(int &x,int &y) {
|
|
|
|
int w,h;
|
|
|
|
GetClientSize(&w,&h);
|
2007-03-30 01:04:26 +02:00
|
|
|
wxASSERT(dx2 > 0);
|
|
|
|
wxASSERT(dy2 > 0);
|
|
|
|
wxASSERT(w > 0);
|
|
|
|
wxASSERT(h > 0);
|
2007-01-23 07:32:16 +01:00
|
|
|
x = (x-dx1)*w/dx2;
|
|
|
|
y = (y-dy1)*h/dy2;
|
|
|
|
}
|
2007-07-01 02:19:55 +02:00
|
|
|
|
2009-10-05 06:22:28 +02:00
|
|
|
void VideoDisplay::SetVisualMode(int mode, bool render) {
|
2007-07-01 02:19:55 +02:00
|
|
|
// Set visual
|
2007-07-04 06:24:47 +02:00
|
|
|
if (visualMode != mode) {
|
2007-07-07 05:21:52 +02:00
|
|
|
wxToolBar *toolBar = NULL;
|
2007-07-04 06:24:47 +02:00
|
|
|
if (box) {
|
|
|
|
toolBar = box->visualSubToolBar;
|
2007-07-07 05:21:52 +02:00
|
|
|
toolBar->ClearTools();
|
|
|
|
toolBar->Realize();
|
|
|
|
toolBar->Show(false);
|
2009-09-10 03:41:34 +02:00
|
|
|
if (!box->visualToolBar->GetToolState(mode + Video_Mode_Standard)) {
|
|
|
|
box->visualToolBar->ToggleTool(mode + Video_Mode_Standard,true);
|
|
|
|
}
|
2007-07-04 06:24:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Replace mode
|
|
|
|
visualMode = mode;
|
|
|
|
delete visual;
|
|
|
|
switch (mode) {
|
|
|
|
case 0: visual = new VisualToolCross(this); break;
|
2007-07-07 05:21:52 +02:00
|
|
|
case 1: visual = new VisualToolDrag(this,toolBar); break;
|
2007-07-04 06:24:47 +02:00
|
|
|
case 2: visual = new VisualToolRotateZ(this); break;
|
|
|
|
case 3: visual = new VisualToolRotateXY(this); break;
|
|
|
|
case 4: visual = new VisualToolScale(this); break;
|
|
|
|
case 5: visual = new VisualToolClip(this); break;
|
2007-07-07 05:21:52 +02:00
|
|
|
case 6: visual = new VisualToolVectorClip(this,toolBar); break;
|
2007-07-04 06:24:47 +02:00
|
|
|
default: visual = NULL;
|
|
|
|
}
|
|
|
|
|
2009-09-10 03:41:34 +02:00
|
|
|
// Update size as the new typesetting tool may have changed the subtoolbar size
|
2007-07-04 06:24:47 +02:00
|
|
|
UpdateSize();
|
2009-10-13 19:28:39 +02:00
|
|
|
ControlSlider->Refresh(false);
|
2007-07-01 02:19:55 +02:00
|
|
|
}
|
2009-10-05 06:22:28 +02:00
|
|
|
if (render) Render();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoDisplay::OnSubTool(wxCommandEvent &event) {
|
|
|
|
if (visual) visual->OnSubTool(event);
|
2007-07-01 02:19:55 +02:00
|
|
|
}
|