forked from mia/Aegisub
Mostly rewrite the visual tools and related classes
Convert all coordinates within the visual tools to Vector2D, which has been significantly extended. Eliminates a lot of issues with accumulated rounding errors and simplifies a lot of code. Modernize the visual tools' interactions with the rest of Aegisub by connecting to signals directly rather than routing everything through the video display and converting the main visual tool mode toolbar to the command system. Extract all references to OpenGL from the visual tools and move them to OpenGLWrapper as a first step towards making it possible to implement an alternative video renderer. In the process, eliminate all uses of OpenGL immediate mode. Fix a bunch of minor issues and general instability. Originally committed to SVN as r5823.
This commit is contained in:
parent
2e5cbf079e
commit
be77dc8307
51 changed files with 2440 additions and 3195 deletions
|
@ -1919,6 +1919,10 @@
|
||||||
RelativePath="..\..\src\command\video.cpp"
|
RelativePath="..\..\src\command\video.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\src\command\vis_tool.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Preferences"
|
Name="Preferences"
|
||||||
|
|
|
@ -288,6 +288,7 @@
|
||||||
<ClCompile Include="$(SrcDir)command\timecode.cpp" />
|
<ClCompile Include="$(SrcDir)command\timecode.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)command\tool.cpp" />
|
<ClCompile Include="$(SrcDir)command\tool.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)command\video.cpp" />
|
<ClCompile Include="$(SrcDir)command\video.cpp" />
|
||||||
|
<ClCompile Include="$(SrcDir)command\vis_tool.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)compat.cpp" />
|
<ClCompile Include="$(SrcDir)compat.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)dialog_about.cpp" />
|
<ClCompile Include="$(SrcDir)dialog_about.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)dialog_attachments.cpp" />
|
<ClCompile Include="$(SrcDir)dialog_attachments.cpp" />
|
||||||
|
|
|
@ -1196,6 +1196,9 @@
|
||||||
<ClCompile Include="$(SrcDir)command\video.cpp">
|
<ClCompile Include="$(SrcDir)command\video.cpp">
|
||||||
<Filter>Commands</Filter>
|
<Filter>Commands</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="$(SrcDir)command\vis_tool.cpp">
|
||||||
|
<Filter>Commands</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="$(SrcDir)pen.cpp">
|
<ClCompile Include="$(SrcDir)pen.cpp">
|
||||||
<Filter>Utilities\UI utilities</Filter>
|
<Filter>Utilities\UI utilities</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -160,6 +160,7 @@
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
#include <wx/notebook.h>
|
#include <wx/notebook.h>
|
||||||
|
#include <wx/numformatter.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
#include <wx/power.h>
|
#include <wx/power.h>
|
||||||
#include <wx/protocol/http.h>
|
#include <wx/protocol/http.h>
|
||||||
|
@ -170,11 +171,11 @@
|
||||||
#include <wx/regex.h>
|
#include <wx/regex.h>
|
||||||
#include <wx/sashwin.h>
|
#include <wx/sashwin.h>
|
||||||
#include <wx/scrolbar.h>
|
#include <wx/scrolbar.h>
|
||||||
#include <wx/srchctrl.h>
|
|
||||||
#include <wx/settings.h>
|
#include <wx/settings.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/slider.h>
|
#include <wx/slider.h>
|
||||||
#include <wx/spinctrl.h>
|
#include <wx/spinctrl.h>
|
||||||
|
#include <wx/srchctrl.h>
|
||||||
#include <wx/stackwalk.h>
|
#include <wx/stackwalk.h>
|
||||||
#include <wx/statbmp.h>
|
#include <wx/statbmp.h>
|
||||||
#include <wx/statbox.h>
|
#include <wx/statbox.h>
|
||||||
|
|
|
@ -121,6 +121,8 @@ protected:
|
||||||
void AdjustScrollbar();
|
void AdjustScrollbar();
|
||||||
void SetColumnWidths();
|
void SetColumnWidths();
|
||||||
|
|
||||||
|
bool IsDisplayed(const AssDialogue *line) const;
|
||||||
|
|
||||||
// Re-implement functions from BaseSelectionController to add batching
|
// Re-implement functions from BaseSelectionController to add batching
|
||||||
void AnnounceActiveLineChanged(AssDialogue *new_line);
|
void AnnounceActiveLineChanged(AssDialogue *new_line);
|
||||||
void AnnounceSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
void AnnounceSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
||||||
|
@ -139,7 +141,6 @@ public:
|
||||||
void EndBatch();
|
void EndBatch();
|
||||||
void SetByFrame(bool state);
|
void SetByFrame(bool state);
|
||||||
|
|
||||||
bool IsDisplayed(const AssDialogue *line) const;
|
|
||||||
void SelectRow(int row, bool addToSelected = false, bool select=true);
|
void SelectRow(int row, bool addToSelected = false, bool select=true);
|
||||||
int GetFirstSelRow() const;
|
int GetFirstSelRow() const;
|
||||||
wxArrayInt GetSelection() const;
|
wxArrayInt GetSelection() const;
|
||||||
|
|
|
@ -21,7 +21,8 @@ SRC = \
|
||||||
time.cpp \
|
time.cpp \
|
||||||
timecode.cpp \
|
timecode.cpp \
|
||||||
tool.cpp \
|
tool.cpp \
|
||||||
video.cpp
|
video.cpp \
|
||||||
|
vis_tool.cpp
|
||||||
|
|
||||||
SRC += \
|
SRC += \
|
||||||
icon.cpp \
|
icon.cpp \
|
||||||
|
|
|
@ -88,6 +88,7 @@ namespace cmd {
|
||||||
void init_timecode();
|
void init_timecode();
|
||||||
void init_tool();
|
void init_tool();
|
||||||
void init_video();
|
void init_video();
|
||||||
|
void init_visual_tools();
|
||||||
|
|
||||||
void init_builtin_commands() {
|
void init_builtin_commands() {
|
||||||
LOG_D("command/init") << "Populating command map";
|
LOG_D("command/init") << "Populating command map";
|
||||||
|
@ -104,6 +105,7 @@ namespace cmd {
|
||||||
init_timecode();
|
init_timecode();
|
||||||
init_tool();
|
init_tool();
|
||||||
init_video();
|
init_video();
|
||||||
|
init_visual_tools();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
|
|
@ -198,6 +198,13 @@ INSERT_ICON("video/opt/autoscroll", toggle_video_autoscroll)
|
||||||
INSERT_ICON("video/play", button_play)
|
INSERT_ICON("video/play", button_play)
|
||||||
INSERT_ICON("video/play/line", button_playline)
|
INSERT_ICON("video/play/line", button_playline)
|
||||||
INSERT_ICON("video/stop", button_pause)
|
INSERT_ICON("video/stop", button_pause)
|
||||||
|
INSERT_ICON("video/tool/clip", visual_clip)
|
||||||
|
INSERT_ICON("video/tool/cross", visual_standard)
|
||||||
|
INSERT_ICON("video/tool/drag", visual_move)
|
||||||
|
INSERT_ICON("video/tool/rotate/xy", visual_rotatexy)
|
||||||
|
INSERT_ICON("video/tool/rotate/z", visual_rotatez)
|
||||||
|
INSERT_ICON("video/tool/scale", visual_scale)
|
||||||
|
INSERT_ICON("video/tool/vector_clip", visual_vector_clip)
|
||||||
INSERT_ICON("video/zoom/in", zoom_in_button)
|
INSERT_ICON("video/zoom/in", zoom_in_button)
|
||||||
INSERT_ICON("video/zoom/out", zoom_out_button)
|
INSERT_ICON("video/zoom/out", zoom_out_button)
|
||||||
|
|
||||||
|
|
|
@ -238,10 +238,7 @@ struct video_copy_coordinates : public validator_video_loaded {
|
||||||
|
|
||||||
void operator()(agi::Context *c) {
|
void operator()(agi::Context *c) {
|
||||||
if (wxTheClipboard->Open()) {
|
if (wxTheClipboard->Open()) {
|
||||||
int x, y;
|
wxTheClipboard->SetData(new wxTextDataObject(c->videoBox->videoDisplay->GetMousePosition().Str()));
|
||||||
c->videoBox->videoDisplay->GetMousePosition(&x, &y);
|
|
||||||
c->videoBox->videoDisplay->ToScriptCoords(&x, &y);
|
|
||||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%d,%d", x, y)));
|
|
||||||
wxTheClipboard->Close();
|
wxTheClipboard->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
142
aegisub/src/command/vis_tool.cpp
Normal file
142
aegisub/src/command/vis_tool.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
//
|
||||||
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
/// @file vis_tool.cpp
|
||||||
|
/// @brief Visual typesetting tools commands
|
||||||
|
/// @ingroup command visual_ui
|
||||||
|
///
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "../include/aegisub/context.h"
|
||||||
|
#include "../video_box.h"
|
||||||
|
#include "../video_context.h"
|
||||||
|
#include "../video_display.h"
|
||||||
|
#include "../visual_tool_clip.h"
|
||||||
|
#include "../visual_tool_cross.h"
|
||||||
|
#include "../visual_tool_drag.h"
|
||||||
|
#include "../visual_tool_rotatexy.h"
|
||||||
|
#include "../visual_tool_rotatez.h"
|
||||||
|
#include "../visual_tool_scale.h"
|
||||||
|
#include "../visual_tool_vector_clip.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using cmd::Command;
|
||||||
|
/// @defgroup cmd-visual Visual typesetting tools commands
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
struct validator_video_loaded : public Command {
|
||||||
|
CMD_TYPE(COMMAND_VALIDATE)
|
||||||
|
bool Validate(const agi::Context *c) {
|
||||||
|
return c->videoController->IsLoaded();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_cross : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/cross")
|
||||||
|
STR_MENU("Standard")
|
||||||
|
STR_DISP("Standard")
|
||||||
|
STR_HELP("Standard mode, double click sets position.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolCross(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_drag : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/drag")
|
||||||
|
STR_MENU("Drag")
|
||||||
|
STR_DISP("Drag")
|
||||||
|
STR_HELP("Drag subtitles.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolDrag(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_rotate_z : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/rotate/z")
|
||||||
|
STR_MENU("Rotate Z")
|
||||||
|
STR_DISP("Rotate Z")
|
||||||
|
STR_HELP("Rotate subtitles on their Z axis.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolRotateZ(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_rotate_xy : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/rotate/xy")
|
||||||
|
STR_MENU("Rotate XY")
|
||||||
|
STR_DISP("Rotate XY")
|
||||||
|
STR_HELP("Rotate subtitles on their X and Y axes.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolRotateXY(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_scale : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/scale")
|
||||||
|
STR_MENU("Scale")
|
||||||
|
STR_DISP("Scale")
|
||||||
|
STR_HELP("Scale subtitles on X and Y axes.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolScale(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_clip : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/clip")
|
||||||
|
STR_MENU("Clip")
|
||||||
|
STR_DISP("Clip")
|
||||||
|
STR_HELP("Clip subtitles to a rectangle.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolClip(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct visual_mode_vector_clip : public validator_video_loaded {
|
||||||
|
CMD_NAME("video/tool/vector_clip")
|
||||||
|
STR_MENU("Vector Clip")
|
||||||
|
STR_DISP("Vector Clip")
|
||||||
|
STR_HELP("Clip subtitles to a vectorial arean.")
|
||||||
|
|
||||||
|
void operator()(agi::Context *c) {
|
||||||
|
c->videoBox->videoDisplay->SetTool(new VisualToolVectorClip(c->videoBox->videoDisplay, c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
namespace cmd {
|
||||||
|
void init_visual_tools() {
|
||||||
|
reg(new visual_mode_cross);
|
||||||
|
reg(new visual_mode_drag);
|
||||||
|
reg(new visual_mode_rotate_z);
|
||||||
|
reg(new visual_mode_rotate_xy);
|
||||||
|
reg(new visual_mode_scale);
|
||||||
|
reg(new visual_mode_clip);
|
||||||
|
reg(new visual_mode_vector_clip);
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,6 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "validators.h"
|
#include "validators.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
|
||||||
#include "video_provider_manager.h"
|
#include "video_provider_manager.h"
|
||||||
|
|
||||||
DialogProperties::DialogProperties(agi::Context *c)
|
DialogProperties::DialogProperties(agi::Context *c)
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
#include "subs_edit_ctrl.h"
|
#include "subs_edit_ctrl.h"
|
||||||
#include "subs_grid.h"
|
#include "subs_grid.h"
|
||||||
#include "video_display.h"
|
|
||||||
|
|
||||||
// IDs
|
// IDs
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -55,7 +55,6 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "validators.h"
|
#include "validators.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
|
||||||
|
|
||||||
/// Window IDs
|
/// Window IDs
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -342,20 +342,30 @@ void OpenGLTextTexture::Insert(OpenGLTextGlyph &glyph) {
|
||||||
|
|
||||||
/// Draw a glyph at (x,y)
|
/// Draw a glyph at (x,y)
|
||||||
void OpenGLTextGlyph::Draw(int x,int y) const {
|
void OpenGLTextGlyph::Draw(int x,int y) const {
|
||||||
// Store matrix and translate
|
|
||||||
glPushMatrix();
|
|
||||||
glTranslatef((float)x,(float)y,0.0f);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
float tex_coords[] = {
|
||||||
glTexCoord2f(x1,y1); glVertex2f(0,0); // Top-left
|
x1, y1,
|
||||||
glTexCoord2f(x1,y2); glVertex2f(0,h); // Bottom-left
|
x1, y2,
|
||||||
glTexCoord2f(x2,y2); glVertex2f(w,h); // Bottom-right
|
x2, y2,
|
||||||
glTexCoord2f(x2,y1); glVertex2f(w,0); // Top-right
|
x2, y1
|
||||||
glEnd();
|
};
|
||||||
|
|
||||||
glPopMatrix();
|
float vert_coords[] = {
|
||||||
|
x, y,
|
||||||
|
x, y + h,
|
||||||
|
x + w, y + h,
|
||||||
|
x + w, y
|
||||||
|
};
|
||||||
|
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, vert_coords);
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, 0, tex_coords);
|
||||||
|
glDrawArrays(GL_QUADS, 0, 4);
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -42,303 +29,417 @@
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
#include <OpenGL/glu.h>
|
||||||
#include <OpenGL/glext.h>
|
#include <OpenGL/glext.h>
|
||||||
#else
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
#include "gl/glext.h"
|
#include "gl/glext.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const float deg2rad = 3.1415926536f / 180.f;
|
||||||
|
static const float rad2deg = 180.f / 3.1415926536f;
|
||||||
|
static const float pi = 3.1415926535897932384626433832795f;
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#define glGetProc(a) wglGetProcAddress(a)
|
||||||
|
#elif !defined(__APPLE__)
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
// Not required on OS X.
|
||||||
|
#define APIENTRY
|
||||||
|
#define GL_EXT(type, name)
|
||||||
|
#else
|
||||||
|
#define GL_EXT(type, name) \
|
||||||
|
static type name = reinterpret_cast<type>(glGetProc(#name)); \
|
||||||
|
if (!name) { \
|
||||||
|
name = reinterpret_cast<type>(& name ## Fallback); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class VertexArray {
|
||||||
|
std::vector<float> data;
|
||||||
|
size_t dim;
|
||||||
|
public:
|
||||||
|
VertexArray(size_t dims, size_t elems) {
|
||||||
|
SetSize(dims, elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSize(size_t dims, size_t elems) {
|
||||||
|
dim = dims;
|
||||||
|
data.resize(elems * dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(size_t i, float x, float y) {
|
||||||
|
data[i * dim] = x;
|
||||||
|
data[i * dim + 1] = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(size_t i, float x, float y, float z) {
|
||||||
|
data[i * dim] = x;
|
||||||
|
data[i * dim + 1] = y;
|
||||||
|
data[i * dim + 2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(size_t i, Vector2D p) {
|
||||||
|
data[i * dim] = p.X();
|
||||||
|
data[i * dim + 1] = p.Y();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw(GLenum mode, bool clear = true) {
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(dim, GL_FLOAT, 0, &data[0]);
|
||||||
|
glDrawArrays(mode, 0, data.size() / dim);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
if (clear)
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Constructor
|
|
||||||
///
|
|
||||||
OpenGLWrapper::OpenGLWrapper() {
|
OpenGLWrapper::OpenGLWrapper() {
|
||||||
r1 = g1 = b1 = a1 = 1.0f;
|
line_r = line_g = line_b = line_a = 1.f;
|
||||||
r2 = g2 = b2 = a2 = 1.0f;
|
fill_r = fill_g = fill_b = fill_a = 1.f;
|
||||||
lw = 1;
|
line_width = 1;
|
||||||
|
transform_pushed = false;
|
||||||
|
smooth = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawLine(Vector2D p1, Vector2D p2) const {
|
||||||
|
|
||||||
/// @brief Draw line
|
|
||||||
/// @param x1
|
|
||||||
/// @param y1
|
|
||||||
/// @param x2
|
|
||||||
/// @param y2
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) const {
|
|
||||||
SetModeLine();
|
SetModeLine();
|
||||||
glBegin(GL_LINES);
|
VertexArray buf(2, 2);
|
||||||
glVertex2f(x1,y1);
|
buf.Set(0, p1);
|
||||||
glVertex2f(x2,y2);
|
buf.Set(1, p2);
|
||||||
glEnd();
|
buf.Draw(GL_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Vector2D interp(Vector2D p1, Vector2D p2, float t) {
|
||||||
|
return t * p1 + (1 - t) * p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawDashedLine(Vector2D p1, Vector2D p2, float step) const {
|
||||||
/// @brief Draw line
|
float dist = (p2 - p1).Len();
|
||||||
/// @param x1
|
step /= dist;
|
||||||
/// @param y1
|
dist -= step;
|
||||||
/// @param x2
|
for (float t = 0; t < 1.f; t += 2 * step) {
|
||||||
/// @param y2
|
DrawLine(interp(p1, p2, t), interp(p1, p2, t + step));
|
||||||
/// @param step
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawDashedLine(float x1,float y1,float x2,float y2,float step) const {
|
|
||||||
float dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
|
|
||||||
int steps = (int)((dist-20)/step);
|
|
||||||
double stepx = double(x2-x1)/steps;
|
|
||||||
double stepy = double(y2-y1)/steps;
|
|
||||||
for (int i=0;i<steps;i++) {
|
|
||||||
if (i % 2 == 0) DrawLine(x1+int(i*stepx),y1+int(i*stepy),x1+int((i+1)*stepx),y1+int((i+1)*stepy));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawEllipse(Vector2D center, Vector2D radius) const {
|
||||||
|
DrawRing(center, radius.Y(), radius.Y(), radius.X() / radius.Y());
|
||||||
/// @brief Draw circle
|
|
||||||
/// @param x
|
|
||||||
/// @param y
|
|
||||||
/// @param radiusX
|
|
||||||
/// @param radiusY
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawEllipse(float x,float y,float radiusX,float radiusY) const {
|
|
||||||
DrawRing(x,y,radiusY,radiusY,radiusX/radiusY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawRectangle(Vector2D p1, Vector2D p2) const {
|
||||||
|
VertexArray buf(2, 4);
|
||||||
|
buf.Set(0, p1);
|
||||||
|
buf.Set(1, Vector2D(p2, p1));
|
||||||
|
buf.Set(2, p2);
|
||||||
|
buf.Set(3, Vector2D(p1, p2));
|
||||||
|
|
||||||
|
|
||||||
/// @brief Draw rectangle
|
|
||||||
/// @param x1
|
|
||||||
/// @param y1
|
|
||||||
/// @param x2
|
|
||||||
/// @param y2
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawRectangle(float x1,float y1,float x2,float y2) const {
|
|
||||||
// Fill
|
// Fill
|
||||||
if (a2 != 0.0) {
|
if (fill_a != 0.0) {
|
||||||
SetModeFill();
|
SetModeFill();
|
||||||
glBegin(GL_QUADS);
|
buf.Draw(GL_QUADS, false);
|
||||||
glVertex2f(x1,y1);
|
|
||||||
glVertex2f(x2,y1);
|
|
||||||
glVertex2f(x2,y2);
|
|
||||||
glVertex2f(x1,y2);
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outline
|
// Outline
|
||||||
if (a1 != 0.0) {
|
if (line_a != 0.0) {
|
||||||
SetModeLine();
|
SetModeLine();
|
||||||
glBegin(GL_LINE_LOOP);
|
buf.Draw(GL_LINE_LOOP);
|
||||||
glVertex2f(x1,y1);
|
|
||||||
glVertex2f(x2,y1);
|
|
||||||
glVertex2f(x2,y2);
|
|
||||||
glVertex2f(x1,y2);
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawTriangle(Vector2D p1, Vector2D p2, Vector2D p3) const {
|
||||||
|
VertexArray buf(2, 3);
|
||||||
|
buf.Set(0, p1);
|
||||||
|
buf.Set(1, p2);
|
||||||
|
buf.Set(2, p3);
|
||||||
|
|
||||||
|
|
||||||
/// @brief Draw triangle
|
|
||||||
/// @param x1
|
|
||||||
/// @param y1
|
|
||||||
/// @param x2
|
|
||||||
/// @param y2
|
|
||||||
/// @param x3
|
|
||||||
/// @param y3
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawTriangle(float x1,float y1,float x2,float y2,float x3,float y3) const {
|
|
||||||
// Fill
|
// Fill
|
||||||
if (a2 != 0.0) {
|
if (fill_a != 0.0) {
|
||||||
SetModeFill();
|
SetModeFill();
|
||||||
glBegin(GL_TRIANGLES);
|
buf.Draw(GL_TRIANGLES, false);
|
||||||
glVertex2f(x1,y1);
|
|
||||||
glVertex2f(x2,y2);
|
|
||||||
glVertex2f(x3,y3);
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outline
|
// Outline
|
||||||
if (a1 != 0.0) {
|
if (line_a != 0.0) {
|
||||||
SetModeLine();
|
SetModeLine();
|
||||||
glBegin(GL_LINE_LOOP);
|
buf.Draw(GL_LINE_LOOP);
|
||||||
glVertex2f(x1,y1);
|
|
||||||
glVertex2f(x2,y2);
|
|
||||||
glVertex2f(x3,y3);
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawRing(Vector2D center, float r1, float r2, float ar, float arc_start, float arc_end) const {
|
||||||
|
if (r2 > r1)
|
||||||
/// @brief Draw ring (annulus)
|
std::swap(r1, r2);
|
||||||
/// @param x
|
|
||||||
/// @param y
|
|
||||||
/// @param r1
|
|
||||||
/// @param r2
|
|
||||||
/// @param ar
|
|
||||||
/// @param arcStart
|
|
||||||
/// @param arcEnd
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::DrawRing(float x,float y,float r1,float r2,float ar,float arcStart,float arcEnd) const {
|
|
||||||
// Make r1 bigger
|
|
||||||
if (r2 > r1) {
|
|
||||||
float temp = r1;
|
|
||||||
r1 = r2;
|
|
||||||
r2 = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Arc range
|
// Arc range
|
||||||
bool hasEnds = arcStart != arcEnd;
|
bool needs_end_caps = arc_start != arc_end;
|
||||||
float pi = 3.1415926535897932384626433832795f;
|
|
||||||
arcEnd *= pi / 180.f;
|
arc_end *= deg2rad;
|
||||||
arcStart *= pi / 180.f;
|
arc_start *= deg2rad;
|
||||||
if (arcEnd <= arcStart) arcEnd += 2.0f*pi;
|
if (arc_end <= arc_start)
|
||||||
float range = arcEnd - arcStart;
|
arc_end += 2.f * pi;
|
||||||
|
float range = arc_end - arc_start;
|
||||||
|
|
||||||
// Math
|
// Math
|
||||||
int steps = int((r1 + r1*ar) * range / (2.0f*pi))*4;
|
int steps = std::max<int>(((r1 + r1 * ar) * range / (2.f * pi)) * 4, 12);
|
||||||
if (steps < 12) steps = 12;
|
float step = range / steps;
|
||||||
//float end = arcEnd;
|
float cur_angle = arc_start;
|
||||||
float step = range/steps;
|
|
||||||
float curAngle = arcStart;
|
|
||||||
|
|
||||||
// Fill
|
VertexArray buf(2, steps);
|
||||||
if (a2 != 0.0) {
|
|
||||||
|
Vector2D scale_inner = Vector2D(ar, 1) * r1;
|
||||||
|
Vector2D scale_outer = Vector2D(ar, 1) * r2;
|
||||||
|
|
||||||
|
if (fill_a != 0.0) {
|
||||||
SetModeFill();
|
SetModeFill();
|
||||||
|
|
||||||
// Annulus
|
// Annulus
|
||||||
if (r1 != r2) {
|
if (r1 != r2) {
|
||||||
glBegin(GL_QUADS);
|
buf.SetSize(2, (steps + 1) * 2);
|
||||||
for (int i=0;i<steps;i++) {
|
for (int i = 0; i <= steps; i++) {
|
||||||
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
|
Vector2D offset = Vector2D::FromAngle(cur_angle);
|
||||||
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
|
buf.Set(i * 2 + 0, center + offset * scale_inner);
|
||||||
curAngle += step;
|
buf.Set(i * 2 + 1, center + offset * scale_outer);
|
||||||
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
|
cur_angle += step;
|
||||||
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
|
|
||||||
}
|
}
|
||||||
glEnd();
|
buf.Draw(GL_QUAD_STRIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circle
|
// Circle
|
||||||
else {
|
else {
|
||||||
glBegin(GL_POLYGON);
|
buf.SetSize(2, steps);
|
||||||
for (int i=0;i<steps;i++) {
|
for (int i = 0; i < steps; i++) {
|
||||||
glVertex2f(x+sin(curAngle)*r1,y+cos(curAngle)*r1);
|
buf.Set(i, center + Vector2D::FromAngle(cur_angle) * scale_inner);
|
||||||
curAngle += step;
|
cur_angle += step;
|
||||||
}
|
}
|
||||||
glEnd();
|
buf.Draw(GL_POLYGON);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset angle
|
cur_angle = arc_start;
|
||||||
curAngle = arcStart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outlines
|
if (line_a == 0.0) return;
|
||||||
if (a1 != 0.0) {
|
|
||||||
// Outer
|
|
||||||
steps++;
|
|
||||||
SetModeLine();
|
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
for (int i=0;i<steps;i++) {
|
|
||||||
glVertex2f(x+sin(curAngle)*r1,y+cos(curAngle)*r1);
|
|
||||||
curAngle += step;
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
// Inner
|
// Outer
|
||||||
if (r1 != r2) {
|
steps++;
|
||||||
curAngle = arcStart;
|
buf.SetSize(2, steps);
|
||||||
glBegin(GL_LINE_STRIP);
|
|
||||||
for (int i=0;i<steps;i++) {
|
|
||||||
glVertex2f(x+sin(curAngle)*r2,y+cos(curAngle)*r2);
|
|
||||||
curAngle += step;
|
|
||||||
}
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
// End caps
|
SetModeLine();
|
||||||
if (hasEnds) {
|
for (int i = 0; i < steps; i++) {
|
||||||
glBegin(GL_LINES);
|
buf.Set(i, center + Vector2D::FromAngle(cur_angle) * scale_outer);
|
||||||
glVertex2f(x+sin(arcStart)*r1,y+cos(arcStart)*r1);
|
cur_angle += step;
|
||||||
glVertex2f(x+sin(arcStart)*r2,y+cos(arcStart)*r2);
|
|
||||||
glVertex2f(x+sin(arcEnd)*r1,y+cos(arcEnd)*r1);
|
|
||||||
glVertex2f(x+sin(arcEnd)*r2,y+cos(arcEnd)*r2);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
buf.Draw(GL_LINE_STRIP);
|
||||||
|
|
||||||
|
// Inner
|
||||||
|
if (r1 == r2) return;
|
||||||
|
|
||||||
|
cur_angle = arc_start;
|
||||||
|
buf.SetSize(2, steps);
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
buf.Set(i, center + Vector2D::FromAngle(cur_angle) * scale_inner);
|
||||||
|
cur_angle += step;
|
||||||
|
}
|
||||||
|
buf.Draw(GL_LINE_STRIP);
|
||||||
|
|
||||||
|
if (!needs_end_caps) return;
|
||||||
|
|
||||||
|
buf.SetSize(2, 4);
|
||||||
|
buf.Set(0, center + Vector2D::FromAngle(arc_start) * scale_inner);
|
||||||
|
buf.Set(1, center + Vector2D::FromAngle(arc_start) * scale_outer);
|
||||||
|
buf.Set(2, center + Vector2D::FromAngle(arc_end) * scale_inner);
|
||||||
|
buf.Set(3, center + Vector2D::FromAngle(arc_end) * scale_outer);
|
||||||
|
buf.Draw(GL_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetLineColour(wxColour col, float alpha, int width) {
|
||||||
|
line_r = col.Red() / 255.f;
|
||||||
/// @brief Set line colour
|
line_g = col.Green() / 255.f;
|
||||||
/// @param col
|
line_b = col.Blue() / 255.f;
|
||||||
/// @param alpha
|
line_a = alpha;
|
||||||
/// @param width
|
line_width = width;
|
||||||
///
|
|
||||||
void OpenGLWrapper::SetLineColour(wxColour col,float alpha,int width) {
|
|
||||||
r1 = col.Red()/255.0f;
|
|
||||||
g1 = col.Green()/255.0f;
|
|
||||||
b1 = col.Blue()/255.0f;
|
|
||||||
a1 = alpha;
|
|
||||||
lw = width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetFillColour(wxColour col, float alpha) {
|
||||||
|
fill_r = col.Red() / 255.f;
|
||||||
/// @brief Set fill colour
|
fill_g = col.Green() / 255.f;
|
||||||
/// @param col
|
fill_b = col.Blue() / 255.f;
|
||||||
/// @param alpha
|
fill_a = alpha;
|
||||||
///
|
|
||||||
void OpenGLWrapper::SetFillColour(wxColour col,float alpha) {
|
|
||||||
r2 = col.Red()/255.0f;
|
|
||||||
g2 = col.Green()/255.0f;
|
|
||||||
b2 = col.Blue()/255.0f;
|
|
||||||
a2 = alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Line
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::SetModeLine() const {
|
void OpenGLWrapper::SetModeLine() const {
|
||||||
glColor4f(r1,g1,b1,a1);
|
glColor4f(line_r, line_g, line_b, line_a);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glLineWidth(lw);
|
glLineWidth(line_width);
|
||||||
glEnable(GL_LINE_SMOOTH);
|
if (smooth)
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
else
|
||||||
|
glDisable(GL_LINE_SMOOTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Fill
|
|
||||||
///
|
|
||||||
void OpenGLWrapper::SetModeFill() const {
|
void OpenGLWrapper::SetModeFill() const {
|
||||||
glColor4f(r2,g2,b2,a2);
|
glColor4f(fill_r, fill_g, fill_b, fill_a);
|
||||||
if (a2 == 1.0f) glDisable(GL_BLEND);
|
if (fill_a == 1.f) glDisable(GL_BLEND);
|
||||||
else {
|
else {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetInvert() {
|
||||||
|
glEnable(GL_COLOR_LOGIC_OP);
|
||||||
|
glLogicOp(GL_INVERT);
|
||||||
|
|
||||||
|
// GL_LINE_SMOOTH combines badly with inverting
|
||||||
/// @brief Is extension supported?
|
smooth = false;
|
||||||
/// @param ext
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool OpenGLWrapper::IsExtensionSupported(const char *ext) {
|
|
||||||
char *extList = (char*) glGetString(GL_EXTENSIONS);
|
|
||||||
if (!extList) return false;
|
|
||||||
return strstr(extList, ext) != NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::ClearInvert() {
|
||||||
|
glDisable(GL_COLOR_LOGIC_OP);
|
||||||
|
smooth = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLWrapper::IsExtensionSupported(const char *ext) {
|
||||||
|
char *extList = (char * )glGetString(GL_EXTENSIONS);
|
||||||
|
return extList && !!strstr(extList, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawLines(size_t dim, std::vector<float> const& lines) {
|
||||||
|
DrawLines(dim, &lines[0], lines.size() / dim);
|
||||||
|
}
|
||||||
|
|
||||||
/// DOCME
|
void OpenGLWrapper::DrawLines(size_t dim, std::vector<float> const& lines, size_t c_dim, std::vector<float> const& colors) {
|
||||||
wxMutex OpenGLWrapper::glMutex;
|
glShadeModel(GL_SMOOTH);
|
||||||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
|
glColorPointer(c_dim, GL_FLOAT, 0, &colors[0]);
|
||||||
|
DrawLines(dim, &lines[0], lines.size() / dim);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
glShadeModel(GL_FLAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawLines(size_t dim, const float *lines, size_t n) {
|
||||||
|
SetModeLine();
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(dim, GL_FLOAT, 0, lines);
|
||||||
|
glDrawArrays(GL_LINES, 0, n);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawLineStrip(size_t dim, std::vector<float> const& lines) {
|
||||||
|
SetModeLine();
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(dim, GL_FLOAT, 0, &lines[0]);
|
||||||
|
glDrawArrays(GL_LINE_STRIP, 0, lines.size() / dim);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Substitute for glMultiDrawArrays for sub-1.4 OpenGL
|
||||||
|
// Not required on OS X.
|
||||||
|
#ifndef __APPLE__
|
||||||
|
static void APIENTRY glMultiDrawArraysFallback(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) {
|
||||||
|
for (int i = 0; i < primcount; ++i) {
|
||||||
|
glDrawArrays(mode, *first++, *count++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void OpenGLWrapper::DrawMultiPolygon(std::vector<float> const& points, std::vector<int> &start, std::vector<int> &count, Vector2D video_size, bool invert) {
|
||||||
|
GL_EXT(PFNGLMULTIDRAWARRAYSPROC, glMultiDrawArrays);
|
||||||
|
|
||||||
|
// The following is nonzero winding-number PIP based on stencils
|
||||||
|
|
||||||
|
// Draw to stencil only
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glColorMask(0, 0, 0, 0);
|
||||||
|
|
||||||
|
// GL_INCR_WRAP was added in 1.4, so instead set the entire stencil to 128
|
||||||
|
// and wobble from there
|
||||||
|
glStencilFunc(GL_NEVER, 128, 0xFF);
|
||||||
|
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
||||||
|
|
||||||
|
VertexArray buf(2, 4);
|
||||||
|
buf.Set(0, Vector2D());
|
||||||
|
buf.Set(1, Vector2D(video_size, 0));
|
||||||
|
buf.Set(2, video_size);
|
||||||
|
buf.Set(3, Vector2D(0, video_size));
|
||||||
|
glColor4f(0, 0, 0, 1);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
buf.Draw(GL_QUADS, false);
|
||||||
|
|
||||||
|
// Increment the winding number for each forward facing triangle
|
||||||
|
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||||
|
glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
|
||||||
|
|
||||||
|
// Decrement the winding number for each backfacing triangle
|
||||||
|
glStencilOp(GL_DECR, GL_DECR, GL_DECR);
|
||||||
|
glCullFace(GL_FRONT);
|
||||||
|
glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
|
||||||
|
// Draw the actual rectangle
|
||||||
|
glColorMask(1, 1, 1, 1);
|
||||||
|
float real_line_a = line_a;
|
||||||
|
line_a = 0;
|
||||||
|
|
||||||
|
// VSFilter draws when the winding number is nonzero, so we want to draw the
|
||||||
|
// mask when the winding number is zero (where 128 is zero due to the lack of
|
||||||
|
// wrapping combined with unsigned numbers)
|
||||||
|
glStencilFunc(invert ? GL_EQUAL : GL_NOTEQUAL, 128, 0xFF);
|
||||||
|
DrawRectangle(Vector2D(), video_size);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
// Draw lines
|
||||||
|
line_a = real_line_a;
|
||||||
|
SetModeLine();
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||||
|
glMultiDrawArrays(GL_LINE_LOOP, &start[0], &count[0], start.size());
|
||||||
|
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetOrigin(Vector2D origin) {
|
||||||
|
PrepareTransform();
|
||||||
|
glTranslatef(origin.X(), origin.Y(), -1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetScale(Vector2D scale) {
|
||||||
|
PrepareTransform();
|
||||||
|
glScalef(scale.X() / 100.f, scale.Y() / 100.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::SetRotation(float x, float y, float z) {
|
||||||
|
PrepareTransform();
|
||||||
|
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
|
||||||
|
glMultMatrixf(matrix);
|
||||||
|
glScalef(1.f, 1.f, 8.f);
|
||||||
|
glRotatef(y, 0.f, -1.f, 0.f);
|
||||||
|
glRotatef(x, -1.f, 0.f, 0.f);
|
||||||
|
glRotatef(z, 0.f, 0.f, -1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::PrepareTransform() {
|
||||||
|
if (!transform_pushed) {
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
transform_pushed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWrapper::ResetTransform() {
|
||||||
|
if (transform_pushed) {
|
||||||
|
glPopMatrix();
|
||||||
|
transform_pushed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -34,41 +21,13 @@
|
||||||
/// @ingroup video_output
|
/// @ingroup video_output
|
||||||
///
|
///
|
||||||
|
|
||||||
|
#include "vector2d.h"
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#include <OpenGL/glu.h>
|
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glu.h>
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
typedef GLuint GLhandleARB;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <wx/thread.h>
|
#include <vector>
|
||||||
#include <wx/colour.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
#define glGetProc(a) wglGetProcAddress(a)
|
|
||||||
#else
|
|
||||||
#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
// Not required on OS X.
|
|
||||||
#define GL_EXT(type, name)
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define GL_EXT(type, name) \
|
|
||||||
static type name = reinterpret_cast<type>(glGetProc(#name)); \
|
|
||||||
if (!name) { \
|
|
||||||
name = reinterpret_cast<type>(& name ## Fallback); \
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class wxColour;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class OpenGLWrapper
|
/// @class OpenGLWrapper
|
||||||
|
@ -76,55 +35,51 @@ typedef GLuint GLhandleARB;
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class OpenGLWrapper {
|
class OpenGLWrapper {
|
||||||
private:
|
float line_r, line_g, line_b, line_a;
|
||||||
|
float fill_r, fill_g, fill_b, fill_a;
|
||||||
|
|
||||||
/// DOCME
|
int line_width;
|
||||||
|
bool smooth;
|
||||||
|
|
||||||
/// DOCME
|
bool transform_pushed;
|
||||||
|
void PrepareTransform();
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
float r1,g1,b1,a1;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
float r2,g2,b2,a2;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int lw;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenGLWrapper();
|
OpenGLWrapper();
|
||||||
|
|
||||||
|
void SetLineColour(wxColour col, float alpha = 1.0f, int width = 1);
|
||||||
/// DOCME
|
void SetFillColour(wxColour col, float alpha = 1.0f);
|
||||||
static wxMutex glMutex;
|
|
||||||
|
|
||||||
void SetLineColour(wxColour col,float alpha=1.0f,int width=1);
|
|
||||||
void SetFillColour(wxColour col,float alpha=1.0f);
|
|
||||||
void SetModeLine() const;
|
void SetModeLine() const;
|
||||||
void SetModeFill() const;
|
void SetModeFill() const;
|
||||||
void DrawLine(float x1,float y1,float x2,float y2) const;
|
|
||||||
void DrawDashedLine(float x1,float y1,float x2,float y2,float dashLen) const;
|
|
||||||
void DrawEllipse(float x,float y,float radiusX,float radiusY) const;
|
|
||||||
|
|
||||||
/// @brief DOCME
|
void SetInvert();
|
||||||
/// @param x
|
void ClearInvert();
|
||||||
/// @param y
|
|
||||||
/// @param radius
|
void SetScale(Vector2D scale);
|
||||||
///
|
void SetOrigin(Vector2D origin);
|
||||||
void DrawCircle(float x,float y,float radius) const { DrawEllipse(x,y,radius,radius); }
|
void SetRotation(float x, float y, float z);
|
||||||
void DrawRectangle(float x1,float y1,float x2,float y2) const;
|
void ResetTransform();
|
||||||
void DrawRing(float x,float y,float r1,float r2,float ar=1.0f,float arcStart=0.0f,float arcEnd=0.0f) const;
|
|
||||||
void DrawTriangle(float x1,float y1,float x2,float y2,float x3,float y3) const;
|
void DrawLine(Vector2D p1, Vector2D p2) const;
|
||||||
|
void DrawDashedLine(Vector2D p1, Vector2D p2, float dashLen) const;
|
||||||
|
void DrawEllipse(Vector2D center, Vector2D radius) const;
|
||||||
|
void DrawCircle(Vector2D center, float radius) const { DrawEllipse(center, Vector2D(radius, radius)); }
|
||||||
|
void DrawRectangle(Vector2D p1, Vector2D p2) const;
|
||||||
|
void DrawRing(Vector2D center, float r1, float r2, float ar = 1.0f, float arcStart = 0.0f, float arcEnd = 0.0f) const;
|
||||||
|
void DrawTriangle(Vector2D p1, Vector2D p2, Vector2D p3) const;
|
||||||
|
|
||||||
|
void DrawLines(size_t dim, std::vector<float> const& lines);
|
||||||
|
void DrawLines(size_t dim, std::vector<float> const& lines, size_t c_dim, std::vector<float> const& colors);
|
||||||
|
void DrawLines(size_t dim, const float *lines, size_t n);
|
||||||
|
void DrawLineStrip(size_t dim, std::vector<float> const& lines);
|
||||||
|
|
||||||
|
/// Draw a multipolygon serialized into a single array
|
||||||
|
/// @param points List of coordinates
|
||||||
|
/// @param start Indices in points which are the start of a new polygon
|
||||||
|
/// @param count Number of points in each polygon
|
||||||
|
/// @param video_size Bottom-right corner of the visible area
|
||||||
|
/// @param invert Draw the area outside the polygons instead
|
||||||
|
void DrawMultiPolygon(std::vector<float> const& points, std::vector<int> &start, std::vector<int> &count, Vector2D video_size, bool invert);
|
||||||
|
|
||||||
static bool IsExtensionSupported(const char *ext);
|
static bool IsExtensionSupported(const char *ext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,5 +34,5 @@ namespace toolbar {
|
||||||
/// @param context Project context
|
/// @param context Project context
|
||||||
/// @param hotkey Hotkey context for the tooltip
|
/// @param hotkey Hotkey context for the tooltip
|
||||||
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *context, std::string const& hotkey);
|
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *context, std::string const& hotkey);
|
||||||
wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *context, std::string const& hotkey);
|
wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *context, std::string const& hotkey, bool vertical = false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,43 +474,43 @@
|
||||||
"key" : "Left"
|
"key" : "Left"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool crosshair" : [
|
"video/tool/cross" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "A"
|
"key" : "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool drag" : [
|
"video/tool/drag" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "S"
|
"key" : "S"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool rectangle clip" : [
|
"video/tool/clip" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "H"
|
"key" : "H"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool rotate xy" : [
|
"video/tool/rotate/xy" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "F"
|
"key" : "F"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool rotate z" : [
|
"video/tool/rotate/z" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "D"
|
"key" : "D"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool scale" : [
|
"video/tool/scale" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "G"
|
"key" : "G"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"visual typesetting set tool vector clip" : [
|
"video/tool/vector_clip" : [
|
||||||
{
|
{
|
||||||
"modifiers" : [],
|
"modifiers" : [],
|
||||||
"key" : "J"
|
"key" : "J"
|
||||||
|
|
|
@ -61,5 +61,16 @@
|
||||||
"",
|
"",
|
||||||
"app/options",
|
"app/options",
|
||||||
"grid/tag/cycle_hiding"
|
"grid/tag/cycle_hiding"
|
||||||
|
],
|
||||||
|
"visual_tools" : [
|
||||||
|
"video/tool/cross",
|
||||||
|
"video/tool/drag",
|
||||||
|
"video/tool/rotate/z",
|
||||||
|
"video/tool/rotate/xy",
|
||||||
|
"video/tool/scale",
|
||||||
|
"video/tool/clip",
|
||||||
|
"video/tool/vector_clip",
|
||||||
|
"",
|
||||||
|
"help/video"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,192 +37,164 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include <wx/tokenzr.h>
|
#include <wx/tokenzr.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include "spline.h"
|
#include "spline.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
|
|
||||||
/// @brief Spline constructor
|
#include "utils.h"
|
||||||
Spline::Spline(const VideoDisplay &scale) : scale(scale) {
|
#include "visual_tool.h"
|
||||||
|
|
||||||
|
Spline::Spline(const VisualToolBase &scale) : scale(scale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Encode to ASS
|
/// @brief Encode to ASS
|
||||||
wxString Spline::EncodeToASS() {
|
wxString Spline::EncodeToASS() {
|
||||||
wxString result;
|
wxString result;
|
||||||
char lastCommand = 0;
|
result.reserve(size() * 10);
|
||||||
|
char last = 0;
|
||||||
|
|
||||||
// Insert each element
|
for (iterator cur = begin(); cur != end(); ++cur) {
|
||||||
for (iterator cur=begin();cur!=end();cur++) {
|
|
||||||
// Each curve
|
|
||||||
switch (cur->type) {
|
switch (cur->type) {
|
||||||
case CURVE_POINT: {
|
case SplineCurve::POINT:
|
||||||
if (lastCommand != 'm') {
|
if (last != 'm') {
|
||||||
result += "m ";
|
result += "m ";
|
||||||
lastCommand = 'm';
|
last = 'm';
|
||||||
}
|
}
|
||||||
int x = cur->p1.x;
|
result += scale.ToScriptCoords(cur->p1).DStr(' ');
|
||||||
int y = cur->p1.y;
|
|
||||||
scale.ToScriptCoords(&x, &y);
|
|
||||||
result += wxString::Format("%i %i ", x, y);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case CURVE_LINE: {
|
case SplineCurve::LINE:
|
||||||
if (lastCommand != 'l') {
|
if (last != 'l') {
|
||||||
result += "l ";
|
result += "l ";
|
||||||
lastCommand = 'l';
|
last = 'l';
|
||||||
}
|
}
|
||||||
int x = cur->p2.x;
|
result += scale.ToScriptCoords(cur->p2).DStr(' ');
|
||||||
int y = cur->p2.y;
|
|
||||||
scale.ToScriptCoords(&x, &y);
|
|
||||||
result += wxString::Format("%i %i ", x, y);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case CURVE_BICUBIC: {
|
case SplineCurve::BICUBIC:
|
||||||
if (lastCommand != 'b') {
|
if (last != 'b') {
|
||||||
result += "b ";
|
result += "b ";
|
||||||
lastCommand = 'b';
|
last = 'b';
|
||||||
}
|
}
|
||||||
int x2 = cur->p2.x;
|
result += scale.ToScriptCoords(cur->p2).DStr(' ');
|
||||||
int y2 = cur->p2.y;
|
result += scale.ToScriptCoords(cur->p3).DStr(' ');
|
||||||
int x3 = cur->p3.x;
|
result += scale.ToScriptCoords(cur->p4).DStr(' ');
|
||||||
int y3 = cur->p3.y;
|
|
||||||
int x4 = cur->p4.x;
|
|
||||||
int y4 = cur->p4.y;
|
|
||||||
scale.ToScriptCoords(&x2, &y2);
|
|
||||||
scale.ToScriptCoords(&x3, &y3);
|
|
||||||
scale.ToScriptCoords(&x4, &y4);
|
|
||||||
result += wxString::Format("%i %i %i %i %i %i ", x2, y2, x3, y3, x4, y4);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
result += " ";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Decode from ASS
|
|
||||||
/// @param str
|
|
||||||
void Spline::DecodeFromASS(wxString str) {
|
void Spline::DecodeFromASS(wxString str) {
|
||||||
// Clear current
|
// Clear current
|
||||||
clear();
|
clear();
|
||||||
std::vector<int> stack;
|
std::vector<float> stack;
|
||||||
|
|
||||||
// Prepare
|
// Prepare
|
||||||
char lastCommand = 'm';
|
char command = 'm';
|
||||||
int x = 0;
|
Vector2D pt;
|
||||||
int y = 0;
|
|
||||||
|
|
||||||
// Tokenize the string
|
// Tokenize the string
|
||||||
wxStringTokenizer tkn(str," ");
|
wxStringTokenizer tkn(str, " ");
|
||||||
while (tkn.HasMoreTokens()) {
|
while (tkn.HasMoreTokens()) {
|
||||||
wxString token = tkn.GetNextToken();
|
wxString token = tkn.GetNextToken();
|
||||||
|
double n;
|
||||||
// Got a number
|
if (token.ToCDouble(&n)) {
|
||||||
if (token.IsNumber()) {
|
|
||||||
long n;
|
|
||||||
token.ToLong(&n);
|
|
||||||
stack.push_back(n);
|
stack.push_back(n);
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
if (stack.size() == 2 && lastCommand == 'm') {
|
if (stack.size() == 2 && command == 'm') {
|
||||||
scale.FromScriptCoords(&stack[0], &stack[1]);
|
pt = scale.FromScriptCoords(Vector2D(stack[0], stack[1]));
|
||||||
SplineCurve curve;
|
|
||||||
x = curve.p1.x = stack[0];
|
|
||||||
y = curve.p1.y = stack[1];
|
|
||||||
curve.type = CURVE_POINT;
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
push_back(curve);
|
|
||||||
|
push_back(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line
|
// Line
|
||||||
if (stack.size() == 2 && lastCommand == 'l') {
|
if (stack.size() == 2 && command == 'l') {
|
||||||
scale.FromScriptCoords(&stack[0], &stack[1]);
|
SplineCurve curve(pt, scale.FromScriptCoords(Vector2D(stack[0], stack[1])));
|
||||||
SplineCurve curve;
|
|
||||||
curve.p1.x = x;
|
|
||||||
curve.p1.y = y;
|
|
||||||
x = curve.p2.x = stack[0];
|
|
||||||
y = curve.p2.y = stack[1];
|
|
||||||
curve.type = CURVE_LINE;
|
|
||||||
stack.clear();
|
|
||||||
push_back(curve);
|
push_back(curve);
|
||||||
|
|
||||||
|
pt = curve.p2;
|
||||||
|
stack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bicubic
|
// Bicubic
|
||||||
else if (stack.size() == 6 && lastCommand == 'b') {
|
else if (stack.size() == 6 && command == 'b') {
|
||||||
scale.FromScriptCoords(&stack[0], &stack[1]);
|
SplineCurve curve(pt,
|
||||||
scale.FromScriptCoords(&stack[2], &stack[3]);
|
scale.FromScriptCoords(Vector2D(stack[0], stack[1])),
|
||||||
scale.FromScriptCoords(&stack[4], &stack[5]);
|
scale.FromScriptCoords(Vector2D(stack[2], stack[3])),
|
||||||
SplineCurve curve;
|
scale.FromScriptCoords(Vector2D(stack[4], stack[5])));
|
||||||
curve.p1.x = x;
|
|
||||||
curve.p1.y = y;
|
|
||||||
curve.p2.x = stack[0];
|
|
||||||
curve.p2.y = stack[1];
|
|
||||||
curve.p3.x = stack[2];
|
|
||||||
curve.p3.y = stack[3];
|
|
||||||
curve.p4.x = stack[4];
|
|
||||||
curve.p4.y = stack[5];
|
|
||||||
curve.type = CURVE_BICUBIC;
|
|
||||||
x = curve.p4.x;
|
|
||||||
y = curve.p4.y;
|
|
||||||
stack.clear();
|
|
||||||
push_back(curve);
|
push_back(curve);
|
||||||
}
|
|
||||||
|
|
||||||
// Close
|
pt = curve.p4;
|
||||||
else if (lastCommand == 'c') {
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Got something else
|
// Got something else
|
||||||
else {
|
else if (token.size() == 1) {
|
||||||
if (token == "m") lastCommand = 'm';
|
command = token[0];
|
||||||
else if (token == "l") lastCommand = 'l';
|
stack.clear();
|
||||||
else if (token == "b") lastCommand = 'b';
|
|
||||||
else if (token == "n") lastCommand = 'n';
|
|
||||||
else if (token == "s") lastCommand = 's';
|
|
||||||
else if (token == "c") lastCommand = 'c';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Moves a specific point in the spline
|
void Spline::MovePoint(iterator curve,int point,Vector2D pos) {
|
||||||
/// @param curveIndex
|
|
||||||
/// @param point
|
|
||||||
/// @param pos
|
|
||||||
void Spline::MovePoint(iterator curve,int point,Vector2D const& pos) {
|
|
||||||
iterator prev = curve;
|
iterator prev = curve;
|
||||||
if (curve != begin()) --prev;
|
if (curve != begin()) --prev;
|
||||||
iterator next = curve;
|
iterator next = curve;
|
||||||
++next;
|
++next;
|
||||||
if (next != end() && next->type == CURVE_POINT) next = end();
|
if (next != end() && next->type == SplineCurve::POINT)
|
||||||
|
next = end();
|
||||||
|
|
||||||
// Modify
|
// Modify
|
||||||
if (point == 0) {
|
if (point == 0) {
|
||||||
curve->p1 = pos;
|
curve->p1 = pos;
|
||||||
if (curve != begin() && curve->type != CURVE_POINT) prev->EndPoint() = pos;
|
if (curve != begin() && curve->type != SplineCurve::POINT)
|
||||||
if (next != end() && curve->type == CURVE_POINT) next->p1 = pos;
|
prev->EndPoint() = pos;
|
||||||
|
if (next != end() && curve->type == SplineCurve::POINT)
|
||||||
|
next->p1 = pos;
|
||||||
}
|
}
|
||||||
else if (point == 1) {
|
else if (point == 1) {
|
||||||
curve->p2 = pos;
|
curve->p2 = pos;
|
||||||
if (next != end() && curve->type == CURVE_LINE) next->p1 = pos;
|
if (next != end() && curve->type == SplineCurve::LINE)
|
||||||
|
next->p1 = pos;
|
||||||
}
|
}
|
||||||
else if (point == 2) {
|
else if (point == 2) {
|
||||||
curve->p3 = pos;
|
curve->p3 = pos;
|
||||||
}
|
}
|
||||||
else if (point == 3) {
|
else if (point == 3) {
|
||||||
curve->p4 = pos;
|
curve->p4 = pos;
|
||||||
if (next != end()) next->p1 = pos;
|
if (next != end())
|
||||||
|
next->p1 = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Gets a list of points in the curve
|
static int render_bicubic(Spline::iterator cur, std::vector<float> &points) {
|
||||||
/// @param points
|
int len = int(
|
||||||
/// @param pointCurve
|
(cur->p2 - cur->p1).Len() +
|
||||||
|
(cur->p3 - cur->p2).Len() +
|
||||||
|
(cur->p4 - cur->p3).Len());
|
||||||
|
int steps = len/8;
|
||||||
|
|
||||||
|
for (int i = 0; i <= steps; ++i) {
|
||||||
|
// Get t and t-1 (u)
|
||||||
|
float t = i / float(steps);
|
||||||
|
Vector2D p = cur->GetPoint(t);
|
||||||
|
points.push_back(p.X());
|
||||||
|
points.push_back(p.Y());
|
||||||
|
}
|
||||||
|
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
void Spline::GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count) {
|
void Spline::GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count) {
|
||||||
points.clear();
|
points.clear();
|
||||||
first.clear();
|
first.clear();
|
||||||
|
@ -232,106 +204,65 @@ void Spline::GetPointList(std::vector<float>& points, std::vector<int>& first, s
|
||||||
int curCount = 0;
|
int curCount = 0;
|
||||||
|
|
||||||
// Generate points for each curve
|
// Generate points for each curve
|
||||||
for (iterator cur = begin();cur!=end();cur++) {
|
for (iterator cur = begin(); cur != end(); ++cur) {
|
||||||
switch (cur->type) {
|
switch (cur->type) {
|
||||||
case CURVE_POINT:
|
case SplineCurve::POINT:
|
||||||
if (curCount > 0) {
|
if (curCount > 0)
|
||||||
count.push_back(curCount);
|
count.push_back(curCount);
|
||||||
}
|
|
||||||
|
|
||||||
// start new path
|
// start new path
|
||||||
first.push_back(points.size() / 2);
|
first.push_back(points.size() / 2);
|
||||||
points.push_back(cur->p1.x);
|
points.push_back(cur->p1.X());
|
||||||
points.push_back(cur->p1.y);
|
points.push_back(cur->p1.Y());
|
||||||
curCount = 1;
|
curCount = 1;
|
||||||
break;
|
break;
|
||||||
case CURVE_LINE:
|
|
||||||
points.push_back(cur->p2.x);
|
|
||||||
points.push_back(cur->p2.y);
|
|
||||||
curCount++;
|
|
||||||
break;
|
|
||||||
case CURVE_BICUBIC: {
|
|
||||||
// Get the control points
|
|
||||||
Vector2D p1 = cur->p1;
|
|
||||||
Vector2D p2 = cur->p2;
|
|
||||||
Vector2D p3 = cur->p3;
|
|
||||||
Vector2D p4 = cur->p4;
|
|
||||||
|
|
||||||
// Find number of steps
|
case SplineCurve::LINE:
|
||||||
int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
|
points.push_back(cur->p2.X());
|
||||||
int steps = len/8;
|
points.push_back(cur->p2.Y());
|
||||||
|
++curCount;
|
||||||
// Render curve
|
|
||||||
for (int i=1;i<=steps;i++) {
|
|
||||||
// Get t and t-1 (u)
|
|
||||||
float t = float(i)/float(steps);
|
|
||||||
Vector2D p = cur->GetPoint(t);
|
|
||||||
points.push_back(p.x);
|
|
||||||
points.push_back(p.y);
|
|
||||||
}
|
|
||||||
curCount += steps;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
case SplineCurve::BICUBIC:
|
||||||
|
curCount += render_bicubic(cur, points);
|
||||||
|
break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
count.push_back(curCount);
|
count.push_back(curCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spline::GetPointList(std::vector<float> &points, iterator curve) {
|
void Spline::GetPointList(std::vector<float> &points, iterator curve) {
|
||||||
points.clear();
|
points.clear();
|
||||||
if (curve == end()) return;
|
if (curve == end()) return;
|
||||||
switch (curve->type) {
|
switch (curve->type) {
|
||||||
case CURVE_LINE:
|
case SplineCurve::LINE:
|
||||||
points.push_back(curve->p1.x);
|
points.push_back(curve->p1.X());
|
||||||
points.push_back(curve->p1.y);
|
points.push_back(curve->p1.Y());
|
||||||
points.push_back(curve->p2.x);
|
points.push_back(curve->p2.X());
|
||||||
points.push_back(curve->p2.y);
|
points.push_back(curve->p2.Y());
|
||||||
break;
|
break;
|
||||||
case CURVE_BICUBIC: {
|
|
||||||
// Get the control points
|
|
||||||
Vector2D p1 = curve->p1;
|
|
||||||
Vector2D p2 = curve->p2;
|
|
||||||
Vector2D p3 = curve->p3;
|
|
||||||
Vector2D p4 = curve->p4;
|
|
||||||
|
|
||||||
// Find number of steps
|
case SplineCurve::BICUBIC:
|
||||||
int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
|
render_bicubic(curve, points);
|
||||||
int steps = len/8;
|
|
||||||
|
|
||||||
// Render curve
|
|
||||||
for (int i=0;i<=steps;i++) {
|
|
||||||
// Get t and t-1 (u)
|
|
||||||
float t = float(i)/float(steps);
|
|
||||||
Vector2D p = curve->GetPoint(t);
|
|
||||||
points.push_back(p.x);
|
|
||||||
points.push_back(p.y);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief t value and curve of the point closest to reference
|
void Spline::GetClosestParametricPoint(Vector2D reference,iterator &curve,float &t,Vector2D &pt) {
|
||||||
/// @param reference
|
|
||||||
/// @param curve
|
|
||||||
/// @param t
|
|
||||||
/// @param pt
|
|
||||||
void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve,float &t,Vector2D &pt) {
|
|
||||||
curve = end();
|
curve = end();
|
||||||
t = 0.f;
|
t = 0.f;
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
|
|
||||||
// Close the shape
|
// Close the shape
|
||||||
SplineCurve pad;
|
push_back(SplineCurve(back().EndPoint(), front().p1));
|
||||||
pad.p1 = back().EndPoint();
|
|
||||||
pad.p2 = front().p1;
|
|
||||||
pad.type = CURVE_LINE;
|
|
||||||
push_back(pad);
|
|
||||||
|
|
||||||
float closest = std::numeric_limits<float>::infinity();
|
float closest = std::numeric_limits<float>::infinity();
|
||||||
for (iterator cur = begin();cur!=end();cur++) {
|
for (iterator cur = begin(); cur != end(); ++cur) {
|
||||||
float param = cur->GetClosestParam(reference);
|
float param = cur->GetClosestParam(reference);
|
||||||
Vector2D p1 = cur->GetPoint(param);
|
Vector2D p1 = cur->GetPoint(param);
|
||||||
float dist = (p1-reference).SquareLen();
|
float dist = (p1-reference).SquareLen();
|
||||||
|
@ -351,19 +282,14 @@ void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve
|
||||||
pop_back();
|
pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Point closest to reference
|
Vector2D Spline::GetClosestPoint(Vector2D reference) {
|
||||||
/// @param reference
|
|
||||||
/// @return
|
|
||||||
Vector2D Spline::GetClosestPoint(Vector2D const& reference) {
|
|
||||||
iterator curve;
|
iterator curve;
|
||||||
float t;
|
float t;
|
||||||
Vector2D point;
|
Vector2D point;
|
||||||
GetClosestParametricPoint(reference,curve,t,point);
|
GetClosestParametricPoint(reference, curve, t, point);
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Smoothes the spline
|
|
||||||
/// @param smooth
|
|
||||||
void Spline::Smooth(float smooth) {
|
void Spline::Smooth(float smooth) {
|
||||||
// See if there are enough curves
|
// See if there are enough curves
|
||||||
if (size() < 3) return;
|
if (size() < 3) return;
|
||||||
|
@ -371,13 +297,12 @@ void Spline::Smooth(float smooth) {
|
||||||
// Smooth curve
|
// Smooth curve
|
||||||
iterator curve1 = end();
|
iterator curve1 = end();
|
||||||
--curve1;
|
--curve1;
|
||||||
for (iterator cur = begin(); cur != end();) {
|
for (iterator cur = begin(); cur != end(); ) {
|
||||||
iterator curve0 = curve1;
|
iterator curve0 = curve1;
|
||||||
curve1 = cur;
|
curve1 = cur;
|
||||||
cur++;
|
++cur;
|
||||||
iterator curve2 = cur == end() ? begin() : cur;
|
iterator curve2 = cur == end() ? begin() : cur;
|
||||||
|
|
||||||
// Smooth curve
|
curve1->Smooth(curve0->p1, curve2->p2, smooth);
|
||||||
curve1->Smooth(curve0->p1,curve2->p2,smooth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,29 +43,41 @@
|
||||||
|
|
||||||
#include "spline_curve.h"
|
#include "spline_curve.h"
|
||||||
|
|
||||||
class VideoDisplay;
|
class VisualToolBase;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class Spline
|
/// @class Spline
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
class Spline : private std::list<SplineCurve> {
|
class Spline : private std::list<SplineCurve> {
|
||||||
private:
|
const VisualToolBase &scale;
|
||||||
const VideoDisplay &scale;
|
|
||||||
public:
|
public:
|
||||||
Spline(const VideoDisplay &scale);
|
Spline(const VisualToolBase &scale);
|
||||||
|
|
||||||
|
/// Encode to an ASS vector drawing
|
||||||
wxString EncodeToASS();
|
wxString EncodeToASS();
|
||||||
|
|
||||||
|
/// Decode an ASS vector drawing
|
||||||
void DecodeFromASS(wxString str);
|
void DecodeFromASS(wxString str);
|
||||||
|
|
||||||
void MovePoint(iterator curve,int point,Vector2D const& pos);
|
/// @brief Moves a specific point in the spline
|
||||||
|
/// @param curve Curve which the point is in
|
||||||
|
/// @param point Index in the curve
|
||||||
|
/// @param pos New position
|
||||||
|
void MovePoint(iterator curve, int point, Vector2D pos);
|
||||||
|
|
||||||
|
/// Smooth the spline
|
||||||
void Smooth(float smooth=1.0f);
|
void Smooth(float smooth=1.0f);
|
||||||
|
|
||||||
|
/// Gets a list of points in the curve
|
||||||
void GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count);
|
void GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count);
|
||||||
|
/// Gets a list of points in the curve
|
||||||
void GetPointList(std::vector<float> &points, iterator curve);
|
void GetPointList(std::vector<float> &points, iterator curve);
|
||||||
|
|
||||||
void GetClosestParametricPoint(Vector2D const& reference, iterator& curve, float &t, Vector2D &point);
|
/// Get t value and curve of the point closest to reference
|
||||||
Vector2D GetClosestPoint(Vector2D const& reference);
|
void GetClosestParametricPoint(Vector2D reference, iterator& curve, float &t, Vector2D &point);
|
||||||
Vector2D GetClosestControlPoint(Vector2D const& reference);
|
/// Get closest point on the curve to reference
|
||||||
|
Vector2D GetClosestPoint(Vector2D reference);
|
||||||
|
Vector2D GetClosestControlPoint(Vector2D reference);
|
||||||
|
|
||||||
// This list intentionally excludes things specific to std::list
|
// This list intentionally excludes things specific to std::list
|
||||||
using std::list<SplineCurve>::value_type;
|
using std::list<SplineCurve>::value_type;
|
||||||
|
|
|
@ -34,145 +34,103 @@
|
||||||
/// @ingroup visual_ts
|
/// @ingroup visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "spline_curve.h"
|
#include "spline_curve.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/// @brief Curve constructor
|
#ifndef AGI_PRE
|
||||||
///
|
#include <limits>
|
||||||
SplineCurve::SplineCurve() {
|
#include <numeric>
|
||||||
type = CURVE_INVALID;
|
#endif
|
||||||
|
|
||||||
|
SplineCurve::SplineCurve(Vector2D p1) : p1(p1), type(POINT) { }
|
||||||
|
SplineCurve::SplineCurve(Vector2D p1, Vector2D p2) : p1(p1), p2(p2), type(LINE) { }
|
||||||
|
SplineCurve::SplineCurve(Vector2D p1, Vector2D p2, Vector2D p3, Vector2D p4)
|
||||||
|
: p1(p1), p2(p2), p3(p3), p4(p4), type(BICUBIC)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Split a curve in two using the de Casteljau algorithm
|
void SplineCurve::Split(SplineCurve &c1, SplineCurve &c2, float t) {
|
||||||
/// @param c1
|
if (type == LINE) {
|
||||||
/// @param c2
|
c1 = SplineCurve(p1, p1 * (1 - t) + p2 * t);
|
||||||
/// @param t
|
c2 = SplineCurve(c1.p2, p2);
|
||||||
///
|
|
||||||
void SplineCurve::Split(SplineCurve &c1,SplineCurve &c2,float t) {
|
|
||||||
// Split a line
|
|
||||||
if (type == CURVE_LINE) {
|
|
||||||
c1.type = CURVE_LINE;
|
|
||||||
c2.type = CURVE_LINE;
|
|
||||||
c1.p1 = p1;
|
|
||||||
c2.p2 = p2;
|
|
||||||
c1.p2 = p1*(1-t)+p2*t;
|
|
||||||
c2.p1 = c1.p2;
|
|
||||||
}
|
}
|
||||||
|
else if (type == BICUBIC) {
|
||||||
|
float u = 1 - t;
|
||||||
|
Vector2D p12 = p1 * u + p2 * t;
|
||||||
|
Vector2D p23 = p2 * u + p3 * t;
|
||||||
|
Vector2D p34 = p3 * u + p4 * t;
|
||||||
|
Vector2D p123 = p12 * u + p23 * t;
|
||||||
|
Vector2D p234 = p23 * u + p34 * t;
|
||||||
|
Vector2D p1234 = p123 * u + p234 * t;
|
||||||
|
|
||||||
// Split a bicubic
|
c1 = SplineCurve(p1, p12, p123, p1234);
|
||||||
else if (type == CURVE_BICUBIC) {
|
c2 = SplineCurve(p1234, p234, p34, p4);
|
||||||
c1.type = CURVE_BICUBIC;
|
|
||||||
c2.type = CURVE_BICUBIC;
|
|
||||||
|
|
||||||
// Sub-divisions
|
|
||||||
float u = 1-t;
|
|
||||||
Vector2D p12 = p1*u+p2*t;
|
|
||||||
Vector2D p23 = p2*u+p3*t;
|
|
||||||
Vector2D p34 = p3*u+p4*t;
|
|
||||||
Vector2D p123 = p12*u+p23*t;
|
|
||||||
Vector2D p234 = p23*u+p34*t;
|
|
||||||
Vector2D p1234 = p123*u+p234*t;
|
|
||||||
|
|
||||||
// Set points
|
|
||||||
c1.p1 = p1;
|
|
||||||
c2.p4 = p4;
|
|
||||||
c1.p2 = p12;
|
|
||||||
c1.p3 = p123;
|
|
||||||
c1.p4 = p1234;
|
|
||||||
c2.p1 = p1234;
|
|
||||||
c2.p2 = p234;
|
|
||||||
c2.p3 = p34;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Based on http://antigrain.com/research/bezier_interpolation/index.html Smoothes the curve
|
void SplineCurve::Smooth(Vector2D p0, Vector2D p3, float smooth) {
|
||||||
/// @param P0
|
if (type != LINE || p1 == p2) return;
|
||||||
/// @param P3
|
smooth = mid(0.f, smooth, 1.f);
|
||||||
/// @param smooth
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void SplineCurve::Smooth(Vector2D const& P0,Vector2D const& P3,float smooth) {
|
|
||||||
// Validate
|
|
||||||
if (type != CURVE_LINE) return;
|
|
||||||
if (p1 == p2) return;
|
|
||||||
smooth = mid(0.f,smooth,1.f);
|
|
||||||
|
|
||||||
// Get points
|
|
||||||
Vector2D P1 = p1;
|
|
||||||
Vector2D P2 = p2;
|
|
||||||
|
|
||||||
// Calculate intermediate points
|
// Calculate intermediate points
|
||||||
Vector2D c1 = (P0+P1)/2.f;
|
Vector2D c1 = (p0 + p1) / 2.f;
|
||||||
Vector2D c2 = (P1+P2)/2.f;
|
Vector2D c2 = (p1 + p2) / 2.f;
|
||||||
Vector2D c3 = (P2+P3)/2.f;
|
Vector2D c3 = (p2 + p3) / 2.f;
|
||||||
float len1 = (P1-P0).Len();
|
|
||||||
float len2 = (P2-P1).Len();
|
float len1 = (p1 - p0).Len();
|
||||||
float len3 = (P3-P2).Len();
|
float len2 = (p2 - p1).Len();
|
||||||
float k1 = len1/(len1+len2);
|
float len3 = (p3 - p2).Len();
|
||||||
float k2 = len2/(len2+len3);
|
|
||||||
Vector2D m1 = c1+(c2-c1)*k1;
|
float k1 = len1 / (len1 + len2);
|
||||||
Vector2D m2 = c2+(c3-c2)*k2;
|
float k2 = len2 / (len2 + len3);
|
||||||
|
|
||||||
|
Vector2D m1 = c1 + (c2 - c1) * k1;
|
||||||
|
Vector2D m2 = c2 + (c3 - c2) * k2;
|
||||||
|
|
||||||
// Set curve points
|
// Set curve points
|
||||||
p4 = p2;
|
p4 = p2;
|
||||||
p2 = m1+(c2-m1)*smooth + P1 - m1;
|
p3 = m2 + (c2 - m2) * smooth + p2 - m2;
|
||||||
p3 = m2+(c2-m2)*smooth + P2 - m2;
|
p2 = m1 + (c2 - m1) * smooth + p1 - m1;
|
||||||
type = CURVE_BICUBIC;
|
type = BICUBIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get a point
|
|
||||||
/// @param t
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D SplineCurve::GetPoint(float t) const {
|
Vector2D SplineCurve::GetPoint(float t) const {
|
||||||
if (type == CURVE_POINT) return p1;
|
float u = 1.f - t;
|
||||||
if (type == CURVE_LINE) {
|
|
||||||
return p1*(1.f-t) + p2*t;
|
|
||||||
}
|
|
||||||
if (type == CURVE_BICUBIC) {
|
|
||||||
float u = 1.f-t;
|
|
||||||
return p1*u*u*u + 3*p2*t*u*u + 3*p3*t*t*u + p4*t*t*t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Vector2D(0,0);
|
if (type == POINT)
|
||||||
|
return p1;
|
||||||
|
if (type == LINE)
|
||||||
|
return p1 * u + p2 * t;
|
||||||
|
|
||||||
|
return p1*u*u*u + 3*p2*t*u*u + 3*p3*t*t*u + p4*t*t*t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2D& SplineCurve::EndPoint() {
|
Vector2D& SplineCurve::EndPoint() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CURVE_POINT: return p1;
|
case POINT: return p1;
|
||||||
case CURVE_LINE: return p2;
|
case LINE: return p2;
|
||||||
case CURVE_BICUBIC: return p4;
|
case BICUBIC: return p4;
|
||||||
default: return p1;
|
default: return p1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get point closest to reference
|
Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const {
|
||||||
/// @param ref
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D SplineCurve::GetClosestPoint(Vector2D const& ref) const {
|
|
||||||
return GetPoint(GetClosestParam(ref));
|
return GetPoint(GetClosestParam(ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get value of parameter closest to point
|
float SplineCurve::GetClosestParam(Vector2D ref) const {
|
||||||
/// @param ref
|
if (type == LINE)
|
||||||
/// @return
|
return GetClosestSegmentPart(p1, p2, ref);
|
||||||
///
|
|
||||||
float SplineCurve::GetClosestParam(Vector2D const& ref) const {
|
if (type == BICUBIC) {
|
||||||
if (type == CURVE_LINE) {
|
|
||||||
return GetClosestSegmentPart(p1,p2,ref);
|
|
||||||
}
|
|
||||||
if (type == CURVE_BICUBIC) {
|
|
||||||
int steps = 100;
|
int steps = 100;
|
||||||
float bestDist = 80000000.f;
|
float bestDist = std::numeric_limits<float>::max();
|
||||||
float bestT = 0.f;
|
float bestT = 0.f;
|
||||||
for (int i=0;i<=steps;i++) {
|
for (int i = 0; i <= steps; ++i) {
|
||||||
float t = float(i)/float(steps);
|
float t = i / float(steps);
|
||||||
float dist = (GetPoint(t)-ref).Len();
|
float dist = (GetPoint(t) - ref).SquareLen();
|
||||||
if (dist < bestDist) {
|
if (dist < bestDist) {
|
||||||
bestDist = dist;
|
bestDist = dist;
|
||||||
bestT = t;
|
bestT = t;
|
||||||
|
@ -180,45 +138,30 @@ float SplineCurve::GetClosestParam(Vector2D const& ref) const {
|
||||||
}
|
}
|
||||||
return bestT;
|
return bestT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.f;
|
return 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Quick distance
|
float SplineCurve::GetQuickDistance(Vector2D ref) const {
|
||||||
/// @param ref
|
if (type == BICUBIC) {
|
||||||
/// @return
|
float lens[] = {
|
||||||
///
|
GetClosestSegmentDistance(p1, p2, ref),
|
||||||
float SplineCurve::GetQuickDistance(Vector2D const& ref) const {
|
GetClosestSegmentDistance(p2, p3, ref),
|
||||||
using std::min;
|
GetClosestSegmentDistance(p3, p4, ref),
|
||||||
if (type == CURVE_BICUBIC) {
|
GetClosestSegmentDistance(p4, p1, ref),
|
||||||
float len1 = GetClosestSegmentDistance(p1,p2,ref);
|
GetClosestSegmentDistance(p1, p3, ref),
|
||||||
float len2 = GetClosestSegmentDistance(p2,p3,ref);
|
GetClosestSegmentDistance(p2, p4, ref)
|
||||||
float len3 = GetClosestSegmentDistance(p3,p4,ref);
|
};
|
||||||
float len4 = GetClosestSegmentDistance(p4,p1,ref);
|
return *std::min_element(lens, lens + 6);
|
||||||
float len5 = GetClosestSegmentDistance(p1,p3,ref);
|
|
||||||
float len6 = GetClosestSegmentDistance(p2,p4,ref);
|
|
||||||
return min(min(min(len1,len2),min(len3,len4)),min(len5,len6));
|
|
||||||
}
|
}
|
||||||
|
return (GetClosestPoint(ref) - ref).Len();
|
||||||
// Something else
|
|
||||||
else return (GetClosestPoint(ref)-ref).Len();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Closest t in segment p1-p2 to point p3
|
float SplineCurve::GetClosestSegmentPart(Vector2D pt1, Vector2D pt2, Vector2D pt3) const {
|
||||||
/// @param pt1
|
return mid(0.f, (pt3 - pt1).Dot(pt2 - pt1) / (pt2 - pt1).SquareLen(), 1.f);
|
||||||
/// @param pt2
|
|
||||||
/// @param pt3
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
float SplineCurve::GetClosestSegmentPart(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
|
|
||||||
return mid(0.f,(pt3-pt1).Dot(pt2-pt1)/(pt2-pt1).SquareLen(),1.f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Closest distance between p3 and segment p1-p2
|
float SplineCurve::GetClosestSegmentDistance(Vector2D pt1, Vector2D pt2, Vector2D pt3) const {
|
||||||
/// @param pt1
|
float t = GetClosestSegmentPart(pt1, pt2, pt3);
|
||||||
/// @param pt2
|
return (pt1 * (1.f - t) + pt2 * t - pt3).Len();
|
||||||
/// @param pt3
|
|
||||||
///
|
|
||||||
float SplineCurve::GetClosestSegmentDistance(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
|
|
||||||
float t = GetClosestSegmentPart(pt1,pt2,pt3);
|
|
||||||
return (pt1*(1.f-t)+pt2*t-pt3).Len();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,57 +34,54 @@
|
||||||
/// @ingroup visual_ts
|
/// @ingroup visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "vector2d.h"
|
#include "vector2d.h"
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
enum CurveType {
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
CURVE_INVALID,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
CURVE_POINT,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
CURVE_LINE,
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
CURVE_BICUBIC
|
|
||||||
};
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class SplineCurve
|
/// @class SplineCurve
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class SplineCurve {
|
class SplineCurve {
|
||||||
private:
|
/// Closest t in segment p1-p2 to point p3
|
||||||
float GetClosestSegmentPart(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
|
float GetClosestSegmentPart(Vector2D p1, Vector2D p2, Vector2D p3) const;
|
||||||
float GetClosestSegmentDistance(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
|
|
||||||
|
|
||||||
|
/// Closest distance between p3 and segment p1-p2
|
||||||
|
float GetClosestSegmentDistance(Vector2D p1, Vector2D p2, Vector2D p3) const;
|
||||||
public:
|
public:
|
||||||
|
enum CurveType {
|
||||||
|
POINT,
|
||||||
|
LINE,
|
||||||
|
BICUBIC
|
||||||
|
};
|
||||||
|
|
||||||
/// DOCME
|
Vector2D p1;
|
||||||
|
Vector2D p2;
|
||||||
/// DOCME
|
Vector2D p3;
|
||||||
|
Vector2D p4;
|
||||||
/// DOCME
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
Vector2D p1,p2,p3,p4;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
CurveType type;
|
CurveType type;
|
||||||
|
|
||||||
SplineCurve();
|
SplineCurve(Vector2D p1 = Vector2D());
|
||||||
void Split(SplineCurve &c1,SplineCurve &c2,float t=0.5);
|
SplineCurve(Vector2D p1, Vector2D p2);
|
||||||
void Smooth(Vector2D const& prev,Vector2D const& next,float smooth=1.0f);
|
SplineCurve(Vector2D p1, Vector2D p2, Vector2D p3, Vector2D p4);
|
||||||
|
|
||||||
|
/// @brief Split a curve in two using the de Casteljau algorithm
|
||||||
|
/// @param[out] c1 Curve before split point
|
||||||
|
/// @param[out] c2 Curve after split point
|
||||||
|
/// @param t Split point
|
||||||
|
void Split(SplineCurve &c1, SplineCurve &c2, float t = 0.5f);
|
||||||
|
|
||||||
|
/// @brief Smooths the curve
|
||||||
|
/// @note Based on http://antigrain.com/research/bezier_interpolation/index.html
|
||||||
|
void Smooth(Vector2D prev, Vector2D next, float smooth = 1.0f);
|
||||||
|
|
||||||
Vector2D GetPoint(float t) const;
|
Vector2D GetPoint(float t) const;
|
||||||
Vector2D& EndPoint();
|
Vector2D& EndPoint();
|
||||||
Vector2D GetClosestPoint(Vector2D const& ref) const;
|
/// Get point on the curve closest to reference
|
||||||
float GetClosestParam(Vector2D const& ref) const;
|
Vector2D GetClosestPoint(Vector2D ref) const;
|
||||||
float GetQuickDistance(Vector2D const& ref) const;
|
/// Get t value for the closest point to reference
|
||||||
|
float GetClosestParam(Vector2D ref) const;
|
||||||
|
/// Get distance from ref to the closest point on the curve
|
||||||
|
float GetQuickDistance(Vector2D ref) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "validators.h"
|
#include "validators.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BUTTON_BOLD = 1300,
|
BUTTON_BOLD = 1300,
|
||||||
|
|
|
@ -166,8 +166,8 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context)
|
Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context, bool vertical)
|
||||||
: wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_HORIZONTAL)
|
: wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | (vertical ? wxTB_VERTICAL : wxTB_HORIZONTAL))
|
||||||
, name(name)
|
, name(name)
|
||||||
, context(c)
|
, context(c)
|
||||||
, ht_context(ht_context)
|
, ht_context(ht_context)
|
||||||
|
@ -182,10 +182,10 @@ namespace {
|
||||||
|
|
||||||
namespace toolbar {
|
namespace toolbar {
|
||||||
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *c, std::string const& hotkey) {
|
void AttachToolbar(wxFrame *frame, std::string const& name, agi::Context *c, std::string const& hotkey) {
|
||||||
frame->SetToolBar(new Toolbar(frame, name, c, hotkey));
|
frame->SetToolBar(new Toolbar(frame, name, c, hotkey, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& hotkey) {
|
wxToolBar *GetToolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& hotkey, bool vertical) {
|
||||||
return new Toolbar(parent, name, c, hotkey);
|
return new Toolbar(parent, name, c, hotkey, vertical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -34,238 +21,77 @@
|
||||||
/// @ingroup utility visual_ts
|
/// @ingroup utility visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
|
|
||||||
///////////
|
|
||||||
// Headers
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
|
||||||
#include <math.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "vector2d.h"
|
#include "vector2d.h"
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
/// @brief Null constructor
|
#include <wx/numformatter.h>
|
||||||
///
|
#endif
|
||||||
Vector2D::Vector2D () {
|
|
||||||
x = y = 0;
|
Vector2D operator *(float f, Vector2D v) {
|
||||||
|
return Vector2D(v.X() * f, v.Y() * f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D operator /(float f, Vector2D v) {
|
||||||
|
return Vector2D(f / v.X(), f / v.Y());
|
||||||
/// @brief Standard constructor
|
|
||||||
/// @param _x
|
|
||||||
/// @param _y
|
|
||||||
///
|
|
||||||
Vector2D::Vector2D (float _x,float _y) {
|
|
||||||
x = _x;
|
|
||||||
y = _y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D operator +(float f, Vector2D v) {
|
||||||
|
return Vector2D(v.X() + f, v.Y() + f);
|
||||||
/// @brief Construction from another vector
|
|
||||||
/// @param vec
|
|
||||||
///
|
|
||||||
Vector2D::Vector2D (const Vector2D &vec) {
|
|
||||||
x = vec.x;
|
|
||||||
y = vec.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D operator -(float f, Vector2D v) {
|
||||||
|
return Vector2D(f - v.X(), f - v.Y());
|
||||||
/// @brief Assignment
|
|
||||||
/// @param param
|
|
||||||
///
|
|
||||||
void Vector2D::operator = (const Vector2D param) {
|
|
||||||
x = param.x;
|
|
||||||
y = param.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::Unit() const {
|
||||||
|
float len = Len();
|
||||||
/// @brief Comparison
|
if (len == 0)
|
||||||
/// @param param
|
return Vector2D(0, 0);
|
||||||
/// @return
|
return *this / len;
|
||||||
///
|
|
||||||
bool Vector2D::operator == (const Vector2D param) const {
|
|
||||||
return ((x == param.x) && (y == param.y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::SingleAxis() const {
|
||||||
/// @brief DOCME
|
if (abs(x) < abs(y))
|
||||||
/// @param param
|
return Vector2D(0, y);
|
||||||
/// @return
|
else
|
||||||
///
|
return Vector2D(x, 0);
|
||||||
bool Vector2D::operator != (const Vector2D param) const {
|
|
||||||
return ((x != param.x) || (y == param.y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::Max(Vector2D param) const {
|
||||||
|
return Vector2D(std::max(x, param.x), std::max(y, param.y));
|
||||||
/// @brief Adition
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator + (const Vector2D param) const {
|
|
||||||
return Vector2D(x + param.x,y + param.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::Min(Vector2D param) const {
|
||||||
/// @brief DOCME
|
return Vector2D(std::min(x, param.x), std::min(y, param.y));
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator += (const Vector2D param) {
|
|
||||||
x += param.x;
|
|
||||||
y += param.y;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::Round(float step) const {
|
||||||
|
return Vector2D(floorf(x / step + .5f) * step, floorf(y / step + .5f) * step);
|
||||||
/// @brief Subtraction
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator - (const Vector2D param) const {
|
|
||||||
return Vector2D(x - param.x,y - param.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D::operator unspecified_bool_type() const {
|
||||||
/// @brief DOCME
|
return *this == Bad() ? 0 : &Vector2D::x;
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator -= (const Vector2D param) {
|
|
||||||
x -= param.x;
|
|
||||||
y -= param.y;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::Bad() {
|
||||||
|
return Vector2D(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
|
||||||
/// @brief Negate
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator - () const {
|
|
||||||
return Vector2D(-x,-y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString Vector2D::PStr(char sep) const {
|
||||||
|
return "(" + Str(sep) + ")";
|
||||||
/// @brief Multiplication by scalar
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator * (float param) const {
|
|
||||||
return Vector2D(x * param,y * param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString Vector2D::DStr(char sep) const {
|
||||||
/// @brief DOCME
|
return wxString::Format("%d%c%d", (int)x, sep, (int)y);
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator *= (float param) {
|
|
||||||
x *= param;
|
|
||||||
y *= param;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString Vector2D::Str(char sep) const {
|
||||||
/// @brief DOCME
|
return
|
||||||
/// @param f
|
wxNumberFormatter::ToString(x, 3, wxNumberFormatter::Style_NoTrailingZeroes) +
|
||||||
/// @param v
|
sep +
|
||||||
/// @return
|
wxNumberFormatter::ToString(y, 3, wxNumberFormatter::Style_NoTrailingZeroes);
|
||||||
///
|
|
||||||
Vector2D operator * (float f,const Vector2D &v) {
|
|
||||||
return Vector2D(v.x * f,v.y * f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Division by scalar
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator / (float param) const {
|
|
||||||
return Vector2D(x / param,y / param);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::operator /= (float param) {
|
|
||||||
x /= param;
|
|
||||||
y /= param;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param f
|
|
||||||
/// @param v
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
Vector2D operator / (float f,const Vector2D &v) {
|
|
||||||
return Vector2D(v.x / f,v.y / f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Cross product
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
float Vector2D::Cross (const Vector2D param) const {
|
|
||||||
return x * param.y - y * param.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Dot product
|
|
||||||
/// @param param
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
float Vector2D::Dot (const Vector2D param) const {
|
|
||||||
return (x * param.x) + (y * param.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Length
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
float Vector2D::Len () const {
|
|
||||||
return sqrt(x*x + y*y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Squared Length
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
float Vector2D::SquareLen () const {
|
|
||||||
return x*x + y*y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Unitary
|
|
||||||
///
|
|
||||||
Vector2D Vector2D::Unit () const {
|
|
||||||
float l = Len();
|
|
||||||
if (l != 0) {
|
|
||||||
Vector2D temp;
|
|
||||||
temp.x = x;
|
|
||||||
temp.y = y;
|
|
||||||
return temp / l;
|
|
||||||
}
|
|
||||||
else return Vector2D(0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -34,8 +21,13 @@
|
||||||
/// @ingroup utility visual_ts
|
/// @ingroup utility visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <wx/gdicmn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class Vector2D
|
/// @class Vector2D
|
||||||
|
@ -43,53 +35,62 @@
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class Vector2D {
|
class Vector2D {
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
typedef float Vector2D::*unspecified_bool_type;
|
||||||
public:
|
public:
|
||||||
|
float X() const { return x; }
|
||||||
|
float Y() const { return y; }
|
||||||
|
|
||||||
/// DOCME
|
Vector2D() : x(0), y(0) { }
|
||||||
|
Vector2D(float x, float y) : x(x), y(y) { }
|
||||||
|
Vector2D(wxPoint pt) : x(pt.x), y(pt.y) { }
|
||||||
|
Vector2D(Vector2D x, Vector2D y) : x(x.x), y(y.y) { }
|
||||||
|
Vector2D(float x, Vector2D y) : x(x), y(y.y) { }
|
||||||
|
Vector2D(Vector2D x, float y) : x(x.x), y(y) { }
|
||||||
|
|
||||||
/// DOCME
|
bool operator ==(const Vector2D r) const { return x == r.x && y == r.y; }
|
||||||
float x,y;
|
bool operator !=(const Vector2D r) const { return x != r.x || y != r.y; }
|
||||||
|
operator unspecified_bool_type() const;
|
||||||
|
|
||||||
Vector2D ();
|
Vector2D operator -() const { return Vector2D(-x, -y); }
|
||||||
Vector2D (float _x,float _y);
|
Vector2D operator +(const Vector2D r) const { return Vector2D(x + r.x, y + r.y); }
|
||||||
Vector2D (const Vector2D &vec);
|
Vector2D operator -(const Vector2D r) const { return Vector2D(x - r.x, y - r.y); }
|
||||||
|
Vector2D operator *(const Vector2D r) const { return Vector2D(x * r.x, y * r.y); }
|
||||||
|
Vector2D operator /(const Vector2D r) const { return Vector2D(x / r.x, y / r.y); }
|
||||||
|
Vector2D operator +(float param) const { return Vector2D(x + param, y + param); }
|
||||||
|
Vector2D operator -(float param) const { return Vector2D(x - param, y - param); }
|
||||||
|
Vector2D operator *(float param) const { return Vector2D(x * param, y * param); }
|
||||||
|
Vector2D operator /(float param) const { return Vector2D(x / param, y / param); }
|
||||||
|
|
||||||
void operator = (const Vector2D param);
|
Vector2D Unit() const;
|
||||||
bool operator == (const Vector2D param) const;
|
Vector2D SingleAxis() const;
|
||||||
bool operator != (const Vector2D param) const;
|
|
||||||
|
|
||||||
Vector2D operator - () const;
|
Vector2D Perpendicular() const { return Vector2D(-y, x); }
|
||||||
Vector2D operator + (const Vector2D param) const;
|
|
||||||
Vector2D operator - (const Vector2D param) const;
|
|
||||||
Vector2D operator * (float param) const;
|
|
||||||
Vector2D operator / (float param) const;
|
|
||||||
|
|
||||||
Vector2D operator += (const Vector2D param);
|
Vector2D Max(Vector2D param) const;
|
||||||
Vector2D operator -= (const Vector2D param);
|
Vector2D Min(Vector2D param) const;
|
||||||
Vector2D operator *= (float param);
|
Vector2D Round(float step) const;
|
||||||
Vector2D operator /= (float param);
|
|
||||||
|
|
||||||
Vector2D Unit () const;
|
float Cross(const Vector2D param) const { return x * param.y - y * param.x; }
|
||||||
float Cross (const Vector2D param) const;
|
float Dot(const Vector2D param) const { return x * param.x + y * param.y; }
|
||||||
float Dot (const Vector2D param) const;
|
|
||||||
|
|
||||||
float Len () const;
|
float Len() const { return sqrt(x*x + y*y); }
|
||||||
|
float SquareLen() const { return x*x + y*y; }
|
||||||
|
float Angle() const { return atan2(y, x); }
|
||||||
|
|
||||||
/// @brief DOCME
|
/// Get as string with given separator
|
||||||
/// @return
|
wxString Str(char sep = ',') const;
|
||||||
///
|
/// Get as string surrounded by parentheses with given separator
|
||||||
float Length () const { return Len(); }
|
wxString PStr(char sep = ',') const;
|
||||||
float SquareLen () const;
|
/// Get as string with given separator with values rounded to ints
|
||||||
|
wxString DStr(char sep = ',') const;
|
||||||
|
|
||||||
/// @brief DOCME
|
static Vector2D FromAngle(float angle) { return Vector2D(cos(-angle), sin(-angle)); }
|
||||||
///
|
static Vector2D Bad();
|
||||||
float SquareLength () const { return SquareLen(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Vector2D operator * (float f, Vector2D v);
|
||||||
////////////////////
|
Vector2D operator / (float f, Vector2D v);
|
||||||
// Global operators
|
Vector2D operator + (float f, Vector2D v);
|
||||||
Vector2D operator * (float f,const Vector2D &v);
|
Vector2D operator - (float f, Vector2D v);
|
||||||
Vector2D operator / (float f,const Vector2D &v);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "include/aegisub/context.h"
|
#include "include/aegisub/context.h"
|
||||||
|
#include "include/aegisub/toolbar.h"
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
@ -104,22 +105,11 @@ VideoBox::VideoBox(wxWindow *parent, bool isDetached, agi::Context *context)
|
||||||
zoomBox = new wxComboBox(this, -1, "75%", wxDefaultPosition, wxDefaultSize, choices, wxCB_DROPDOWN);
|
zoomBox = new wxComboBox(this, -1, "75%", wxDefaultPosition, wxDefaultSize, choices, wxCB_DROPDOWN);
|
||||||
|
|
||||||
// Typesetting buttons
|
// Typesetting buttons
|
||||||
visualToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,wxTB_VERTICAL|wxTB_FLAT|wxTB_NODIVIDER);
|
visualToolBar = toolbar::GetToolbar(this, "visual_tools", context, "Video", true);
|
||||||
visualToolBar->AddTool(Video_Mode_Standard,_("Standard"),GETIMAGE(visual_standard_24),_("Standard mode, double click sets position."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Drag,_("Drag"),GETIMAGE(visual_move_24),_("Drag subtitles."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Rotate_Z,_("Rotate Z"),GETIMAGE(visual_rotatez_24),_("Rotate subtitles on their Z axis."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Rotate_XY,_("Rotate XY"),GETIMAGE(visual_rotatexy_24),_("Rotate subtitles on their X and Y axes."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Scale,_("Scale"),GETIMAGE(visual_scale_24),_("Scale subtitles on X and Y axes."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Clip,_("Clip"),GETIMAGE(visual_clip_24),_("Clip subtitles to a rectangle."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddTool(Video_Mode_Vector_Clip,_("Vector Clip"),GETIMAGE(visual_vector_clip_24),_("Clip subtitles to a vectorial area."),wxITEM_RADIO);
|
|
||||||
visualToolBar->AddSeparator();
|
|
||||||
visualToolBar->AddTool(wxID_HELP,_("Help"),cmd::get("help/video")->Icon(24),_("Open the manual page for Visual Typesetting."));
|
|
||||||
visualToolBar->Realize();
|
|
||||||
// Avoid ugly themed background on Vista and possibly also Win7
|
// Avoid ugly themed background on Vista and possibly also Win7
|
||||||
visualToolBar->SetBackgroundStyle(wxBG_STYLE_COLOUR);
|
visualToolBar->SetBackgroundStyle(wxBG_STYLE_COLOUR);
|
||||||
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
|
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
|
||||||
|
|
||||||
// Display
|
|
||||||
videoDisplay = new VideoDisplay(this,isDetached,zoomBox,this,context);
|
videoDisplay = new VideoDisplay(this,isDetached,zoomBox,this,context);
|
||||||
|
|
||||||
// Top sizer
|
// Top sizer
|
||||||
|
|
|
@ -92,14 +92,3 @@ public:
|
||||||
VideoBox(wxWindow *parent, bool isDetached, agi::Context *context);
|
VideoBox(wxWindow *parent, bool isDetached, agi::Context *context);
|
||||||
~VideoBox();
|
~VideoBox();
|
||||||
};
|
};
|
||||||
|
|
||||||
// IDs
|
|
||||||
enum {
|
|
||||||
Video_Mode_Standard = 5000,
|
|
||||||
Video_Mode_Drag,
|
|
||||||
Video_Mode_Rotate_Z,
|
|
||||||
Video_Mode_Rotate_XY,
|
|
||||||
Video_Mode_Scale,
|
|
||||||
Video_Mode_Clip,
|
|
||||||
Video_Mode_Vector_Clip,
|
|
||||||
};
|
|
||||||
|
|
|
@ -266,7 +266,8 @@ void VideoContext::JumpToFrame(int n) {
|
||||||
|
|
||||||
frame_n = mid(0, n, GetLength() - 1);
|
frame_n = mid(0, n, GetLength() - 1);
|
||||||
|
|
||||||
Seek(n);
|
GetFrameAsync(frame_n);
|
||||||
|
Seek(frame_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
|
void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
|
||||||
|
@ -274,11 +275,11 @@ void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::GetFrameAsync(int n) {
|
void VideoContext::GetFrameAsync(int n) {
|
||||||
provider->RequestFrame(n,videoFPS.TimeAtFrame(n)/1000.0);
|
provider->RequestFrame(n, videoFPS.TimeAtFrame(n) / 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tr1::shared_ptr<AegiVideoFrame> VideoContext::GetFrame(int n, bool raw) {
|
std::tr1::shared_ptr<AegiVideoFrame> VideoContext::GetFrame(int n, bool raw) {
|
||||||
return provider->GetFrame(n, videoFPS.TimeAtFrame(n)/1000.0, raw);
|
return provider->GetFrame(n, videoFPS.TimeAtFrame(n) / 1000.0, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
int VideoContext::GetWidth() const {
|
int VideoContext::GetWidth() const {
|
||||||
|
@ -326,10 +327,6 @@ void VideoContext::SaveSnapshot(bool raw) {
|
||||||
GetFrame(frame_n,raw)->GetImage().SaveFile(path,wxBITMAP_TYPE_PNG);
|
GetFrame(frame_n,raw)->GetImage().SaveFile(path,wxBITMAP_TYPE_PNG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoContext::GetScriptSize(int &sw,int &sh) {
|
|
||||||
context->ass->GetResolution(sw,sh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoContext::NextFrame() {
|
void VideoContext::NextFrame() {
|
||||||
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
|
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -232,13 +232,6 @@ public:
|
||||||
/// @param end Type of time
|
/// @param end Type of time
|
||||||
void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START);
|
void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START);
|
||||||
|
|
||||||
/// @brief Get the height and width of the current script
|
|
||||||
/// @param[out] w Width
|
|
||||||
/// @param[out] h Height
|
|
||||||
///
|
|
||||||
/// This probably shouldn't be in VideoContext
|
|
||||||
void GetScriptSize(int &w,int &h);
|
|
||||||
|
|
||||||
/// Starting playing the video
|
/// Starting playing the video
|
||||||
void Play();
|
void Play();
|
||||||
/// Play the next frame then stop
|
/// Play the next frame then stop
|
||||||
|
|
|
@ -56,13 +56,13 @@
|
||||||
#include <GL/glu.h>
|
#include <GL/glu.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "include/aegisub/context.h"
|
|
||||||
#include "include/aegisub/hotkey.h"
|
|
||||||
#include "include/aegisub/menu.h"
|
|
||||||
|
|
||||||
#include "video_display.h"
|
#include "video_display.h"
|
||||||
|
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
|
#include "command/command.h"
|
||||||
|
#include "include/aegisub/context.h"
|
||||||
|
#include "include/aegisub/hotkey.h"
|
||||||
|
#include "include/aegisub/menu.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "threaded_frame_source.h"
|
#include "threaded_frame_source.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -70,13 +70,6 @@
|
||||||
#include "video_box.h"
|
#include "video_box.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "visual_tool.h"
|
#include "visual_tool.h"
|
||||||
#include "visual_tool_clip.h"
|
|
||||||
#include "visual_tool_cross.h"
|
|
||||||
#include "visual_tool_drag.h"
|
|
||||||
#include "visual_tool_rotatexy.h"
|
|
||||||
#include "visual_tool_rotatez.h"
|
|
||||||
#include "visual_tool_scale.h"
|
|
||||||
#include "visual_tool_vector_clip.h"
|
|
||||||
|
|
||||||
/// Attribute list for gl canvases; set the canvases to doublebuffered rgba with an 8 bit stencil buffer
|
/// Attribute list for gl canvases; set the canvases to doublebuffered rgba with an 8 bit stencil buffer
|
||||||
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
|
int attribList[] = { WX_GL_RGBA , WX_GL_DOUBLEBUFFER, WX_GL_STENCIL_SIZE, 8, 0 };
|
||||||
|
@ -104,14 +97,17 @@ VideoDisplay::VideoDisplay(
|
||||||
: wxGLCanvas (parent, -1, attribList, wxDefaultPosition, wxDefaultSize, 0, wxPanelNameStr)
|
: wxGLCanvas (parent, -1, attribList, wxDefaultPosition, wxDefaultSize, 0, wxPanelNameStr)
|
||||||
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
|
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
|
||||||
, con(c)
|
, con(c)
|
||||||
, currentFrame(-1)
|
, w(8)
|
||||||
, w(8), h(8), viewport_x(0), viewport_width(0), viewport_bottom(0), viewport_top(0), viewport_height(0)
|
, h(8)
|
||||||
|
, mouse_pos(Vector2D::Bad())
|
||||||
|
, viewport_left(0)
|
||||||
|
, viewport_width(0)
|
||||||
|
, viewport_bottom(0)
|
||||||
|
, viewport_top(0)
|
||||||
|
, viewport_height(0)
|
||||||
, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125)
|
, zoomValue(OPT_GET("Video/Default Zoom")->GetInt() * .125 + .125)
|
||||||
, videoOut(new VideoOutGL())
|
, videoOut(new VideoOutGL())
|
||||||
, activeMode(Video_Mode_Standard)
|
|
||||||
, toolBar(box->visualSubToolBar)
|
, toolBar(box->visualSubToolBar)
|
||||||
, scriptW(INT_MIN)
|
|
||||||
, scriptH(INT_MIN)
|
|
||||||
, zoomBox(zoomBox)
|
, zoomBox(zoomBox)
|
||||||
, box(box)
|
, box(box)
|
||||||
, freeSize(freeSize)
|
, freeSize(freeSize)
|
||||||
|
@ -120,34 +116,29 @@ VideoDisplay::VideoDisplay(
|
||||||
|
|
||||||
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
||||||
zoomBox->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &VideoDisplay::SetZoomFromBox, this);
|
zoomBox->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &VideoDisplay::SetZoomFromBox, this);
|
||||||
box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VideoDisplay::OnMode, this, Video_Mode_Standard, Video_Mode_Vector_Clip);
|
|
||||||
|
|
||||||
con->videoController->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
|
con->videoController->Bind(EVT_FRAME_READY, &VideoDisplay::UploadFrameData, this);
|
||||||
slots.push_back(con->videoController->AddSeekListener(&VideoDisplay::SetFrame, this));
|
|
||||||
slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this));
|
slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, this));
|
||||||
slots.push_back(con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this));
|
slots.push_back(con->videoController->AddARChangeListener(&VideoDisplay::UpdateSize, this));
|
||||||
slots.push_back(con->ass->AddCommitListener(&VideoDisplay::OnCommit, this));
|
|
||||||
|
|
||||||
Bind(wxEVT_PAINT, std::tr1::bind(&VideoDisplay::Render, this));
|
Bind(wxEVT_PAINT, std::tr1::bind(&VideoDisplay::Render, this));
|
||||||
if (freeSize) {
|
if (freeSize) {
|
||||||
Bind(wxEVT_SIZE, &VideoDisplay::OnSizeEvent, this);
|
Bind(wxEVT_SIZE, &VideoDisplay::OnSizeEvent, this);
|
||||||
}
|
}
|
||||||
Bind(wxEVT_CONTEXT_MENU, &VideoDisplay::OnContextMenu, this);
|
Bind(wxEVT_CONTEXT_MENU, &VideoDisplay::OnContextMenu, this);
|
||||||
|
Bind(wxEVT_ENTER_WINDOW, &VideoDisplay::OnMouseEvent, this);
|
||||||
Bind(wxEVT_KEY_DOWN, &VideoDisplay::OnKeyDown, this);
|
Bind(wxEVT_KEY_DOWN, &VideoDisplay::OnKeyDown, this);
|
||||||
|
Bind(wxEVT_LEAVE_WINDOW, &VideoDisplay::OnMouseLeave, this);
|
||||||
Bind(wxEVT_LEFT_DCLICK, &VideoDisplay::OnMouseEvent, this);
|
Bind(wxEVT_LEFT_DCLICK, &VideoDisplay::OnMouseEvent, this);
|
||||||
Bind(wxEVT_LEFT_DOWN, &VideoDisplay::OnMouseEvent, this);
|
Bind(wxEVT_LEFT_DOWN, &VideoDisplay::OnMouseEvent, this);
|
||||||
Bind(wxEVT_LEFT_UP, &VideoDisplay::OnMouseEvent, this);
|
Bind(wxEVT_LEFT_UP, &VideoDisplay::OnMouseEvent, this);
|
||||||
Bind(wxEVT_MOTION, &VideoDisplay::OnMouseEvent, this);
|
Bind(wxEVT_MOTION, &VideoDisplay::OnMouseEvent, this);
|
||||||
Bind(wxEVT_ENTER_WINDOW, &VideoDisplay::OnMouseEnter, this);
|
|
||||||
Bind(wxEVT_LEAVE_WINDOW, &VideoDisplay::OnMouseLeave, this);
|
|
||||||
Bind(wxEVT_MOUSEWHEEL, &VideoDisplay::OnMouseWheel, this);
|
Bind(wxEVT_MOUSEWHEEL, &VideoDisplay::OnMouseWheel, this);
|
||||||
|
|
||||||
SetCursor(wxNullCursor);
|
SetCursor(wxNullCursor);
|
||||||
|
|
||||||
if (con->videoController->IsLoaded()) {
|
if (con->videoController->IsLoaded())
|
||||||
con->videoController->GetScriptSize(scriptW, scriptH);
|
|
||||||
OnVideoOpen();
|
OnVideoOpen();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDisplay::~VideoDisplay () {
|
VideoDisplay::~VideoDisplay () {
|
||||||
|
@ -163,25 +154,6 @@ bool VideoDisplay::InitContext() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::ShowCursor(bool show) {
|
|
||||||
if (show) {
|
|
||||||
SetCursor(wxNullCursor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SetCursor(wxCursor(wxCURSOR_BLANK));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoDisplay::SetFrame(int frameNumber) {
|
|
||||||
currentFrame = frameNumber;
|
|
||||||
|
|
||||||
// Render the new frame
|
|
||||||
if (con->videoController->IsLoaded()) {
|
|
||||||
tool->SetFrame(frameNumber);
|
|
||||||
con->videoController->GetFrameAsync(currentFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
|
void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
|
||||||
if (!InitContext()) return;
|
if (!InitContext()) return;
|
||||||
|
|
||||||
|
@ -207,16 +179,10 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
|
||||||
|
|
||||||
void VideoDisplay::OnVideoOpen() {
|
void VideoDisplay::OnVideoOpen() {
|
||||||
if (!con->videoController->IsLoaded()) return;
|
if (!con->videoController->IsLoaded()) return;
|
||||||
|
if (!tool.get())
|
||||||
|
cmd::call("video/tool/cross", con);
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
if (!tool.get()) tool.reset(new VisualToolCross(this, con, video, toolBar));
|
con->videoController->JumpToFrame(0);
|
||||||
SetFrame(0);
|
|
||||||
tool->Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoDisplay::OnCommit(int type) {
|
|
||||||
if (type == AssFile::COMMIT_NEW || type & AssFile::COMMIT_SCRIPTINFO)
|
|
||||||
con->videoController->GetScriptSize(scriptW, scriptH);
|
|
||||||
if (tool.get()) tool->Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::Render() try {
|
void VideoDisplay::Render() try {
|
||||||
|
@ -225,7 +191,7 @@ void VideoDisplay::Render() try {
|
||||||
assert(wxIsMainThread());
|
assert(wxIsMainThread());
|
||||||
if (!viewport_height || !viewport_width) UpdateSize();
|
if (!viewport_height || !viewport_width) UpdateSize();
|
||||||
|
|
||||||
videoOut->Render(viewport_x, viewport_bottom, viewport_width, viewport_height);
|
videoOut->Render(viewport_left, viewport_bottom, viewport_width, viewport_height);
|
||||||
E(glViewport(0, std::min(viewport_bottom, 0), w, h));
|
E(glViewport(0, std::min(viewport_bottom, 0), w, h));
|
||||||
|
|
||||||
E(glMatrixMode(GL_PROJECTION));
|
E(glMatrixMode(GL_PROJECTION));
|
||||||
|
@ -238,73 +204,55 @@ void VideoDisplay::Render() try {
|
||||||
// Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
|
// Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
|
||||||
// 16:9 or wider
|
// 16:9 or wider
|
||||||
if (ar > 1.75) {
|
if (ar > 1.75) {
|
||||||
DrawOverscanMask(w * 0.1, h * 0.05, wxColor(30,70,200),0.5);
|
DrawOverscanMask(.1f, .05f);
|
||||||
DrawOverscanMask(w * 0.035, h * 0.035, wxColor(30,70,200),0.5);
|
DrawOverscanMask(0.035f, 0.035f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Less wide than 16:9 (use 4:3 standard)
|
// Less wide than 16:9 (use 4:3 standard)
|
||||||
else {
|
else {
|
||||||
DrawOverscanMask(w * 0.067, h * 0.05, wxColor(30,70,200),0.5);
|
DrawOverscanMask(.067f, .05f);
|
||||||
DrawOverscanMask(w * 0.033, h * 0.035, wxColor(30,70,200),0.5);
|
DrawOverscanMask(0.033f, 0.035f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.x > INT_MIN || video.y > INT_MIN || alwaysShowTools->GetBool()) {
|
if (mouse_pos || alwaysShowTools->GetBool()) {
|
||||||
if (!con->videoController->IsPlaying())
|
if (!con->videoController->IsPlaying())
|
||||||
tool->Draw();
|
tool->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
}
|
}
|
||||||
catch (const VideoOutException &err) {
|
catch (const agi::Exception &err) {
|
||||||
wxLogError(
|
wxLogError(
|
||||||
"An error occurred trying to render the video frame on the screen.\n"
|
"An error occurred trying to render the video frame on the screen.\n"
|
||||||
"Error message reported: %s",
|
"Error message reported: %s",
|
||||||
err.GetMessage());
|
err.GetChainedMessage());
|
||||||
con->videoController->Reset();
|
|
||||||
}
|
|
||||||
catch (const OpenGlException &err) {
|
|
||||||
wxLogError(
|
|
||||||
"An error occurred trying to render visual overlays on the screen.\n"
|
|
||||||
"Error message reported: %s",
|
|
||||||
err.GetMessage());
|
|
||||||
con->videoController->Reset();
|
|
||||||
}
|
|
||||||
catch (const char *err) {
|
|
||||||
wxLogError(
|
|
||||||
"An error occurred trying to render the video frame on the screen.\n"
|
|
||||||
"Error message reported: %s",
|
|
||||||
err);
|
|
||||||
con->videoController->Reset();
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
wxLogError(
|
|
||||||
"An error occurred trying to render the video frame to screen.\n"
|
|
||||||
"No further error message given.");
|
|
||||||
con->videoController->Reset();
|
con->videoController->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const {
|
void VideoDisplay::DrawOverscanMask(float horizontal_percent, float vertical_percent) const {
|
||||||
|
Vector2D size(w * horizontal_percent / 2, h * vertical_percent / 2);
|
||||||
int rad1 = h * 0.05;
|
int rad1 = h * 0.05;
|
||||||
int gapH = sizeH+rad1;
|
Vector2D gap = size + rad1;
|
||||||
int gapV = sizeV+rad1;
|
int rad2 = gap.Len() + 1;
|
||||||
int rad2 = sqrt(double(gapH*gapH + gapV*gapV)) + 1;
|
Vector2D v(w, h);
|
||||||
|
Vector2D igap = v - gap;
|
||||||
|
Vector2D isize = v - size;
|
||||||
|
|
||||||
OpenGLWrapper gl;
|
OpenGLWrapper gl;
|
||||||
E(gl.SetFillColour(color, alpha));
|
gl.SetFillColour(wxColor(30, 70, 200), .5f);
|
||||||
gl.SetLineColour(wxColor(0, 0, 0), 0.0, 1);
|
gl.SetLineColour(*wxBLACK, 0, 1);
|
||||||
|
|
||||||
// Draw sides
|
// Draw sides
|
||||||
E(gl.DrawRectangle(gapH, 0, w-gapH, sizeV)); // Top
|
gl.DrawRectangle(Vector2D(gap, 0), Vector2D(igap, size)); // Top
|
||||||
E(gl.DrawRectangle(w-sizeH, gapV, w, h-gapV)); // Right
|
gl.DrawRectangle(Vector2D(isize, gap), Vector2D(v, igap)); // Right
|
||||||
E(gl.DrawRectangle(gapH, h-sizeV, w-gapH, h)); // Bottom
|
gl.DrawRectangle(Vector2D(gap, isize), Vector2D(igap, v)); // Bottom
|
||||||
E(gl.DrawRectangle(0, gapV, sizeH, h-gapV)); // Left
|
gl.DrawRectangle(Vector2D(0, gap), Vector2D(size, igap)); // Left
|
||||||
|
|
||||||
// Draw rounded corners
|
// Draw rounded corners
|
||||||
E(gl.DrawRing(gapH, gapV, rad1, rad2, 1.0, 180.0, 270.0)); // Top-left
|
gl.DrawRing(gap, rad1, rad2, 1.f, 90.f, 180.f); // Top-left
|
||||||
E(gl.DrawRing(w-gapH, gapV, rad1, rad2, 1.0, 90.0, 180.0)); // Top-right
|
gl.DrawRing(Vector2D(igap, gap), rad1, rad2, 1.f, 0.f, 90.f); // Top-right
|
||||||
E(gl.DrawRing(w-gapH, h-gapV, rad1, rad2, 1.0, 0.0, 90.0)); // Bottom-right
|
gl.DrawRing(v - gap, rad1, rad2, 1.f, 270.f, 360.f); // Bottom-right
|
||||||
E(gl.DrawRing(gapH, h-gapV, rad1, rad2, 1.0,270.0,360.0)); // Bottom-left
|
gl.DrawRing(Vector2D(gap, igap), rad1, rad2, 1.f, 180.f, 270.f); // Bottom-left
|
||||||
|
|
||||||
E(glDisable(GL_BLEND));
|
E(glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
@ -323,7 +271,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
||||||
|
|
||||||
if (freeSize) {
|
if (freeSize) {
|
||||||
GetClientSize(&w,&h);
|
GetClientSize(&w,&h);
|
||||||
viewport_x = 0;
|
viewport_left = 0;
|
||||||
viewport_bottom = 0;
|
viewport_bottom = 0;
|
||||||
viewport_top = 0;
|
viewport_top = 0;
|
||||||
viewport_width = w;
|
viewport_width = w;
|
||||||
|
@ -336,7 +284,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
||||||
// Window is wider than video, blackbox left/right
|
// Window is wider than video, blackbox left/right
|
||||||
if (displayAr - videoAr > 0.01f) {
|
if (displayAr - videoAr > 0.01f) {
|
||||||
int delta = w - videoAr * h;
|
int delta = w - videoAr * h;
|
||||||
viewport_x = delta / 2;
|
viewport_left = delta / 2;
|
||||||
viewport_width = w - delta;
|
viewport_width = w - delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +307,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
||||||
// Cap the canvas size to the window size
|
// Cap the canvas size to the window size
|
||||||
int cw = std::min(w, maxW), ch = std::min(h, maxH);
|
int cw = std::min(w, maxW), ch = std::min(h, maxH);
|
||||||
|
|
||||||
viewport_x = 0;
|
viewport_left = 0;
|
||||||
viewport_bottom = ch - h;
|
viewport_bottom = ch - h;
|
||||||
viewport_top = 0;
|
viewport_top = 0;
|
||||||
viewport_width = w;
|
viewport_width = w;
|
||||||
|
@ -380,11 +328,8 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
||||||
SetEvtHandlerEnabled(true);
|
SetEvtHandlerEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
con->videoController->GetScriptSize(scriptW, scriptH);
|
if (tool.get())
|
||||||
video.w = w;
|
tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
|
||||||
video.h = h;
|
|
||||||
|
|
||||||
if (tool.get()) tool->Refresh();
|
|
||||||
|
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
@ -403,20 +348,13 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
||||||
if (event.ButtonDown())
|
if (event.ButtonDown())
|
||||||
SetFocus();
|
SetFocus();
|
||||||
|
|
||||||
video.x = event.GetX();
|
mouse_pos = event.GetPosition();
|
||||||
video.y = event.GetY();
|
|
||||||
|
|
||||||
tool->OnMouseEvent(event);
|
tool->OnMouseEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::OnMouseEnter(wxMouseEvent& event) {
|
|
||||||
ShowCursor(activeMode != Video_Mode_Standard);
|
|
||||||
tool->OnMouseEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
|
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
|
||||||
video.x = INT_MIN;
|
mouse_pos = Vector2D::Bad();
|
||||||
video.y = INT_MIN;
|
|
||||||
tool->OnMouseEvent(event);
|
tool->OnMouseEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,33 +367,22 @@ void VideoDisplay::OnMouseWheel(wxMouseEvent& event) {
|
||||||
|
|
||||||
void VideoDisplay::OnContextMenu(wxContextMenuEvent&) {
|
void VideoDisplay::OnContextMenu(wxContextMenuEvent&) {
|
||||||
if (!context_menu.get()) context_menu.reset(menu::GetMenu("video_context", con));
|
if (!context_menu.get()) context_menu.reset(menu::GetMenu("video_context", con));
|
||||||
ShowCursor(true);
|
SetCursor(wxNullCursor);
|
||||||
menu::OpenPopupMenu(context_menu.get(), this);
|
menu::OpenPopupMenu(context_menu.get(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::OnKeyDown(wxKeyEvent &event) {
|
void VideoDisplay::OnKeyDown(wxKeyEvent &event) {
|
||||||
/// @todo
|
event.StopPropagation();
|
||||||
int kc = event.GetKeyCode();
|
if (hotkey::check("Video", con, event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
|
||||||
if (kc == 'A') SetMode(Video_Mode_Standard);
|
return;
|
||||||
else if (kc == 'S') SetMode(Video_Mode_Drag);
|
|
||||||
else if (kc == 'D') SetMode(Video_Mode_Rotate_Z);
|
|
||||||
else if (kc == 'F') SetMode(Video_Mode_Rotate_XY);
|
|
||||||
else if (kc == 'G') SetMode(Video_Mode_Scale);
|
|
||||||
else if (kc == 'H') SetMode(Video_Mode_Clip);
|
|
||||||
else if (kc == 'J') SetMode(Video_Mode_Vector_Clip);
|
|
||||||
else {
|
|
||||||
event.StopPropagation();
|
|
||||||
if (hotkey::check("Video Display", con, event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VideoDisplay::SetZoom(double value) {
|
void VideoDisplay::SetZoom(double value) {
|
||||||
zoomValue = std::max(value, .125);
|
zoomValue = std::max(value, .125);
|
||||||
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
|
void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
|
||||||
wxString strValue = zoomBox->GetValue();
|
wxString strValue = zoomBox->GetValue();
|
||||||
strValue.EndsWith("%", &strValue);
|
strValue.EndsWith("%", &strValue);
|
||||||
|
@ -466,57 +393,19 @@ void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
void VideoDisplay::SetTool(VisualToolBase *new_tool) {
|
||||||
void VideoDisplay::SetTool() {
|
|
||||||
tool.reset();
|
|
||||||
tool.reset(new T(this, con, video, toolBar));
|
|
||||||
box->Bind(wxEVT_COMMAND_TOOL_CLICKED, &T::OnSubTool, static_cast<T*>(tool.get()), VISUAL_SUB_TOOL_START, VISUAL_SUB_TOOL_END);
|
|
||||||
}
|
|
||||||
void VideoDisplay::OnMode(const wxCommandEvent &event) {
|
|
||||||
SetMode(event.GetId());
|
|
||||||
}
|
|
||||||
void VideoDisplay::SetMode(int mode) {
|
|
||||||
if (activeMode == mode) return;
|
|
||||||
|
|
||||||
toolBar->ClearTools();
|
toolBar->ClearTools();
|
||||||
toolBar->Realize();
|
toolBar->Realize();
|
||||||
toolBar->Show(false);
|
toolBar->Show(false);
|
||||||
|
|
||||||
if (!box->visualToolBar->GetToolState(mode)) {
|
tool.reset(new_tool);
|
||||||
box->visualToolBar->ToggleTool(mode, true);
|
tool->SetToolbar(toolBar);
|
||||||
}
|
tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
|
||||||
|
|
||||||
activeMode = mode;
|
|
||||||
switch (mode) {
|
|
||||||
case Video_Mode_Standard: SetTool<VisualToolCross>(); break;
|
|
||||||
case Video_Mode_Drag: SetTool<VisualToolDrag>(); break;
|
|
||||||
case Video_Mode_Rotate_Z: SetTool<VisualToolRotateZ>(); break;
|
|
||||||
case Video_Mode_Rotate_XY: SetTool<VisualToolRotateXY>(); break;
|
|
||||||
case Video_Mode_Scale: SetTool<VisualToolScale>(); break;
|
|
||||||
case Video_Mode_Clip: SetTool<VisualToolClip>(); break;
|
|
||||||
case Video_Mode_Vector_Clip: SetTool<VisualToolVectorClip>(); break;
|
|
||||||
default: assert(false); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update size as the new typesetting tool may have changed the subtoolbar size
|
// Update size as the new typesetting tool may have changed the subtoolbar size
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
ShowCursor(activeMode != Video_Mode_Standard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDisplay::ToScriptCoords(int *x, int *y) const {
|
Vector2D VideoDisplay::GetMousePosition() const {
|
||||||
int sx = *x - viewport_x > 0 ? viewport_width : -viewport_width;
|
return mouse_pos ? tool->ToScriptCoords(mouse_pos) : mouse_pos;
|
||||||
int sy = *y - viewport_top > 0 ? viewport_height : -viewport_height;
|
|
||||||
*x = ((*x - viewport_x) * scriptW + sx / 2) / viewport_width;
|
|
||||||
*y = ((*y - viewport_top) * scriptH + sy / 2) / viewport_height;
|
|
||||||
}
|
|
||||||
void VideoDisplay::FromScriptCoords(int *x, int *y) const {
|
|
||||||
int sx = *x > 0 ? scriptW : -scriptW;
|
|
||||||
int sy = *y > 0 ? scriptH : -scriptH;
|
|
||||||
*x = (*x * viewport_width + sx / 2) / scriptW + viewport_x;
|
|
||||||
*y = (*y * viewport_height + sy / 2) / scriptH + viewport_top;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoDisplay::GetMousePosition(int *x, int *y) const {
|
|
||||||
*x = video.x;
|
|
||||||
*y = video.y;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,14 @@
|
||||||
#include <libaegisub/scoped_ptr.h>
|
#include <libaegisub/scoped_ptr.h>
|
||||||
#include <libaegisub/signal.h>
|
#include <libaegisub/signal.h>
|
||||||
|
|
||||||
|
#include "vector2d.h"
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
class FrameReadyEvent;
|
class FrameReadyEvent;
|
||||||
class VideoBox;
|
class VideoBox;
|
||||||
class VideoContext;
|
class VideoContext;
|
||||||
class VideoOutGL;
|
class VideoOutGL;
|
||||||
class IVisualTool;
|
class VisualToolBase;
|
||||||
class wxComboBox;
|
class wxComboBox;
|
||||||
class wxTextCtrl;
|
class wxTextCtrl;
|
||||||
class wxToolBar;
|
class wxToolBar;
|
||||||
|
@ -59,14 +61,6 @@ namespace agi {
|
||||||
class OptionValue;
|
class OptionValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VideoState {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int w;
|
|
||||||
int h;
|
|
||||||
VideoState() : x(INT_MIN), y(INT_MIN), w(INT_MIN), h(INT_MIN) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @class VideoDisplay
|
/// @class VideoDisplay
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
class VideoDisplay : public wxGLCanvas {
|
class VideoDisplay : public wxGLCanvas {
|
||||||
|
@ -87,8 +81,10 @@ class VideoDisplay : public wxGLCanvas {
|
||||||
/// The height of the canvas in screen pixels
|
/// The height of the canvas in screen pixels
|
||||||
int h;
|
int h;
|
||||||
|
|
||||||
|
Vector2D mouse_pos;
|
||||||
|
|
||||||
/// Screen pixels between the left of the canvas and the left of the video
|
/// Screen pixels between the left of the canvas and the left of the video
|
||||||
int viewport_x;
|
int viewport_left;
|
||||||
/// The width of the video in screen pixels
|
/// The width of the video in screen pixels
|
||||||
int viewport_width;
|
int viewport_width;
|
||||||
/// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport
|
/// Screen pixels between the bottom of the canvas and the bottom of the video; used for glViewport
|
||||||
|
@ -105,22 +101,13 @@ class VideoDisplay : public wxGLCanvas {
|
||||||
agi::scoped_ptr<VideoOutGL> videoOut;
|
agi::scoped_ptr<VideoOutGL> videoOut;
|
||||||
|
|
||||||
/// The active visual typesetting tool
|
/// The active visual typesetting tool
|
||||||
agi::scoped_ptr<IVisualTool> tool;
|
agi::scoped_ptr<VisualToolBase> tool;
|
||||||
/// The current tool's ID
|
|
||||||
int activeMode;
|
|
||||||
/// The toolbar used by individual typesetting tools
|
/// The toolbar used by individual typesetting tools
|
||||||
wxToolBar* toolBar;
|
wxToolBar* toolBar;
|
||||||
|
|
||||||
/// The OpenGL context for this display
|
/// The OpenGL context for this display
|
||||||
agi::scoped_ptr<wxGLContext> glContext;
|
agi::scoped_ptr<wxGLContext> glContext;
|
||||||
|
|
||||||
/// The current script width
|
|
||||||
int scriptW;
|
|
||||||
/// The current script height
|
|
||||||
int scriptH;
|
|
||||||
|
|
||||||
VideoState video;
|
|
||||||
|
|
||||||
/// The dropdown box for selecting zoom levels
|
/// The dropdown box for selecting zoom levels
|
||||||
wxComboBox *zoomBox;
|
wxComboBox *zoomBox;
|
||||||
|
|
||||||
|
@ -131,11 +118,9 @@ class VideoDisplay : public wxGLCanvas {
|
||||||
bool freeSize;
|
bool freeSize;
|
||||||
|
|
||||||
/// @brief Draw an overscan mask
|
/// @brief Draw an overscan mask
|
||||||
/// @param sizeH The amount of horizontal overscan on one side
|
/// @param horizontal_percent The percent of the video reserved horizontally
|
||||||
/// @param sizeV The amount of vertical overscan on one side
|
/// @param vertical_percent The percent of the video reserved vertically
|
||||||
/// @param colour The color of the mask
|
void DrawOverscanMask(float horizontal_percent, float vertical_percent) const;
|
||||||
/// @param alpha The alpha of the mask
|
|
||||||
void DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const;
|
|
||||||
|
|
||||||
/// Upload the image for the current frame to the video card
|
/// Upload the image for the current frame to the video card
|
||||||
void UploadFrameData(FrameReadyEvent&);
|
void UploadFrameData(FrameReadyEvent&);
|
||||||
|
@ -144,21 +129,8 @@ class VideoDisplay : public wxGLCanvas {
|
||||||
/// @return Could the context be set?
|
/// @return Could the context be set?
|
||||||
bool InitContext();
|
bool InitContext();
|
||||||
|
|
||||||
/// @brief Set this video display to the given frame
|
|
||||||
/// @frameNumber The desired frame number
|
|
||||||
void SetFrame(int frameNumber);
|
|
||||||
|
|
||||||
void OnVideoOpen();
|
void OnVideoOpen();
|
||||||
void OnCommit(int type);
|
|
||||||
|
|
||||||
void SetMode(int mode);
|
|
||||||
/// @brief Switch the active tool to a new object of the specified class
|
|
||||||
/// @param T The class of the new visual typesetting tool
|
|
||||||
template <class T> void SetTool();
|
|
||||||
|
|
||||||
/// @brief Set the cursor to either default or blank
|
|
||||||
/// @param show Whether or not the cursor should be visible
|
|
||||||
void ShowCursor(bool show);
|
|
||||||
/// @brief Set the size of the display based on the current zoom and video resolution
|
/// @brief Set the size of the display based on the current zoom and video resolution
|
||||||
void UpdateSize(int arType = -1, double arValue = -1.);
|
void UpdateSize(int arType = -1, double arValue = -1.);
|
||||||
/// @brief Set the zoom level to that indicated by the dropdown
|
/// @brief Set the zoom level to that indicated by the dropdown
|
||||||
|
@ -169,11 +141,9 @@ class VideoDisplay : public wxGLCanvas {
|
||||||
/// @brief Mouse event handler
|
/// @brief Mouse event handler
|
||||||
void OnMouseEvent(wxMouseEvent& event);
|
void OnMouseEvent(wxMouseEvent& event);
|
||||||
void OnMouseWheel(wxMouseEvent& event);
|
void OnMouseWheel(wxMouseEvent& event);
|
||||||
void OnMouseEnter(wxMouseEvent& event);
|
|
||||||
void OnMouseLeave(wxMouseEvent& event);
|
void OnMouseLeave(wxMouseEvent& event);
|
||||||
/// @brief Recalculate video positioning and scaling when the available area or zoom changes
|
/// @brief Recalculate video positioning and scaling when the available area or zoom changes
|
||||||
void OnSizeEvent(wxSizeEvent &event);
|
void OnSizeEvent(wxSizeEvent &event);
|
||||||
void OnMode(const wxCommandEvent &event);
|
|
||||||
void OnContextMenu(wxContextMenuEvent&);
|
void OnContextMenu(wxContextMenuEvent&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -195,17 +165,8 @@ public:
|
||||||
/// @brief Get the current zoom level
|
/// @brief Get the current zoom level
|
||||||
double GetZoom() const { return zoomValue; }
|
double GetZoom() const { return zoomValue; }
|
||||||
|
|
||||||
/// @brief Convert a point from screen to script coordinate frame
|
/// Get the last seen position of the mouse in script coordinates
|
||||||
/// @param x x coordinate; in/out
|
Vector2D GetMousePosition() const;
|
||||||
/// @param y y coordinate; in/out
|
|
||||||
void ToScriptCoords(int *x, int *y) const;
|
|
||||||
/// @brief Convert a point from script to screen coordinate frame
|
|
||||||
/// @param x x coordinate; in/out
|
|
||||||
/// @param y y coordinate; in/out
|
|
||||||
void FromScriptCoords(int *x, int *y) const;
|
|
||||||
|
|
||||||
/// Get the last seen position of the mouse in screen coordinates
|
void SetTool(VisualToolBase *new_tool);
|
||||||
/// @param[out] x x coordinate
|
|
||||||
/// @param[out] y y coordinate
|
|
||||||
void GetMousePosition(int *x, int *y) const;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,69 +40,89 @@
|
||||||
#include "visual_feature.h"
|
#include "visual_feature.h"
|
||||||
|
|
||||||
VisualDraggableFeature::VisualDraggableFeature()
|
VisualDraggableFeature::VisualDraggableFeature()
|
||||||
: type(DRAG_NONE)
|
: start(Vector2D::Bad())
|
||||||
, x(INT_MIN)
|
, type(DRAG_NONE)
|
||||||
, y(INT_MIN)
|
, pos(Vector2D::Bad())
|
||||||
, origX(INT_MIN)
|
|
||||||
, origY(INT_MIN)
|
|
||||||
, layer(0)
|
, layer(0)
|
||||||
, line(NULL)
|
, line(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualDraggableFeature::IsMouseOver(int mx,int my) const {
|
bool VisualDraggableFeature::IsMouseOver(Vector2D mouse_pos) const {
|
||||||
|
if (!pos) return false;
|
||||||
|
|
||||||
|
Vector2D delta = mouse_pos - pos;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DRAG_BIG_SQUARE:
|
case DRAG_BIG_SQUARE:
|
||||||
return !(mx < x-8 || mx > x+8 || my < y-8 || my > y+8);
|
return fabs(delta.X()) < 8 && fabs(delta.Y()) < 8;
|
||||||
case DRAG_BIG_CIRCLE: {
|
|
||||||
int dx = mx-x;
|
case DRAG_BIG_CIRCLE:
|
||||||
int dy = my-y;
|
return delta.SquareLen() < 64;
|
||||||
return dx*dx + dy*dy <= 64;
|
|
||||||
}
|
|
||||||
case DRAG_BIG_TRIANGLE: {
|
case DRAG_BIG_TRIANGLE: {
|
||||||
int _my = my+2;
|
if (delta.Y() < -10 || delta.Y() > 6) return false;
|
||||||
if (_my < y-8 || _my > y+8) return false;
|
float dy = delta.Y() - 6;
|
||||||
int dx = mx-x;
|
return 16 * delta.X() + 9 * dy < 0 && 16 * delta.X() - 9 * dy > 0;
|
||||||
int dy = _my-y-8;
|
|
||||||
return (16*dx+9*dy < 0 && 16*dx-9*dy > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case DRAG_SMALL_SQUARE:
|
case DRAG_SMALL_SQUARE:
|
||||||
return !(mx < x-4 || mx > x+4 || my < y-4 || my > y+4);
|
return fabs(delta.X()) < 4 && fabs(delta.Y()) < 4;
|
||||||
case DRAG_SMALL_CIRCLE: {
|
|
||||||
int dx = mx-x;
|
case DRAG_SMALL_CIRCLE:
|
||||||
int dy = my-y;
|
return delta.SquareLen() < 16;
|
||||||
return dx*dx + dy*dy <= 16;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualDraggableFeature::Draw(OpenGLWrapper const& gl) const {
|
void VisualDraggableFeature::Draw(OpenGLWrapper const& gl) const {
|
||||||
|
if (!pos) return;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DRAG_BIG_SQUARE:
|
case DRAG_BIG_SQUARE:
|
||||||
gl.DrawRectangle(x-8,y-8,x+8,y+8);
|
gl.DrawRectangle(pos - 8, pos + 8);
|
||||||
gl.DrawLine(x,y-16,x,y+16);
|
gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
|
||||||
gl.DrawLine(x-16,y,x+16,y);
|
gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAG_BIG_CIRCLE:
|
case DRAG_BIG_CIRCLE:
|
||||||
gl.DrawCircle(x,y,8);
|
gl.DrawCircle(pos, 8);
|
||||||
gl.DrawLine(x,y-16,x,y+16);
|
gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
|
||||||
gl.DrawLine(x-16,y,x+16,y);
|
gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAG_BIG_TRIANGLE:
|
case DRAG_BIG_TRIANGLE:
|
||||||
gl.DrawTriangle(x-9,y-6,x+9,y-6,x,y+10);
|
gl.DrawTriangle(pos - Vector2D(9, 6), pos + Vector2D(9, -6), pos + Vector2D(0, 10));
|
||||||
gl.DrawLine(x,y,x,y-16);
|
gl.DrawLine(pos, pos + Vector2D(0, -16));
|
||||||
gl.DrawLine(x,y,x-14,y+8);
|
gl.DrawLine(pos, pos + Vector2D(-14, 8));
|
||||||
gl.DrawLine(x,y,x+14,y+8);
|
gl.DrawLine(pos, pos + Vector2D(14, 8));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAG_SMALL_SQUARE:
|
case DRAG_SMALL_SQUARE:
|
||||||
gl.DrawRectangle(x-4,y-4,x+4,y+4);
|
gl.DrawRectangle(pos - 4, pos + 4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAG_SMALL_CIRCLE:
|
case DRAG_SMALL_CIRCLE:
|
||||||
gl.DrawCircle(x,y,4);
|
gl.DrawCircle(pos, 4);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisualDraggableFeature::StartDrag() {
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualDraggableFeature::UpdateDrag(Vector2D d, bool single_axis) {
|
||||||
|
if (single_axis)
|
||||||
|
d = d.SingleAxis();
|
||||||
|
|
||||||
|
pos = start + d;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisualDraggableFeature::HasMoved() const {
|
||||||
|
return pos != start;
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "vector2d.h"
|
||||||
|
|
||||||
class OpenGLWrapper;
|
class OpenGLWrapper;
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
|
|
||||||
|
@ -65,6 +67,8 @@ enum DraggableFeatureType {
|
||||||
/// @class VisualDraggableFeature
|
/// @class VisualDraggableFeature
|
||||||
/// @brief Onscreen control used by many visual tools which doesn't do much
|
/// @brief Onscreen control used by many visual tools which doesn't do much
|
||||||
class VisualDraggableFeature {
|
class VisualDraggableFeature {
|
||||||
|
Vector2D start; ///< position before the last operation began
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
VisualDraggableFeature();
|
VisualDraggableFeature();
|
||||||
|
@ -72,21 +76,23 @@ public:
|
||||||
/// Shape of feature
|
/// Shape of feature
|
||||||
DraggableFeatureType type;
|
DraggableFeatureType type;
|
||||||
|
|
||||||
int x; /// x coordinate
|
Vector2D pos;
|
||||||
int y; /// y coordinate
|
|
||||||
|
|
||||||
int origX; /// x coordindate before the last operation began
|
|
||||||
int origY; /// y coordindate before the last operation began
|
|
||||||
|
|
||||||
int layer; /// Layer; Higher = above
|
int layer; /// Layer; Higher = above
|
||||||
|
|
||||||
AssDialogue* line; /// The dialogue line this feature is for
|
AssDialogue* line; /// The dialogue line this feature is for
|
||||||
|
|
||||||
/// @brief Is the given point over this feature?
|
/// @brief Is the given point over this feature?
|
||||||
/// @param mx x coordinate to test
|
/// @param mouse_pos Position of the mouse
|
||||||
/// @param my y coordinate to test
|
bool IsMouseOver(Vector2D mouse_pos) const;
|
||||||
bool IsMouseOver(int x,int y) const;
|
|
||||||
/// @brief Draw this feature
|
/// @brief Draw this feature
|
||||||
/// @param gl OpenGLWrapper to use
|
/// @param gl OpenGLWrapper to use
|
||||||
void Draw(OpenGLWrapper const& gl) const;
|
void Draw(OpenGLWrapper const& gl) const;
|
||||||
|
|
||||||
|
void StartDrag();
|
||||||
|
|
||||||
|
void UpdateDrag(Vector2D d, bool single_axis);
|
||||||
|
|
||||||
|
bool HasMoved() const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -40,6 +27,8 @@
|
||||||
#include <wx/glcanvas.h>
|
#include <wx/glcanvas.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "visual_tool.h"
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
|
@ -47,133 +36,219 @@
|
||||||
#include "ass_time.h"
|
#include "ass_time.h"
|
||||||
#include "include/aegisub/context.h"
|
#include "include/aegisub/context.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "subs_grid.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
#include "video_display.h"
|
||||||
#include "video_provider_manager.h"
|
#include "video_provider_manager.h"
|
||||||
#include "visual_feature.h"
|
#include "visual_feature.h"
|
||||||
#include "visual_tool.h"
|
|
||||||
#include "visual_tool_clip.h"
|
#include "visual_tool_clip.h"
|
||||||
#include "visual_tool_drag.h"
|
#include "visual_tool_drag.h"
|
||||||
#include "visual_tool_vector_clip.h"
|
#include "visual_tool_vector_clip.h"
|
||||||
|
|
||||||
const wxColour IVisualTool::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
|
template<class C, class F>
|
||||||
|
static void for_each(C &range, F func) {
|
||||||
|
std::for_each(range.begin(), range.end(), func);
|
||||||
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
using std::tr1::placeholders::_1;
|
||||||
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, agi::Context *context, VideoState const& video)
|
|
||||||
: dragStartX(0)
|
const wxColour VisualToolBase::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
|
||||||
, dragStartY(0)
|
|
||||||
, commitId(-1)
|
VisualToolBase::VisualToolBase(VideoDisplay *parent, agi::Context *context)
|
||||||
, selChanged(false)
|
: c(context)
|
||||||
, selectedFeatures(selFeatures)
|
|
||||||
, c(context)
|
|
||||||
, parent(parent)
|
, parent(parent)
|
||||||
, holding(false)
|
, holding(false)
|
||||||
|
, active_line(0)
|
||||||
, dragging(false)
|
, dragging(false)
|
||||||
, externalChange(true)
|
, frame_number(c->videoController->GetFrameN())
|
||||||
, video(video)
|
, left_click(false)
|
||||||
, leftClick(false)
|
, left_double(false)
|
||||||
, leftDClick(false)
|
, shift_down(false)
|
||||||
, shiftDown(false)
|
, ctrl_down(false)
|
||||||
, ctrlDown(false)
|
, alt_down(false)
|
||||||
, altDown(false)
|
, file_changed_connection(c->ass->AddCommitListener(&VisualToolBase::OnCommit, this))
|
||||||
|
, commit_id(-1)
|
||||||
{
|
{
|
||||||
frameNumber = c->videoController->GetFrameN();
|
int script_w, script_h;
|
||||||
curDiag = GetActiveDialogueLine();
|
c->ass->GetResolution(script_w, script_h);
|
||||||
|
script_res = Vector2D(script_w, script_h);
|
||||||
|
active_line = GetActiveDialogueLine();
|
||||||
c->selectionController->AddSelectionListener(this);
|
c->selectionController->AddSelectionListener(this);
|
||||||
curFeature = features.begin();
|
connections.push_back(c->videoController->AddSeekListener(&VisualToolBase::OnSeek, this));
|
||||||
|
parent->Bind(wxEVT_MOUSE_CAPTURE_LOST, &VisualToolBase::OnMouseCaptureLost, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualToolBase::~VisualToolBase() {
|
||||||
|
c->selectionController->RemoveSelectionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::OnCommit(int type) {
|
||||||
|
holding = false;
|
||||||
|
dragging = false;
|
||||||
|
|
||||||
|
if (type & AssFile::COMMIT_NEW || type & AssFile::COMMIT_SCRIPTINFO) {
|
||||||
|
int script_w, script_h;
|
||||||
|
c->ass->GetResolution(script_w, script_h);
|
||||||
|
script_res = Vector2D(script_w, script_h);
|
||||||
|
OnCoordinateSystemsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & AssFile::COMMIT_DIAG_FULL || type & AssFile::COMMIT_DIAG_ADDREM) {
|
||||||
|
active_line = GetActiveDialogueLine();
|
||||||
|
OnFileChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::OnSeek(int new_frame) {
|
||||||
|
if (frame_number == new_frame) return;
|
||||||
|
|
||||||
|
frame_number = new_frame;
|
||||||
|
dragging = false;
|
||||||
|
OnFrameChanged();
|
||||||
|
|
||||||
|
AssDialogue *new_line = GetActiveDialogueLine();
|
||||||
|
if (new_line != active_line) {
|
||||||
|
active_line = new_line;
|
||||||
|
OnLineChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::OnMouseCaptureLost(wxMouseCaptureLostEvent &) {
|
||||||
|
holding = false;
|
||||||
|
dragging = false;
|
||||||
|
left_click = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::OnActiveLineChanged(AssDialogue *new_line) {
|
||||||
|
if (!IsDisplayed(new_line))
|
||||||
|
new_line = 0;
|
||||||
|
|
||||||
|
holding = false;
|
||||||
|
dragging = false;
|
||||||
|
if (new_line != active_line) {
|
||||||
|
active_line = new_line;
|
||||||
|
OnLineChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisualToolBase::IsDisplayed(AssDialogue *line) const {
|
||||||
|
int frame = c->videoController->GetFrameN();
|
||||||
|
return
|
||||||
|
line &&
|
||||||
|
c->videoController->FrameAtTime(line->Start.GetMS(), agi::vfr::START) <= frame &&
|
||||||
|
c->videoController->FrameAtTime(line->End.GetMS(), agi::vfr::END) >= frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::Commit(wxString message) {
|
||||||
|
file_changed_connection.Block();
|
||||||
|
if (message.empty())
|
||||||
|
message = _("visual typesetting");
|
||||||
|
|
||||||
|
commit_id = c->ass->Commit(message, AssFile::COMMIT_DIAG_TEXT, commit_id);
|
||||||
|
file_changed_connection.Unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
AssDialogue* VisualToolBase::GetActiveDialogueLine() {
|
||||||
|
AssDialogue *diag = c->selectionController->GetActiveLine();
|
||||||
|
if (IsDisplayed(diag))
|
||||||
|
return diag;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::SetDisplayArea(int x, int y, int w, int h) {
|
||||||
|
video_pos = Vector2D(x, y);
|
||||||
|
video_res = Vector2D(w, h);
|
||||||
|
|
||||||
|
holding = false;
|
||||||
|
dragging = false;
|
||||||
|
OnCoordinateSystemsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D VisualToolBase::ToScriptCoords(Vector2D point) const {
|
||||||
|
return (point - video_pos) * script_res / video_res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D VisualToolBase::FromScriptCoords(Vector2D point) const {
|
||||||
|
return (point * video_res / script_res) + video_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
template<class FeatureType>
|
||||||
VisualTool<FeatureType>::~VisualTool() {
|
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, agi::Context *context)
|
||||||
c->selectionController->RemoveSelectionListener(this);
|
: VisualToolBase(parent, context)
|
||||||
|
, sel_changed(false)
|
||||||
|
{
|
||||||
|
active_feature = features.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
template<class FeatureType>
|
||||||
void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
||||||
bool needRender = false;
|
left_click = event.LeftDown();
|
||||||
|
left_double = event.LeftDClick();
|
||||||
|
shift_down = event.ShiftDown();
|
||||||
|
ctrl_down = event.CmdDown();
|
||||||
|
alt_down = event.AltDown();
|
||||||
|
|
||||||
|
mouse_pos = event.GetPosition();
|
||||||
|
|
||||||
|
bool need_render = false;
|
||||||
|
|
||||||
if (event.Leaving()) {
|
if (event.Leaving()) {
|
||||||
Update();
|
mouse_pos = Vector2D::Bad();
|
||||||
parent->Render();
|
parent->Render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool()) {
|
|
||||||
needRender = true;
|
|
||||||
}
|
|
||||||
externalChange = false;
|
|
||||||
|
|
||||||
leftClick = event.ButtonDown(wxMOUSE_BTN_LEFT);
|
if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool())
|
||||||
leftDClick = event.LeftDClick();
|
need_render = true;
|
||||||
shiftDown = event.m_shiftDown;
|
|
||||||
#ifdef __APPLE__
|
|
||||||
ctrlDown = event.m_metaDown; // Cmd key
|
|
||||||
#else
|
|
||||||
ctrlDown = event.m_controlDown;
|
|
||||||
#endif
|
|
||||||
altDown = event.m_altDown;
|
|
||||||
|
|
||||||
if (!dragging) {
|
if (!dragging) {
|
||||||
feature_iterator oldHigh = curFeature;
|
feature_iterator prev_feature = active_feature;
|
||||||
GetHighlightedFeature();
|
|
||||||
if (curFeature != oldHigh) needRender = true;
|
int max_layer = INT_MIN;
|
||||||
|
active_feature = features.end();
|
||||||
|
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||||
|
if (cur->IsMouseOver(mouse_pos) && cur->layer >= max_layer) {
|
||||||
|
active_feature = cur;
|
||||||
|
max_layer = cur->layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
need_render |= active_feature != prev_feature;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
// continue drag
|
// continue drag
|
||||||
if (event.LeftIsDown()) {
|
if (event.LeftIsDown()) {
|
||||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
for_each(sel_features, bind(&FeatureType::UpdateDrag, _1,
|
||||||
(*cur)->x = (video.x - dragStartX + (*cur)->origX);
|
mouse_pos - drag_start, shift_down));
|
||||||
(*cur)->y = (video.y - dragStartY + (*cur)->origY);
|
for_each(sel_features, bind(&VisualTool<FeatureType>::UpdateDrag, this, _1));
|
||||||
if (shiftDown) {
|
|
||||||
if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) {
|
|
||||||
(*cur)->y = (*cur)->origY;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
(*cur)->x = (*cur)->origX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateDrag(*cur);
|
|
||||||
CommitDrag(*cur);
|
|
||||||
}
|
|
||||||
Commit();
|
Commit();
|
||||||
needRender = true;
|
need_render = true;
|
||||||
}
|
}
|
||||||
// end drag
|
// end drag
|
||||||
else {
|
else {
|
||||||
dragging = false;
|
dragging = false;
|
||||||
|
|
||||||
// mouse didn't move, fiddle with selection
|
// mouse didn't move, fiddle with selection
|
||||||
if (curFeature->x == curFeature->origX && curFeature->y == curFeature->origY) {
|
if (active_feature != features.end() && !active_feature->HasMoved()) {
|
||||||
// Don't deselect stuff that was selected in this click's mousedown event
|
// Don't deselect stuff that was selected in this click's mousedown event
|
||||||
if (!selChanged) {
|
if (!sel_changed) {
|
||||||
if (ctrlDown) {
|
if (ctrl_down)
|
||||||
// deselect this feature
|
RemoveSelection(active_feature);
|
||||||
RemoveSelection(curFeature);
|
else
|
||||||
}
|
SetSelection(active_feature, true);
|
||||||
else {
|
|
||||||
SetSelection(curFeature);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
|
||||||
CommitDrag(*cur);
|
|
||||||
}
|
|
||||||
Commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
curFeature = features.end();
|
active_feature = features.end();
|
||||||
parent->ReleaseMouse();
|
parent->ReleaseMouse();
|
||||||
parent->SetFocus();
|
parent->SetFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (holding) {
|
else if (holding) {
|
||||||
// continue hold
|
|
||||||
if (event.LeftIsDown()) {
|
if (event.LeftIsDown()) {
|
||||||
UpdateHold();
|
UpdateHold();
|
||||||
needRender = true;
|
need_render = true;
|
||||||
}
|
}
|
||||||
// end hold
|
// end hold
|
||||||
else {
|
else {
|
||||||
|
@ -182,422 +257,318 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
||||||
parent->ReleaseMouse();
|
parent->ReleaseMouse();
|
||||||
parent->SetFocus();
|
parent->SetFocus();
|
||||||
}
|
}
|
||||||
CommitHold();
|
|
||||||
Commit();
|
Commit();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (leftClick) {
|
else if (left_click) {
|
||||||
|
drag_start = mouse_pos;
|
||||||
|
|
||||||
// start drag
|
// start drag
|
||||||
if (curFeature != features.end()) {
|
if (active_feature != features.end()) {
|
||||||
if (selFeatures.find(curFeature) == selFeatures.end()) {
|
if (!sel_features.count(active_feature)) {
|
||||||
selChanged = true;
|
sel_changed = true;
|
||||||
if (ctrlDown) {
|
SetSelection(active_feature, !ctrl_down);
|
||||||
AddSelection(curFeature);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SetSelection(curFeature);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
selChanged = false;
|
sel_changed = false;
|
||||||
}
|
|
||||||
if (curFeature->line) c->selectionController->SetActiveLine(curFeature->line);
|
|
||||||
|
|
||||||
if (InitializeDrag(curFeature)) {
|
if (active_feature->line)
|
||||||
dragStartX = video.x;
|
c->selectionController->SetActiveLine(active_feature->line);
|
||||||
dragStartY = video.y;
|
|
||||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
|
||||||
(*cur)->origX = (*cur)->x;
|
|
||||||
(*cur)->origY = (*cur)->y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (InitializeDrag(active_feature)) {
|
||||||
|
for_each(sel_features, bind(&VisualDraggableFeature::StartDrag, _1));
|
||||||
dragging = true;
|
dragging = true;
|
||||||
parent->CaptureMouse();
|
parent->CaptureMouse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// start hold
|
// start hold
|
||||||
else {
|
else {
|
||||||
if (!altDown) {
|
if (!alt_down) {
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
Selection sel;
|
Selection sel;
|
||||||
sel.insert(c->selectionController->GetActiveLine());
|
sel.insert(c->selectionController->GetActiveLine());
|
||||||
c->selectionController->SetSelectedSet(sel);
|
c->selectionController->SetSelectedSet(sel);
|
||||||
needRender = true;
|
need_render = true;
|
||||||
}
|
}
|
||||||
if (curDiag && InitializeHold()) {
|
if (active_line && InitializeHold()) {
|
||||||
holding = true;
|
holding = true;
|
||||||
parent->CaptureMouse();
|
parent->CaptureMouse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Update() || needRender) parent->Render();
|
if (active_line && left_double)
|
||||||
externalChange = true;
|
OnDoubleClick();
|
||||||
|
|
||||||
if (!event.LeftIsDown()) {
|
//if (need_render)
|
||||||
// Only coalesce the changes made in a single drag
|
parent->Render();
|
||||||
commitId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FeatureType>
|
// Only coalesce the changes made in a single drag
|
||||||
void VisualTool<FeatureType>::Commit(wxString message) {
|
if (!event.LeftIsDown())
|
||||||
externalChange = false;
|
commit_id = -1;
|
||||||
if (message.empty()) {
|
|
||||||
message = _("visual typesetting");
|
|
||||||
}
|
|
||||||
commitId = c->ass->Commit(message, AssFile::COMMIT_DIAG_TEXT, commitId);
|
|
||||||
externalChange = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
AssDialogue* VisualTool<FeatureType>::GetActiveDialogueLine() {
|
|
||||||
AssDialogue *diag = c->selectionController->GetActiveLine();
|
|
||||||
if (diag && c->subsGrid->IsDisplayed(diag))
|
|
||||||
return diag;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
void VisualTool<FeatureType>::GetHighlightedFeature() {
|
|
||||||
int highestLayerFound = INT_MIN;
|
|
||||||
curFeature = features.end();
|
|
||||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
|
||||||
if (cur->IsMouseOver(video.x, video.y) && cur->layer > highestLayerFound) {
|
|
||||||
curFeature = cur;
|
|
||||||
highestLayerFound = cur->layer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
template<class FeatureType>
|
||||||
void VisualTool<FeatureType>::DrawAllFeatures() {
|
void VisualTool<FeatureType>::DrawAllFeatures() {
|
||||||
SetLineColour(colour[0],1.0f,2);
|
gl.SetLineColour(colour[0], 1.0f, 2);
|
||||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||||
int fill;
|
int fill = 1;
|
||||||
if (cur == curFeature)
|
if (cur == active_feature)
|
||||||
fill = 2;
|
fill = 2;
|
||||||
else if (selFeatures.find(cur) != selFeatures.end())
|
else if (sel_features.count(cur))
|
||||||
fill = 3;
|
fill = 3;
|
||||||
else
|
gl.SetFillColour(colour[fill], 0.6f);
|
||||||
fill = 1;
|
cur->Draw(gl);
|
||||||
SetFillColour(colour[fill],0.6f);
|
|
||||||
cur->Draw(*this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
template<class FeatureType>
|
||||||
void VisualTool<FeatureType>::Refresh() {
|
void VisualTool<FeatureType>::SetSelection(feature_iterator feat, bool clear) {
|
||||||
if (externalChange) {
|
if (clear)
|
||||||
curDiag = GetActiveDialogueLine();
|
sel_features.clear();
|
||||||
curFeature = features.end();
|
|
||||||
OnFileChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
void VisualTool<FeatureType>::SetFrame(int newFrameNumber) {
|
|
||||||
if (frameNumber == newFrameNumber) return;
|
|
||||||
frameNumber = newFrameNumber;
|
|
||||||
curFeature = features.end();
|
|
||||||
OnFrameChanged();
|
|
||||||
AssDialogue *newCurDiag = GetActiveDialogueLine();
|
|
||||||
if (newCurDiag != curDiag) {
|
|
||||||
curDiag = newCurDiag;
|
|
||||||
OnLineChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
void VisualTool<FeatureType>::OnActiveLineChanged(AssDialogue *new_line) {
|
|
||||||
if (new_line && !c->subsGrid->IsDisplayed(new_line)) {
|
|
||||||
new_line = NULL;
|
|
||||||
}
|
|
||||||
if (new_line != curDiag) {
|
|
||||||
curDiag = new_line;
|
|
||||||
OnLineChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
void VisualTool<FeatureType>::SetSelection(feature_iterator feat) {
|
|
||||||
selFeatures.clear();
|
|
||||||
lineSelCount.clear();
|
|
||||||
|
|
||||||
selFeatures.insert(feat);
|
|
||||||
|
|
||||||
AssDialogue *line = feat->line;
|
|
||||||
if (line) {
|
|
||||||
lineSelCount[line] = 1;
|
|
||||||
|
|
||||||
|
if (sel_features.insert(feat).second && feat->line) {
|
||||||
Selection sel;
|
Selection sel;
|
||||||
sel.insert(line);
|
if (!clear)
|
||||||
c->selectionController->SetSelectedSet(sel);
|
sel = c->selectionController->GetSelectedSet();
|
||||||
}
|
if (sel.insert(feat->line).second)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class FeatureType>
|
|
||||||
void VisualTool<FeatureType>::AddSelection(feature_iterator feat) {
|
|
||||||
if (selFeatures.insert(feat).second && feat->line) {
|
|
||||||
lineSelCount[feat->line] += 1;
|
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
|
||||||
if (sel.insert(feat->line).second) {
|
|
||||||
c->selectionController->SetSelectedSet(sel);
|
c->selectionController->SetSelectedSet(sel);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
template<class FeatureType>
|
||||||
void VisualTool<FeatureType>::RemoveSelection(feature_iterator feat) {
|
void VisualTool<FeatureType>::RemoveSelection(feature_iterator feat) {
|
||||||
if (selFeatures.erase(feat) > 0 && feat->line) {
|
if (!sel_features.erase(feat) || !feat->line) return;
|
||||||
// Deselect a line only if all features for that line have been
|
|
||||||
// deselected
|
|
||||||
AssDialogue* line = feat->line;
|
|
||||||
lineSelCount[line] -= 1;
|
|
||||||
assert(lineSelCount[line] >= 0);
|
|
||||||
if (lineSelCount[line] <= 0) {
|
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
|
||||||
|
|
||||||
// Don't deselect the only selected line
|
for (selection_iterator it = sel_features.begin(); it != sel_features.end(); ++it) {
|
||||||
if (sel.size() <= 1) return;
|
if ((*it)->line == feat->line) return;
|
||||||
|
|
||||||
sel.erase(line);
|
|
||||||
|
|
||||||
// Set the active line to an arbitrary selected line if we just
|
|
||||||
// deselected the active line
|
|
||||||
if (line == c->selectionController->GetActiveLine()) {
|
|
||||||
c->selectionController->SetActiveLine(*sel.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
c->selectionController->SetSelectedSet(sel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Selection sel = c->selectionController->GetSelectedSet();
|
||||||
|
|
||||||
|
// Don't deselect the only selected line
|
||||||
|
if (sel.size() <= 1) return;
|
||||||
|
|
||||||
|
sel.erase(feat->line);
|
||||||
|
|
||||||
|
// Set the active line to an arbitrary selected line if we just
|
||||||
|
// deselected the active line
|
||||||
|
if (feat->line == c->selectionController->GetActiveLine()) {
|
||||||
|
c->selectionController->SetActiveLine(*sel.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
c->selectionController->SetSelectedSet(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
//////// PARSERS
|
||||||
void VisualTool<FeatureType>::ClearSelection() {
|
|
||||||
selFeatures.clear();
|
|
||||||
lineSelCount.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TagFoundType {
|
typedef const std::vector<AssOverrideParameter*> * param_vec;
|
||||||
TAG_NOT_FOUND = 0,
|
|
||||||
PRIMARY_TAG_FOUND,
|
// Parse line on creation and unparse at the end of scope
|
||||||
ALT_TAG_FOUND
|
struct scoped_tag_parse {
|
||||||
|
AssDialogue *diag;
|
||||||
|
scoped_tag_parse(AssDialogue *diag) : diag(diag) { diag->ParseASSTags(); }
|
||||||
|
~scoped_tag_parse() { diag->ClearBlocks(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Get the first value set for a tag
|
// Find a tag's parameters in a line or return NULL if it's not found
|
||||||
/// @param line Line to get the value from
|
static param_vec find_tag(const AssDialogue *line, wxString tag_name) {
|
||||||
/// @param tag Tag to get the value of
|
for (size_t i = 0; i < line->Blocks.size(); ++i) {
|
||||||
/// @param n Number of parameters passed
|
|
||||||
/// @return Which tag (if any) was found
|
|
||||||
template<class T>
|
|
||||||
static TagFoundType get_value(const AssDialogue *line, wxString tag, size_t n, ...) {
|
|
||||||
wxString alt;
|
|
||||||
if (tag == "\\pos") alt = "\\move";
|
|
||||||
else if (tag == "\\an") alt = "\\a";
|
|
||||||
else if (tag == "\\clip") alt = "\\iclip";
|
|
||||||
|
|
||||||
for (size_t i = 0; i < line->Blocks.size(); i++) {
|
|
||||||
const AssDialogueBlockOverride *ovr = dynamic_cast<const AssDialogueBlockOverride*>(line->Blocks[i]);
|
const AssDialogueBlockOverride *ovr = dynamic_cast<const AssDialogueBlockOverride*>(line->Blocks[i]);
|
||||||
if (!ovr) continue;
|
if (!ovr) continue;
|
||||||
|
|
||||||
for (size_t j=0; j < ovr->Tags.size(); j++) {
|
for (size_t j = 0; j < ovr->Tags.size(); ++j) {
|
||||||
const AssOverrideTag *cur = ovr->Tags[j];
|
if (ovr->Tags[j]->Name == tag_name)
|
||||||
if ((cur->Name == tag || cur->Name == alt) && cur->Params.size() >= n) {
|
return &ovr->Tags[j]->Params;
|
||||||
va_list argp;
|
|
||||||
va_start(argp, n);
|
|
||||||
for (size_t j = 0; j < n; j++) {
|
|
||||||
T *val = va_arg(argp, T *);
|
|
||||||
*val = cur->Params[j]->Get<T>(*val);
|
|
||||||
}
|
|
||||||
va_end(argp);
|
|
||||||
return cur->Name == alt ? ALT_TAG_FOUND : PRIMARY_TAG_FOUND;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TAG_NOT_FOUND;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
// Get a Vector2D from the given tag parameters, or Vector2D::Bad() if they are not valid
|
||||||
void VisualTool<FeatureType>::GetLinePosition(AssDialogue *diag,int &x, int &y) {
|
static Vector2D vec_or_bad(param_vec tag, size_t x_idx, size_t y_idx) {
|
||||||
int orgx,orgy;
|
if (!tag ||
|
||||||
GetLinePosition(diag,x,y,orgx,orgy);
|
tag->size() <= x_idx || tag->size() <= y_idx ||
|
||||||
|
(*tag)[x_idx]->omitted || (*tag)[y_idx]->omitted ||
|
||||||
|
(*tag)[x_idx]->GetType() == VARDATA_NONE || (*tag)[y_idx]->GetType() == VARDATA_NONE)
|
||||||
|
{
|
||||||
|
return Vector2D::Bad();
|
||||||
|
}
|
||||||
|
return Vector2D((*tag)[x_idx]->Get<float>(), (*tag)[y_idx]->Get<float>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
Vector2D VisualToolBase::GetLinePosition(AssDialogue *diag) {
|
||||||
void VisualTool<FeatureType>::GetLinePosition(AssDialogue *diag,int &x, int &y, int &orgx, int &orgy) {
|
scoped_tag_parse parse(diag);
|
||||||
|
|
||||||
|
if (Vector2D ret = vec_or_bad(find_tag(diag, "\\pos"), 0, 1)) return ret;
|
||||||
|
if (Vector2D ret = vec_or_bad(find_tag(diag, "\\move"), 0, 1)) return ret;
|
||||||
|
|
||||||
|
// Get default position
|
||||||
int margin[4];
|
int margin[4];
|
||||||
for (int i=0;i<4;i++) margin[i] = diag->Margin[i];
|
std::copy(diag->Margin, diag->Margin + 4, margin);
|
||||||
int align = 2;
|
int align = 2;
|
||||||
|
|
||||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
|
||||||
if (style) {
|
|
||||||
align = style->alignment;
|
align = style->alignment;
|
||||||
for (int i=0;i<4;i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (margin[i] == 0) margin[i] = style->Margin[i];
|
if (margin[i] == 0)
|
||||||
|
margin[i] = style->Margin[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sw,sh;
|
param_vec align_tag;
|
||||||
c->videoController->GetScriptSize(sw,sh);
|
if ((align_tag = find_tag(diag, "\\an")) && !(*align_tag)[0]->omitted)
|
||||||
|
align = (*align_tag)[0]->Get<int>();
|
||||||
|
else if ((align_tag = find_tag(diag, "\\a"))) {
|
||||||
|
align = (*align_tag)[0]->Get<int>(2);
|
||||||
|
|
||||||
// Process margins
|
// \a -> \an values mapping
|
||||||
margin[1] = sw - margin[1];
|
static int align_mapping[] = { 2, 1, 2, 3, 7, 7, 8, 9, 7, 4, 5, 6 };
|
||||||
margin[3] = sh - margin[2];
|
if (static_cast<size_t>(align) < sizeof(align_mapping) / sizeof(int))
|
||||||
|
align = align_mapping[align];
|
||||||
// Overrides processing
|
else
|
||||||
diag->ParseASSTags();
|
align = 2;
|
||||||
|
|
||||||
if (!get_value<int>(diag, "\\pos", 2, &x, &y)) {
|
|
||||||
if (get_value<int>(diag, "\\an", 1, &align) == ALT_TAG_FOUND) {
|
|
||||||
switch(align) {
|
|
||||||
case 1: case 2: case 3:
|
|
||||||
break;
|
|
||||||
case 5: case 6: case 7:
|
|
||||||
align += 2;
|
|
||||||
break;
|
|
||||||
case 9: case 10: case 11:
|
|
||||||
align -= 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
align = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Alignment type
|
|
||||||
int hor = (align - 1) % 3;
|
|
||||||
int vert = (align - 1) / 3;
|
|
||||||
|
|
||||||
// Calculate positions
|
|
||||||
if (hor == 0) x = margin[0];
|
|
||||||
else if (hor == 1) x = (margin[0] + margin[1])/2;
|
|
||||||
else if (hor == 2) x = margin[1];
|
|
||||||
if (vert == 0) y = margin[3];
|
|
||||||
else if (vert == 1) y = (margin[2] + margin[3])/2;
|
|
||||||
else if (vert == 2) y = margin[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->FromScriptCoords(&x, &y);
|
// Alignment type
|
||||||
|
int hor = (align - 1) % 3;
|
||||||
|
int vert = (align - 1) / 3;
|
||||||
|
|
||||||
if (!get_value<int>(diag, "\\org", 2, &orgx, &orgy)) {
|
// Calculate positions
|
||||||
orgx = x;
|
int x, y;
|
||||||
orgy = y;
|
if (hor == 0)
|
||||||
}
|
x = margin[0];
|
||||||
else {
|
else if (hor == 1)
|
||||||
parent->FromScriptCoords(&orgx, &orgy);
|
x = (script_res.X() + margin[0] - margin[1]) / 2;
|
||||||
}
|
else if (hor == 2)
|
||||||
|
x = margin[1];
|
||||||
|
|
||||||
diag->ClearBlocks();
|
if (vert == 0)
|
||||||
|
y = script_res.Y() - margin[2];
|
||||||
|
else if (vert == 1)
|
||||||
|
y = script_res.Y() / 2;
|
||||||
|
else if (vert == 2)
|
||||||
|
y = margin[2];
|
||||||
|
|
||||||
|
return Vector2D(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
Vector2D VisualToolBase::GetLineOrigin(AssDialogue *diag) {
|
||||||
void VisualTool<FeatureType>::GetLineMove(AssDialogue *diag,bool &hasMove,int &x1,int &y1,int &x2,int &y2,int &t1,int &t2) {
|
scoped_tag_parse parse(diag);
|
||||||
diag->ParseASSTags();
|
return vec_or_bad(find_tag(diag, "\\org"), 0, 1);
|
||||||
|
|
||||||
hasMove =
|
|
||||||
get_value<int>(diag, "\\move", 6, &x1, &y1, &x2, &y2, &t1, &t2) ||
|
|
||||||
get_value<int>(diag, "\\move", 4, &x1, &y1, &x2, &y2);
|
|
||||||
|
|
||||||
if (hasMove) {
|
|
||||||
parent->FromScriptCoords(&x1, &y1);
|
|
||||||
parent->FromScriptCoords(&x2, &y2);
|
|
||||||
}
|
|
||||||
|
|
||||||
diag->ClearBlocks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
bool VisualToolBase::GetLineMove(AssDialogue *diag, Vector2D &p1, Vector2D &p2, int &t1, int &t2) {
|
||||||
void VisualTool<FeatureType>::GetLineRotation(AssDialogue *diag,float &rx,float &ry,float &rz) {
|
scoped_tag_parse parse(diag);
|
||||||
|
|
||||||
|
param_vec tag = find_tag(diag, "\\move");
|
||||||
|
if (!tag)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
p1 = vec_or_bad(tag, 0, 1);
|
||||||
|
p2 = vec_or_bad(tag, 2, 3);
|
||||||
|
// VSFilter actually defaults to -1, but it uses <= 0 to check for default and 0 seems less bug-prone
|
||||||
|
t1 = (*tag)[4]->Get<int>(0);
|
||||||
|
t2 = (*tag)[5]->Get<int>(0);
|
||||||
|
|
||||||
|
return p1 && p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualToolBase::GetLineRotation(AssDialogue *diag, float &rx, float &ry, float &rz) {
|
||||||
rx = ry = rz = 0.f;
|
rx = ry = rz = 0.f;
|
||||||
|
|
||||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
if (AssStyle *style = c->ass->GetStyle(diag->Style))
|
||||||
if (style) {
|
|
||||||
rz = style->angle;
|
rz = style->angle;
|
||||||
}
|
|
||||||
|
|
||||||
diag->ParseASSTags();
|
scoped_tag_parse parse(diag);
|
||||||
|
|
||||||
get_value<float>(diag, "\\frx", 1, &rx);
|
if (param_vec tag = find_tag(diag, "\\frx"))
|
||||||
get_value<float>(diag, "\\fry", 1, &ry);
|
rx = tag->front()->Get<float>(rx);
|
||||||
get_value<float>(diag, "\\frz", 1, &rz);
|
if (param_vec tag = find_tag(diag, "\\fry"))
|
||||||
|
ry = tag->front()->Get<float>(ry);
|
||||||
diag->ClearBlocks();
|
if (param_vec tag = find_tag(diag, "\\frz"))
|
||||||
|
rz = tag->front()->Get<float>(rz);
|
||||||
|
else if (param_vec tag = find_tag(diag, "\\fr"))
|
||||||
|
rz = tag->front()->Get<float>(rz);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
|
||||||
void VisualTool<FeatureType>::GetLineScale(AssDialogue *diag,float &scalX,float &scalY) {
|
float x = 100.f, y = 100.f;
|
||||||
scalX = scalY = 100.f;
|
|
||||||
|
|
||||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
|
||||||
if (style) {
|
x = style->scalex;
|
||||||
scalX = style->scalex;
|
y = style->scaley;
|
||||||
scalY = style->scaley;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diag->ParseASSTags();
|
scoped_tag_parse parse(diag);
|
||||||
|
|
||||||
get_value<float>(diag, "\\fscx", 1, &scalX);
|
if (param_vec tag = find_tag(diag, "\\fscx"))
|
||||||
get_value<float>(diag, "\\fscy", 1, &scalY);
|
x = tag->front()->Get<float>(x);
|
||||||
|
if (param_vec tag = find_tag(diag, "\\fscy"))
|
||||||
|
y = tag->front()->Get<float>(y);
|
||||||
|
|
||||||
diag->ClearBlocks();
|
scale = Vector2D(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
void VisualToolBase::GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse) {
|
||||||
void VisualTool<FeatureType>::GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2,bool &inverse) {
|
|
||||||
x1 = y1 = 0;
|
|
||||||
int sw,sh;
|
|
||||||
c->videoController->GetScriptSize(sw,sh);
|
|
||||||
x2 = sw-1;
|
|
||||||
y2 = sh-1;
|
|
||||||
inverse = false;
|
inverse = false;
|
||||||
|
|
||||||
diag->ParseASSTags();
|
scoped_tag_parse parse(diag);
|
||||||
inverse = get_value<int>(diag, "\\clip", 4, &x1, &y1, &x2, &y2) == ALT_TAG_FOUND;
|
param_vec tag = find_tag(diag, "\\iclip");
|
||||||
diag->ClearBlocks();
|
if (tag)
|
||||||
|
inverse = true;
|
||||||
|
else
|
||||||
|
tag = find_tag(diag, "\\clip");
|
||||||
|
|
||||||
parent->FromScriptCoords(&x1, &y1);
|
if (tag && tag->size() == 4) {
|
||||||
parent->FromScriptCoords(&x2, &y2);
|
p1 = vec_or_bad(tag, 0, 1);
|
||||||
|
p2 = vec_or_bad(tag, 2, 3);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p1 = Vector2D();
|
||||||
|
p2 = script_res - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class FeatureType>
|
wxString VisualToolBase::GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse) {
|
||||||
wxString VisualTool<FeatureType>::GetLineVectorClip(AssDialogue *diag,int &scale,bool &inverse) {
|
scoped_tag_parse parse(diag);
|
||||||
|
|
||||||
scale = 1;
|
scale = 1;
|
||||||
inverse = false;
|
inverse = false;
|
||||||
diag->ParseASSTags();
|
|
||||||
|
|
||||||
int x1, y1, x2, y2;
|
param_vec tag = find_tag(diag, "\\iclip");
|
||||||
TagFoundType res = get_value<int>(diag, "\\clip", 4, &x1, &y1, &x2, &y2);
|
if (tag)
|
||||||
if (res) {
|
inverse = true;
|
||||||
inverse = res == ALT_TAG_FOUND;
|
else
|
||||||
diag->ClearBlocks();
|
tag = find_tag(diag, "\\clip");
|
||||||
return wxString::Format("m %d %d l %d %d %d %d %d %d", x1, y1, x2, y1, x2, y2, x1, y2);
|
|
||||||
|
if (tag && tag->size() == 4) {
|
||||||
|
return wxString::Format("m %d %d l %d %d %d %d %d %d",
|
||||||
|
(*tag)[0]->Get<int>(), (*tag)[1]->Get<int>(),
|
||||||
|
(*tag)[2]->Get<int>(), (*tag)[1]->Get<int>(),
|
||||||
|
(*tag)[2]->Get<int>(), (*tag)[3]->Get<int>(),
|
||||||
|
(*tag)[0]->Get<int>(), (*tag)[3]->Get<int>());
|
||||||
}
|
}
|
||||||
wxString result;
|
if (tag) {
|
||||||
wxString scaleStr;
|
scale = (*tag)[0]->Get<int>(scale);
|
||||||
res = get_value<wxString>(diag, "\\clip", 2, &scaleStr, &result);
|
return (*tag)[1]->Get<wxString>("");
|
||||||
inverse = res == ALT_TAG_FOUND;
|
|
||||||
if (!scaleStr.empty()) {
|
|
||||||
long s;
|
|
||||||
scaleStr.ToLong(&s);
|
|
||||||
scale = s;
|
|
||||||
}
|
}
|
||||||
diag->ClearBlocks();
|
|
||||||
return result;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Set override
|
void VisualToolBase::SetSelectedOverride(wxString const& tag, wxString const& value) {
|
||||||
/// @param tag
|
for_each(c->selectionController->GetSelectedSet(),
|
||||||
/// @param value
|
bind(&VisualToolBase::SetOverride, this, _1, tag, value));
|
||||||
template<class FeatureType>
|
}
|
||||||
void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxString value) {
|
|
||||||
|
void VisualToolBase::SetOverride(AssDialogue* line, wxString const& tag, wxString const& value) {
|
||||||
if (!line) return;
|
if (!line) return;
|
||||||
|
|
||||||
wxString removeTag;
|
wxString removeTag;
|
||||||
if (tag == "\\1c") removeTag = "\\c";
|
if (tag == "\\1c") removeTag = "\\c";
|
||||||
else if (tag == "\\fr") removeTag = "\\frz";
|
else if (tag == "\\frz") removeTag = "\\fr";
|
||||||
else if (tag == "\\pos") removeTag = "\\move";
|
else if (tag == "\\pos") removeTag = "\\move";
|
||||||
else if (tag == "\\move") removeTag = "\\pos";
|
else if (tag == "\\move") removeTag = "\\pos";
|
||||||
else if (tag == "\\clip") removeTag = "\\iclip";
|
else if (tag == "\\clip") removeTag = "\\iclip";
|
||||||
|
@ -607,17 +578,14 @@ void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxStr
|
||||||
|
|
||||||
// Get block at start
|
// Get block at start
|
||||||
line->ParseASSTags();
|
line->ParseASSTags();
|
||||||
AssDialogueBlock *block = line->Blocks.at(0);
|
AssDialogueBlock *block = line->Blocks.front();
|
||||||
|
|
||||||
// Get current block as plain or override
|
// Get current block as plain or override
|
||||||
AssDialogueBlockPlain *plain = dynamic_cast<AssDialogueBlockPlain*>(block);
|
|
||||||
AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(block);
|
|
||||||
assert(dynamic_cast<AssDialogueBlockDrawing*>(block) == NULL);
|
assert(dynamic_cast<AssDialogueBlockDrawing*>(block) == NULL);
|
||||||
|
|
||||||
if (plain) {
|
if (dynamic_cast<AssDialogueBlockPlain*>(block))
|
||||||
line->Text = "{" + insert + "}" + line->Text;
|
line->Text = "{" + insert + "}" + line->Text;
|
||||||
}
|
else if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(block)) {
|
||||||
else if (ovr) {
|
|
||||||
// Remove old of same
|
// Remove old of same
|
||||||
for (size_t i = 0; i < ovr->Tags.size(); i++) {
|
for (size_t i = 0; i < ovr->Tags.size(); i++) {
|
||||||
wxString name = ovr->Tags[i]->Name;
|
wxString name = ovr->Tags[i]->Name;
|
||||||
|
@ -631,8 +599,6 @@ void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxStr
|
||||||
|
|
||||||
line->UpdateText();
|
line->UpdateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->SetFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If only export worked
|
// If only export worked
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -36,6 +23,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -45,83 +33,158 @@
|
||||||
#include <wx/button.h>
|
#include <wx/button.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "base_grid.h"
|
#include <libaegisub/signal.h>
|
||||||
|
|
||||||
#include "gl_wrap.h"
|
#include "gl_wrap.h"
|
||||||
|
#include "selection_controller.h"
|
||||||
|
#include "vector2d.h"
|
||||||
|
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
class SubtitlesGrid;
|
class SubtitlesGrid;
|
||||||
class VideoDisplay;
|
class VideoDisplay;
|
||||||
struct VideoState;
|
class wxToolBar;
|
||||||
namespace agi {
|
namespace agi {
|
||||||
struct Context;
|
struct Context;
|
||||||
class OptionValue;
|
class OptionValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// First window id for visualsubtoolbar items
|
/// @class VisualToolBase
|
||||||
#define VISUAL_SUB_TOOL_START 1300
|
/// @brief Base class for visual tools containing all functionality that doesn't interact with features
|
||||||
|
///
|
||||||
|
/// This is required so that visual tools can be used polymorphically, as
|
||||||
|
/// different VisualTool<T>s are unrelated types otherwise. In addition, as much
|
||||||
|
/// functionality as possible is implemented here to avoid having four copies
|
||||||
|
/// of each method for no good reason (and four times as many error messages)
|
||||||
|
class VisualToolBase : protected SelectionListener<AssDialogue> {
|
||||||
|
std::deque<agi::signal::Connection> connections;
|
||||||
|
|
||||||
/// Last window id for visualsubtoolbar items
|
void OnCommit(int type);
|
||||||
#define VISUAL_SUB_TOOL_END (VISUAL_SUB_TOOL_START+100)
|
void OnSeek(int new_frame);
|
||||||
|
|
||||||
class IVisualTool : public OpenGLWrapper {
|
void OnMouseCaptureLost(wxMouseCaptureLostEvent &);
|
||||||
protected:
|
|
||||||
/// DOCME
|
|
||||||
static const wxColour colour[4];
|
|
||||||
public:
|
|
||||||
virtual void OnMouseEvent(wxMouseEvent &event)=0;
|
|
||||||
virtual void OnSubTool(wxCommandEvent &)=0;
|
|
||||||
virtual bool Update()=0;
|
|
||||||
virtual void Draw()=0;
|
|
||||||
virtual void Refresh()=0;
|
|
||||||
virtual void SetFrame(int frame)=0;
|
|
||||||
virtual ~IVisualTool() { };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ltaddr {
|
|
||||||
template<class T>
|
|
||||||
bool operator()(T lft, T rgt) const {
|
|
||||||
return &*lft < &*rgt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class VisualTool
|
|
||||||
/// @brief DOCME
|
|
||||||
/// DOCME
|
|
||||||
template<class FeatureType>
|
|
||||||
class VisualTool : public IVisualTool, protected SubtitleSelectionListener {
|
|
||||||
protected:
|
|
||||||
typedef FeatureType Feature;
|
|
||||||
typedef typename std::list<FeatureType>::iterator feature_iterator;
|
|
||||||
typedef typename std::list<FeatureType>::const_iterator feature_const_iterator;
|
|
||||||
private:
|
|
||||||
int dragStartX; /// Starting x coordinate of the current drag, if any
|
|
||||||
int dragStartY; /// Starting y coordinate of the current drag, if any
|
|
||||||
|
|
||||||
int commitId;
|
|
||||||
|
|
||||||
/// Set curFeature to the topmost feature under the mouse, or end() if there
|
|
||||||
/// are none
|
|
||||||
void GetHighlightedFeature();
|
|
||||||
|
|
||||||
/// @brief Get the dialogue line currently in the edit box
|
/// @brief Get the dialogue line currently in the edit box
|
||||||
/// @return NULL if the line is not active on the current frame
|
/// @return NULL if the line is not active on the current frame
|
||||||
AssDialogue *GetActiveDialogueLine();
|
AssDialogue *GetActiveDialogueLine();
|
||||||
|
|
||||||
|
// SubtitleSelectionListener implementation
|
||||||
|
void OnActiveLineChanged(AssDialogue *new_line);
|
||||||
|
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { }
|
||||||
|
|
||||||
|
// Below here are the virtuals that must be implemented
|
||||||
|
|
||||||
|
/// Called when the script, video or screen resolutions change
|
||||||
|
virtual void OnCoordinateSystemsChanged() { DoRefresh(); }
|
||||||
|
|
||||||
|
/// Called when the file is changed by something other than a visual tool
|
||||||
|
virtual void OnFileChanged() { DoRefresh(); }
|
||||||
|
|
||||||
|
/// Called when the frame number changes
|
||||||
|
virtual void OnFrameChanged() { }
|
||||||
|
|
||||||
|
/// Called when the active line changes
|
||||||
|
virtual void OnLineChanged() { DoRefresh(); }
|
||||||
|
|
||||||
|
/// Generic refresh to simplify tools which have no interesting state and
|
||||||
|
/// can simply do do the same thing for any external change (i.e. most of
|
||||||
|
/// them). Called only by the above virtual methods.
|
||||||
|
virtual void DoRefresh() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenGLWrapper gl;
|
||||||
|
|
||||||
|
/// Called when the user double-clicks
|
||||||
|
virtual void OnDoubleClick() { }
|
||||||
|
|
||||||
|
static const wxColour colour[4];
|
||||||
|
|
||||||
|
agi::Context *c;
|
||||||
|
VideoDisplay *parent;
|
||||||
|
|
||||||
|
bool holding; ///< Is a hold currently in progress?
|
||||||
|
AssDialogue *active_line; ///< Active dialogue line; NULL if it is not visible on the current frame
|
||||||
|
bool dragging; ///< Is a drag currently in progress?
|
||||||
|
|
||||||
|
int frame_number; ///< Current frame number
|
||||||
|
|
||||||
|
bool left_click; ///< Is a left click event currently being processed?
|
||||||
|
bool left_double; ///< Is a left double click event currently being processed?
|
||||||
|
bool shift_down; ///< Is shift down?
|
||||||
|
bool ctrl_down; ///< Is ctrl down?
|
||||||
|
bool alt_down; ///< Is alt down?
|
||||||
|
|
||||||
|
Vector2D mouse_pos; ///< Last seen mouse position
|
||||||
|
Vector2D drag_start; ///< Mouse position at the beginning of the last drag
|
||||||
|
Vector2D script_res; ///< Script resolution
|
||||||
|
Vector2D video_pos; ///< Top-left corner of the video in the display area
|
||||||
|
Vector2D video_res; ///< Video resolution
|
||||||
|
|
||||||
|
agi::signal::Connection file_changed_connection;
|
||||||
|
int commit_id; ///< Last used commit id for coalescing
|
||||||
|
|
||||||
|
/// @brief Commit the current file state
|
||||||
|
/// @param message Description of changes for undo
|
||||||
|
void Commit(wxString message = "");
|
||||||
|
bool IsDisplayed(AssDialogue *line) const;
|
||||||
|
|
||||||
|
/// Get the line's position if it's set, or it's default based on style if not
|
||||||
|
Vector2D GetLinePosition(AssDialogue *diag);
|
||||||
|
/// Get the line's origin if it's set, or Vector2D::Bad() if not
|
||||||
|
Vector2D GetLineOrigin(AssDialogue *diag);
|
||||||
|
bool GetLineMove(AssDialogue *diag, Vector2D &p1, Vector2D &p2, int &t1, int &t2);
|
||||||
|
void GetLineRotation(AssDialogue *diag, float &rx, float &ry, float &rz);
|
||||||
|
void GetLineScale(AssDialogue *diag, Vector2D &scale);
|
||||||
|
void GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse);
|
||||||
|
wxString GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse);
|
||||||
|
|
||||||
|
void SetOverride(AssDialogue* line, wxString const& tag, wxString const& value);
|
||||||
|
void SetSelectedOverride(wxString const& tag, wxString const& value);
|
||||||
|
|
||||||
|
VisualToolBase(VideoDisplay *parent, agi::Context *context);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Convert a point from video to script coordinates
|
||||||
|
Vector2D ToScriptCoords(Vector2D point) const;
|
||||||
|
/// Convert a point from script to video coordinates
|
||||||
|
Vector2D FromScriptCoords(Vector2D point) const;
|
||||||
|
|
||||||
|
// Stuff called by VideoDisplay
|
||||||
|
virtual void OnMouseEvent(wxMouseEvent &event)=0;
|
||||||
|
virtual void Draw()=0;
|
||||||
|
virtual void SetDisplayArea(int x, int y, int w, int h);
|
||||||
|
virtual void SetToolbar(wxToolBar *tb) { }
|
||||||
|
virtual ~VisualToolBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @class VisualTool
|
||||||
|
/// @brief Visual tool base class containing all common feature-related functionality
|
||||||
|
/// DOCME
|
||||||
|
template<class FeatureType>
|
||||||
|
class VisualTool : public VisualToolBase {
|
||||||
|
protected:
|
||||||
|
typedef FeatureType Feature;
|
||||||
|
typedef typename std::list<FeatureType>::iterator feature_iterator;
|
||||||
|
typedef typename std::list<FeatureType>::const_iterator feature_const_iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ltaddr {
|
||||||
|
template<class T>
|
||||||
|
bool operator()(T lft, T rgt) const {
|
||||||
|
return &*lft < &*rgt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<agi::signal::Connection> slots;
|
||||||
|
|
||||||
typedef typename std::set<feature_iterator, ltaddr>::iterator selection_iterator;
|
typedef typename std::set<feature_iterator, ltaddr>::iterator selection_iterator;
|
||||||
|
|
||||||
std::set<feature_iterator, ltaddr> selFeatures; /// Currently selected visual features
|
bool sel_changed; /// Has the selection already been changed in the current click?
|
||||||
std::map<AssDialogue*, int> lineSelCount; /// Number of selected features for each line
|
|
||||||
|
|
||||||
bool selChanged; /// Has the selection already been changed in the current click?
|
|
||||||
|
|
||||||
/// @brief Called when a hold is begun
|
/// @brief Called when a hold is begun
|
||||||
/// @return Should the hold actually happen?
|
/// @return Should the hold actually happen?
|
||||||
virtual bool InitializeHold() { return false; }
|
virtual bool InitializeHold() { return false; }
|
||||||
/// @brief Called on every mouse event during a hold
|
/// @brief Called on every mouse event during a hold
|
||||||
virtual void UpdateHold() { }
|
virtual void UpdateHold() { }
|
||||||
/// @brief Called at the end of a hold
|
|
||||||
virtual void CommitHold() { }
|
|
||||||
|
|
||||||
/// @brief Called at the beginning of a drag
|
/// @brief Called at the beginning of a drag
|
||||||
/// @param feature The visual feature clicked on
|
/// @param feature The visual feature clicked on
|
||||||
|
@ -130,67 +193,22 @@ private:
|
||||||
/// @brief Called on every mouse event during a drag
|
/// @brief Called on every mouse event during a drag
|
||||||
/// @param feature The current feature to process; not necessarily the one clicked on
|
/// @param feature The current feature to process; not necessarily the one clicked on
|
||||||
virtual void UpdateDrag(feature_iterator feature) { }
|
virtual void UpdateDrag(feature_iterator feature) { }
|
||||||
/// @brief Called at the end of a drag
|
|
||||||
virtual void CommitDrag(feature_iterator feature) { }
|
|
||||||
|
|
||||||
/// Called when the file is changed by something other than a visual tool
|
|
||||||
virtual void OnFileChanged() { DoRefresh(); }
|
|
||||||
/// Called when the frame number changes
|
|
||||||
virtual void OnFrameChanged() { }
|
|
||||||
/// Called when curDiag changes
|
|
||||||
virtual void OnLineChanged() { DoRefresh(); }
|
|
||||||
/// Generic refresh to simplify tools which do the same thing for any
|
|
||||||
/// external change (i.e. almost all of them). Called only by the above
|
|
||||||
/// methods.
|
|
||||||
virtual void DoRefresh() { }
|
|
||||||
|
|
||||||
/// @brief Called when there's stuff
|
|
||||||
/// @return Should the display rerender?
|
|
||||||
virtual bool Update() { return false; };
|
|
||||||
/// @brief Draw stuff
|
/// @brief Draw stuff
|
||||||
virtual void Draw()=0;
|
virtual void Draw()=0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Read-only reference to the set of selected features for subclasses
|
std::set<feature_iterator, ltaddr> sel_features; ///< Currently selected visual features
|
||||||
const std::set<feature_iterator, ltaddr> &selectedFeatures;
|
|
||||||
typedef typename std::set<feature_iterator, ltaddr>::const_iterator sel_iterator;
|
typedef typename std::set<feature_iterator, ltaddr>::const_iterator sel_iterator;
|
||||||
agi::Context *c;
|
|
||||||
VideoDisplay *parent; /// VideoDisplay which this belongs to, used to frame conversion
|
|
||||||
bool holding; /// Is a hold currently in progress?
|
|
||||||
AssDialogue *curDiag; /// Active dialogue line; NULL if it is not visible on the current frame
|
|
||||||
bool dragging; /// Is a drag currently in progress?
|
|
||||||
bool externalChange; /// Only invalid drag lists when refreshing due to external changes
|
|
||||||
|
|
||||||
feature_iterator curFeature; /// Topmost feature under the mouse; generally only valid during a drag
|
/// Topmost feature under the mouse; generally only valid during a drag
|
||||||
std::list<FeatureType> features; /// List of features which are drawn and can be clicked on
|
feature_iterator active_feature;
|
||||||
|
/// List of features which are drawn and can be clicked on
|
||||||
int frameNumber; /// Current frame number
|
/// List is used here for the iterator invalidation properties
|
||||||
VideoState const& video; /// Mouse and video information
|
std::list<FeatureType> features;
|
||||||
|
|
||||||
bool leftClick; /// Is a left click event currently being processed?
|
|
||||||
bool leftDClick; /// Is a left double click event currently being processed?
|
|
||||||
bool shiftDown; /// Is shift down?
|
|
||||||
bool ctrlDown; /// Is ctrl down?
|
|
||||||
bool altDown; /// Is alt down?
|
|
||||||
|
|
||||||
void GetLinePosition(AssDialogue *diag,int &x,int &y);
|
|
||||||
void GetLinePosition(AssDialogue *diag,int &x,int &y,int &orgx,int &orgy);
|
|
||||||
void GetLineMove(AssDialogue *diag,bool &hasMove,int &x1,int &y1,int &x2,int &y2,int &t1,int &t2);
|
|
||||||
void GetLineRotation(AssDialogue *diag,float &rx,float &ry,float &rz);
|
|
||||||
void GetLineScale(AssDialogue *diag,float &scalX,float &scalY);
|
|
||||||
void GetLineClip(AssDialogue *diag,int &x1,int &y1,int &x2,int &y2,bool &inverse);
|
|
||||||
wxString GetLineVectorClip(AssDialogue *diag,int &scale,bool &inverse);
|
|
||||||
void SetOverride(AssDialogue* line, wxString tag, wxString value);
|
|
||||||
|
|
||||||
/// Draw all of the features in the list
|
/// Draw all of the features in the list
|
||||||
void DrawAllFeatures();
|
void DrawAllFeatures();
|
||||||
/// @brief Commit the current file state
|
|
||||||
/// @param message Description of changes for undo
|
|
||||||
void Commit(wxString message = "");
|
|
||||||
|
|
||||||
/// @brief Add a feature (and its line) to the selection
|
|
||||||
/// @param i Index in the feature list
|
|
||||||
void AddSelection(feature_iterator feat);
|
|
||||||
|
|
||||||
/// @brief Remove a feature from the selection
|
/// @brief Remove a feature from the selection
|
||||||
/// @param i Index in the feature list
|
/// @param i Index in the feature list
|
||||||
|
@ -199,35 +217,15 @@ protected:
|
||||||
|
|
||||||
/// @brief Set the selection to a single feature, deselecting everything else
|
/// @brief Set the selection to a single feature, deselecting everything else
|
||||||
/// @param i Index in the feature list
|
/// @param i Index in the feature list
|
||||||
void SetSelection(feature_iterator feat);
|
void SetSelection(feature_iterator feat, bool clear);
|
||||||
|
|
||||||
/// @brief Clear the selection
|
|
||||||
void ClearSelection();
|
|
||||||
|
|
||||||
// SubtitleSelectionListener implementation
|
|
||||||
void OnActiveLineChanged(AssDialogue *new_line);
|
|
||||||
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Handler for all mouse events
|
/// @brief Handler for all mouse events
|
||||||
/// @param event Shockingly enough, the mouse event
|
/// @param event Shockingly enough, the mouse event
|
||||||
void OnMouseEvent(wxMouseEvent &event);
|
void OnMouseEvent(wxMouseEvent &event);
|
||||||
|
|
||||||
/// @brief Event handler for the subtoolbar
|
|
||||||
virtual void OnSubTool(wxCommandEvent &) { }
|
|
||||||
|
|
||||||
/// @brief Signal that the file has changed
|
|
||||||
void Refresh();
|
|
||||||
/// @brief Signal that the current frame number has changed
|
|
||||||
/// @param newFrameNumber The new frame number
|
|
||||||
void SetFrame(int newFrameNumber);
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param parent The VideoDisplay to use for coordinate conversion
|
/// @param parent The VideoDisplay to use for coordinate conversion
|
||||||
/// @param video Video and mouse information passing blob
|
/// @param video Video and mouse information passing blob
|
||||||
VisualTool(VideoDisplay *parent, agi::Context *context, VideoState const& video);
|
VisualTool(VideoDisplay *parent, agi::Context *context);
|
||||||
|
|
||||||
/// @brief Destructor
|
|
||||||
virtual ~VisualTool();
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -39,35 +26,30 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_clip.h"
|
#include "visual_tool_clip.h"
|
||||||
|
|
||||||
VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
#include "utils.h"
|
||||||
: VisualTool<ClipCorner>(parent, context, video)
|
|
||||||
, curX1(0)
|
VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context)
|
||||||
, curY1(0)
|
: VisualTool<ClipCorner>(parent, context)
|
||||||
, curX2(video.w)
|
, cur_1(0, 0)
|
||||||
, curY2(video.h)
|
, cur_2(video_res)
|
||||||
, inverse(false)
|
, inverse(false)
|
||||||
{
|
{
|
||||||
if (curDiag) {
|
|
||||||
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
Feature feat;
|
Feature feat;
|
||||||
feat.type = DRAG_SMALL_CIRCLE;
|
feat.type = DRAG_SMALL_CIRCLE;
|
||||||
features.resize(4, feat);
|
features.resize(4, feat);
|
||||||
|
|
||||||
|
// This is really awkward without being able to just index the list of
|
||||||
|
// features, so copy them into a temporary array
|
||||||
|
ClipCorner *feats[4];
|
||||||
feature_iterator cur = features.begin();
|
feature_iterator cur = features.begin();
|
||||||
feats[0] = &*(cur++);
|
feats[0] = &*(cur++);
|
||||||
feats[1] = &*(cur++);
|
feats[1] = &*(cur++);
|
||||||
feats[2] = &*(cur++);
|
feats[2] = &*(cur++);
|
||||||
feats[3] = &*(cur++);
|
feats[3] = &*(cur++);
|
||||||
|
|
||||||
|
// Attach each feature to the two features it shares edges with
|
||||||
// Top-left
|
// Top-left
|
||||||
int i = 0;
|
int i = 0;
|
||||||
feats[i]->horiz = feats[1];
|
feats[i]->horiz = feats[1];
|
||||||
|
@ -87,129 +69,81 @@ VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context, Vide
|
||||||
// Bottom-right
|
// Bottom-right
|
||||||
feats[i]->horiz = feats[2];
|
feats[i]->horiz = feats[2];
|
||||||
feats[i]->vert = feats[1];
|
feats[i]->vert = feats[1];
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::Draw() {
|
void VisualToolClip::Draw() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
int dx1 = curX1;
|
DrawAllFeatures();
|
||||||
int dy1 = curY1;
|
|
||||||
int dx2 = curX2;
|
|
||||||
int dy2 = curY2;
|
|
||||||
|
|
||||||
// Draw rectangle
|
// Draw rectangle
|
||||||
SetLineColour(colour[3],1.0f,2);
|
gl.SetLineColour(colour[3], 1.0f, 2);
|
||||||
SetFillColour(colour[3],0.0f);
|
gl.SetFillColour(colour[3], 0.0f);
|
||||||
DrawRectangle(dx1,dy1,dx2,dy2);
|
gl.DrawRectangle(cur_1, cur_2);
|
||||||
|
|
||||||
// Draw outside area
|
// Draw outside area
|
||||||
SetLineColour(colour[3],0.0f);
|
gl.SetLineColour(colour[3], 0.0f);
|
||||||
SetFillColour(wxColour(0,0,0),0.5f);
|
gl.SetFillColour(*wxBLACK, 0.5f);
|
||||||
if (inverse) {
|
if (inverse) {
|
||||||
DrawRectangle(dx1,dy1,dx2,dy2);
|
gl.DrawRectangle(cur_1, cur_2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DrawRectangle(0,0,video.w,dy1);
|
Vector2D p1 = cur_1.Min(cur_2);
|
||||||
DrawRectangle(0,dy2,video.w,video.h);
|
Vector2D p2 = cur_1.Max(cur_2);
|
||||||
DrawRectangle(0,dy1,dx1,dy2);
|
gl.DrawRectangle(Vector2D(0, 0), Vector2D(video_res, p1));
|
||||||
DrawRectangle(dx2,dy1,video.w,dy2);
|
gl.DrawRectangle(Vector2D(0, p2), video_res);
|
||||||
|
gl.DrawRectangle(Vector2D(0, p1), Vector2D(p1, p2));
|
||||||
|
gl.DrawRectangle(Vector2D(p2, p1), Vector2D(video_res, p2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw circles
|
|
||||||
SetLineColour(colour[0]);
|
|
||||||
SetFillColour(colour[1],0.5);
|
|
||||||
DrawAllFeatures();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolClip::InitializeHold() {
|
bool VisualToolClip::InitializeHold() {
|
||||||
startX = video.x;
|
|
||||||
startY = video.y;
|
|
||||||
curDiag->StripTag("\\clip");
|
|
||||||
curDiag->StripTag("\\iclip");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::UpdateHold() {
|
void VisualToolClip::UpdateHold() {
|
||||||
curX1 = startX;
|
|
||||||
curY1 = startY;
|
|
||||||
curX2 = video.x;
|
|
||||||
curY2 = video.y;
|
|
||||||
|
|
||||||
// Make sure 1 is smaller than 2
|
|
||||||
if (curX1 > curX2) std::swap(curX1,curX2);
|
|
||||||
if (curY1 > curY2) std::swap(curY1,curY2);
|
|
||||||
|
|
||||||
// Limit to video area
|
// Limit to video area
|
||||||
curX1 = mid(0,curX1,video.w);
|
Vector2D zero(0, 0);
|
||||||
curX2 = mid(0,curX2,video.w);
|
cur_1 = zero.Max(video_res.Min(drag_start));
|
||||||
curY1 = mid(0,curY1,video.h);
|
cur_2 = zero.Max(video_res.Min(mouse_pos));
|
||||||
curY2 = mid(0,curY2,video.h);
|
|
||||||
|
|
||||||
SetFeaturePositions();
|
SetFeaturePositions();
|
||||||
|
CommitHold();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::CommitHold() {
|
void VisualToolClip::CommitHold() {
|
||||||
int x1 = curX1;
|
SetOverride(active_line, inverse ? "\\iclip" : "\\clip",
|
||||||
int x2 = curX2;
|
wxString::Format("(%s,%s)", ToScriptCoords(cur_1.Min(cur_2)).Str(), ToScriptCoords(cur_1.Max(cur_2)).Str()));
|
||||||
int y1 = curY1;
|
|
||||||
int y2 = curY2;
|
|
||||||
parent->ToScriptCoords(&x1, &y1);
|
|
||||||
parent->ToScriptCoords(&x2, &y2);
|
|
||||||
SetOverride(curDiag, inverse ? "\\iclip" : "\\clip",wxString::Format("(%i,%i,%i,%i)",x1,y1,x2,y2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolClip::InitializeDrag(feature_iterator) {
|
bool VisualToolClip::InitializeDrag(feature_iterator) {
|
||||||
curDiag->StripTag("\\clip");
|
|
||||||
curDiag->StripTag("\\iclip");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::UpdateDrag(feature_iterator feature) {
|
void VisualToolClip::UpdateDrag(feature_iterator feature) {
|
||||||
// Update brothers
|
// Update features which share an edge with the dragged one
|
||||||
feature->horiz->y = feature->y;
|
feature->horiz->pos = Vector2D(feature->horiz->pos, feature->pos);
|
||||||
feature->vert->x = feature->x;
|
feature->vert->pos = Vector2D(feature->pos, feature->vert->pos);
|
||||||
|
|
||||||
// Get "cur" from features
|
cur_1 = features.front().pos;
|
||||||
curX1 = feats[0]->x;
|
cur_2 = features.back().pos;
|
||||||
curX2 = feats[3]->x;
|
|
||||||
curY1 = feats[0]->y;
|
|
||||||
curY2 = feats[3]->y;
|
|
||||||
|
|
||||||
// Make sure p1 < p2
|
|
||||||
if (curX1 > curX2) std::swap(curX1,curX2);
|
|
||||||
if (curY1 > curY2) std::swap(curY1,curY2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolClip::CommitDrag(feature_iterator) {
|
|
||||||
CommitHold();
|
CommitHold();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::SetFeaturePositions() {
|
void VisualToolClip::SetFeaturePositions() {
|
||||||
// Top-left
|
feature_iterator it = features.begin();
|
||||||
int i = 0;
|
(it++)->pos = cur_1; // Top-left
|
||||||
feats[i]->x = curX1;
|
(it++)->pos = Vector2D(cur_2, cur_1); // Top-right
|
||||||
feats[i]->y = curY1;
|
(it++)->pos = Vector2D(cur_1, cur_2); // Bottom-left
|
||||||
i++;
|
it->pos = cur_2; // Bottom-right
|
||||||
|
|
||||||
// Top-right
|
|
||||||
feats[i]->x = curX2;
|
|
||||||
feats[i]->y = curY1;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Bottom-left
|
|
||||||
feats[i]->x = curX1;
|
|
||||||
feats[i]->y = curY2;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Bottom-right
|
|
||||||
feats[i]->x = curX2;
|
|
||||||
feats[i]->y = curY2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolClip::DoRefresh() {
|
void VisualToolClip::DoRefresh() {
|
||||||
if (curDiag) {
|
if (active_line) {
|
||||||
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
|
GetLineClip(active_line, cur_1, cur_2, inverse);
|
||||||
|
cur_1 = FromScriptCoords(cur_1);
|
||||||
|
cur_2 = FromScriptCoords(cur_2);
|
||||||
SetFeaturePositions();
|
SetFeaturePositions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -39,16 +26,10 @@
|
||||||
|
|
||||||
/// @class ClipCorner
|
/// @class ClipCorner
|
||||||
/// @brief VisualDraggableFeature with siblings
|
/// @brief VisualDraggableFeature with siblings
|
||||||
class ClipCorner : public VisualDraggableFeature {
|
struct ClipCorner : public VisualDraggableFeature {
|
||||||
public:
|
ClipCorner *horiz; /// Other corner on this corner's horizontal line
|
||||||
ClipCorner* horiz; /// Other corner on this corner's horizontal line
|
ClipCorner *vert; /// Other corner on this corner's vertical line
|
||||||
ClipCorner* vert; /// Other corner on this corner's vertical line
|
ClipCorner() : VisualDraggableFeature() , horiz(0) , vert(0) { }
|
||||||
/// @brief Constructor
|
|
||||||
ClipCorner()
|
|
||||||
: VisualDraggableFeature()
|
|
||||||
, horiz(NULL)
|
|
||||||
, vert(NULL)
|
|
||||||
{ }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
@ -57,11 +38,10 @@ public:
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class VisualToolClip : public VisualTool<ClipCorner> {
|
class VisualToolClip : public VisualTool<ClipCorner> {
|
||||||
int startX,startY,curX1,curY1,curX2,curY2;
|
Vector2D cur_1;
|
||||||
|
Vector2D cur_2;
|
||||||
|
|
||||||
ClipCorner *feats[4];
|
bool inverse; ///< Is this currently in iclip mode?
|
||||||
|
|
||||||
bool inverse;
|
|
||||||
|
|
||||||
bool InitializeHold();
|
bool InitializeHold();
|
||||||
void UpdateHold();
|
void UpdateHold();
|
||||||
|
@ -72,9 +52,8 @@ class VisualToolClip : public VisualTool<ClipCorner> {
|
||||||
|
|
||||||
bool InitializeDrag(feature_iterator feature);
|
bool InitializeDrag(feature_iterator feature);
|
||||||
void UpdateDrag(feature_iterator feature);
|
void UpdateDrag(feature_iterator feature);
|
||||||
void CommitDrag(feature_iterator feature);
|
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
public:
|
public:
|
||||||
VisualToolClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *);
|
VisualToolClip(VideoDisplay *parent, agi::Context *context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -35,88 +22,81 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "include/aegisub/context.h"
|
|
||||||
#include "gl_text.h"
|
|
||||||
#include "video_context.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_cross.h"
|
#include "visual_tool_cross.h"
|
||||||
|
|
||||||
VisualToolCross::VisualToolCross(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
#include "gl_text.h"
|
||||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
#include "include/aegisub/context.h"
|
||||||
, glText(new OpenGLText)
|
#include "video_display.h"
|
||||||
|
|
||||||
|
VisualToolCross::VisualToolCross(VideoDisplay *parent, agi::Context *context)
|
||||||
|
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||||
|
, gl_text(new OpenGLText)
|
||||||
{
|
{
|
||||||
|
parent->SetCursor(wxCursor(wxCURSOR_BLANK));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolCross::Update() {
|
VisualToolCross::~VisualToolCross() {
|
||||||
if (!leftDClick) return true;
|
parent->SetCursor(wxNullCursor);
|
||||||
if (!curDiag) return true;
|
}
|
||||||
|
|
||||||
int dx, dy;
|
void VisualToolCross::OnDoubleClick() {
|
||||||
int vx = video.x;
|
Vector2D d = ToScriptCoords(mouse_pos) - GetLinePosition(active_line);
|
||||||
int vy = video.y;
|
|
||||||
GetLinePosition(curDiag, dx, dy);
|
|
||||||
parent->ToScriptCoords(&vx, &vy);
|
|
||||||
parent->ToScriptCoords(&dx, &dy);
|
|
||||||
dx -= vx;
|
|
||||||
dy -= vy;
|
|
||||||
|
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
Selection sel = c->selectionController->GetSelectedSet();
|
||||||
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
|
for (Selection::const_iterator it = sel.begin(); it != sel.end(); ++it) {
|
||||||
int x1, y1;
|
Vector2D p1, p2;
|
||||||
GetLinePosition(*cur, x1, y1);
|
int t1, t2;
|
||||||
parent->ToScriptCoords(&x1, &y1);
|
if (GetLineMove(*it, p1, p2, t1, t2)) {
|
||||||
SetOverride(*cur, "\\pos", wxString::Format("(%i,%i)", x1 - dx, y1 - dy));
|
if (t1 > 0 || t2 > 0)
|
||||||
|
SetOverride(*it, "\\move", wxString::Format("(%s,%s,%d,%d)", (p1 + d).Str(), (p2 + d).Str(), t1, t2));
|
||||||
|
else
|
||||||
|
SetOverride(*it, "\\move", wxString::Format("(%s,%s)", (p1 + d).Str(), (p2 + d).Str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SetOverride(*it, "\\pos", (GetLinePosition(*it) + d).PStr());
|
||||||
|
|
||||||
|
if (Vector2D org = GetLineOrigin(*it))
|
||||||
|
SetOverride(*it, "\\org", (org + d).PStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
Commit(_("positioning"));
|
Commit(_("positioning"));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolCross::Draw() {
|
void VisualToolCross::Draw() {
|
||||||
|
if (!mouse_pos) return;
|
||||||
|
|
||||||
// Draw cross
|
// Draw cross
|
||||||
glDisable(GL_LINE_SMOOTH);
|
gl.SetInvert();
|
||||||
glEnable(GL_COLOR_LOGIC_OP);
|
gl.SetLineColour(*wxWHITE, 1.0, 1);
|
||||||
glLogicOp(GL_INVERT);
|
float lines[] = {
|
||||||
glLineWidth(1);
|
0.f, mouse_pos.Y(),
|
||||||
glBegin(GL_LINES);
|
video_res.X(), mouse_pos.Y(),
|
||||||
glColor3f(1.0f,1.0f,1.0f);
|
mouse_pos.X(), 0.f,
|
||||||
glVertex2f(0, video.y);
|
mouse_pos.X(), video_res.Y()
|
||||||
glVertex2f(video.w, video.y);
|
};
|
||||||
glVertex2f(video.x, 0);
|
gl.DrawLines(2, lines, 4);
|
||||||
glVertex2f(video.x, video.h);
|
gl.ClearInvert();
|
||||||
glEnd();
|
|
||||||
glDisable(GL_COLOR_LOGIC_OP);
|
|
||||||
|
|
||||||
int tx,ty;
|
Vector2D t = ToScriptCoords(shift_down ? video_res - mouse_pos : mouse_pos);
|
||||||
if (!wxGetMouseState().ShiftDown()) {
|
wxString mouse_text = t.Str();
|
||||||
tx = video.x;
|
|
||||||
ty = video.y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tx = video.w - video.x;
|
|
||||||
ty = video.h - video.y;
|
|
||||||
}
|
|
||||||
parent->ToScriptCoords(&tx, &ty);
|
|
||||||
wxString mouseText = wxString::Format("%i,%i", tx, ty);
|
|
||||||
|
|
||||||
int tw,th;
|
int tw, th;
|
||||||
glText->SetFont("Verdana", 12, true, false);
|
gl_text->SetFont("Verdana", 12, true, false);
|
||||||
glText->SetColour(wxColour(255, 255, 255), 1.f);
|
gl_text->SetColour(*wxWHITE, 1.f);
|
||||||
glText->GetExtent(mouseText, tw, th);
|
gl_text->GetExtent(mouse_text, tw, th);
|
||||||
|
|
||||||
// Calculate draw position
|
// Place the text in the corner of the cross closest to the center of the video
|
||||||
int dx = video.x;
|
int dx = mouse_pos.X();
|
||||||
int dy = video.y;
|
int dy = mouse_pos.Y();
|
||||||
bool left = dx > video.w / 2;
|
if (dx > video_res.X() / 2)
|
||||||
bool bottom = dy < video.h / 2;
|
dx -= tw + 4;
|
||||||
|
else
|
||||||
|
dx += 4;
|
||||||
|
|
||||||
// Text draw coords
|
if (dy < video_res.Y() / 2)
|
||||||
if (left) dx -= tw + 4;
|
dy += 3;
|
||||||
else dx += 4;
|
else
|
||||||
if (bottom) dy += 3;
|
dy -= th + 3;
|
||||||
else dy -= th + 3;
|
|
||||||
|
|
||||||
// Draw text
|
gl_text->Print(mouse_text, dx, dy);
|
||||||
glText->Print(mouseText, dx, dy);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -34,24 +21,21 @@
|
||||||
/// @ingroup visual_ts
|
/// @ingroup visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#include <libaegisub/scoped_ptr.h>
|
||||||
#include <tr1/memory>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "visual_feature.h"
|
#include "visual_feature.h"
|
||||||
#include "visual_tool.h"
|
#include "visual_tool.h"
|
||||||
|
|
||||||
class OpenGLText;
|
class OpenGLText;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class VisualToolCross
|
/// @class VisualToolCross
|
||||||
/// @brief DOCME
|
/// @brief A crosshair which shows the current mouse position and on double-click
|
||||||
///
|
/// shifts the selected lines to the clicked point
|
||||||
/// DOCME
|
|
||||||
class VisualToolCross : public VisualTool<VisualDraggableFeature> {
|
class VisualToolCross : public VisualTool<VisualDraggableFeature> {
|
||||||
bool Update();
|
void OnDoubleClick();
|
||||||
void Draw();
|
void Draw();
|
||||||
std::tr1::shared_ptr<OpenGLText> glText;
|
agi::scoped_ptr<OpenGLText> gl_text;
|
||||||
public:
|
public:
|
||||||
VisualToolCross(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *);
|
VisualToolCross(VideoDisplay *parent, agi::Context *context);
|
||||||
|
~VisualToolCross();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -35,83 +22,79 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "visual_tool_drag.h"
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <wx/bmpbuttn.h>
|
||||||
|
#include <wx/toolbar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "include/aegisub/context.h"
|
#include "include/aegisub/context.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "subs_grid.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "video_context.h"
|
#include "video_context.h"
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_drag.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BUTTON_TOGGLE_MOVE = VISUAL_SUB_TOOL_START
|
|
||||||
};
|
|
||||||
static const DraggableFeatureType DRAG_ORIGIN = DRAG_BIG_TRIANGLE;
|
static const DraggableFeatureType DRAG_ORIGIN = DRAG_BIG_TRIANGLE;
|
||||||
static const DraggableFeatureType DRAG_START = DRAG_BIG_SQUARE;
|
static const DraggableFeatureType DRAG_START = DRAG_BIG_SQUARE;
|
||||||
static const DraggableFeatureType DRAG_END = DRAG_BIG_CIRCLE;
|
static const DraggableFeatureType DRAG_END = DRAG_BIG_CIRCLE;
|
||||||
|
|
||||||
/// @brief Constructor
|
VisualToolDrag::VisualToolDrag(VideoDisplay *parent, agi::Context *context)
|
||||||
/// @param _parent
|
: VisualTool<VisualToolDragDraggableFeature>(parent, context)
|
||||||
/// @param toolBar
|
, primary(0)
|
||||||
VisualToolDrag::VisualToolDrag(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar * toolBar)
|
, button_is_move(true)
|
||||||
: VisualTool<VisualToolDragDraggableFeature>(parent, context, video)
|
|
||||||
, toolBar(toolBar)
|
|
||||||
, primary(NULL)
|
|
||||||
, toggleMoveOnMove(true)
|
|
||||||
{
|
{
|
||||||
toolBar->AddTool(BUTTON_TOGGLE_MOVE, _("Toggle between \\move and \\pos"), GETIMAGE(visual_move_conv_move_24));
|
|
||||||
toolBar->Realize();
|
|
||||||
toolBar->Show(true);
|
|
||||||
|
|
||||||
c->selectionController->GetSelectedSet(selection);
|
c->selectionController->GetSelectedSet(selection);
|
||||||
OnFileChanged();
|
}
|
||||||
|
|
||||||
|
void VisualToolDrag::SetToolbar(wxToolBar *tb) {
|
||||||
|
toolbar = tb;
|
||||||
|
toolbar->AddTool(-1, _("Toggle between \\move and \\pos"), GETIMAGE(visual_move_conv_move_24));
|
||||||
|
toolbar->Realize();
|
||||||
|
toolbar->Show(true);
|
||||||
|
|
||||||
|
toolbar->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VisualToolDrag::OnSubTool, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::UpdateToggleButtons() {
|
void VisualToolDrag::UpdateToggleButtons() {
|
||||||
// Check which bitmap to use
|
bool to_move = true;
|
||||||
bool toMove = true;
|
if (active_line) {
|
||||||
if (curDiag) {
|
Vector2D p1, p2;
|
||||||
int x1,y1,x2,y2,t1,t2;
|
int t1, t2;
|
||||||
bool hasMove;
|
to_move = !GetLineMove(active_line, p1, p2, t1, t2);
|
||||||
GetLineMove(curDiag,hasMove,x1,y1,x2,y2,t1,t2);
|
|
||||||
toMove = !hasMove;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No change needed
|
if (to_move == button_is_move) return;
|
||||||
if (toMove == toggleMoveOnMove) return;
|
|
||||||
|
|
||||||
// Change bitmap
|
toolbar->SetToolNormalBitmap(toolbar->GetToolByPos(0)->GetId(),
|
||||||
if (toMove) {
|
to_move ? GETIMAGE(visual_move_conv_move_24) : GETIMAGE(visual_move_conv_pos_24));
|
||||||
toolBar->SetToolNormalBitmap(BUTTON_TOGGLE_MOVE, GETIMAGE(visual_move_conv_move_24));
|
button_is_move = to_move;
|
||||||
}
|
|
||||||
else {
|
|
||||||
toolBar->SetToolNormalBitmap(BUTTON_TOGGLE_MOVE, GETIMAGE(visual_move_conv_pos_24));
|
|
||||||
}
|
|
||||||
toggleMoveOnMove = toMove;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Toggle button pressed
|
|
||||||
/// @param event
|
|
||||||
void VisualToolDrag::OnSubTool(wxCommandEvent &) {
|
void VisualToolDrag::OnSubTool(wxCommandEvent &) {
|
||||||
// Toggle \move <-> \pos
|
// Toggle \move <-> \pos
|
||||||
|
VideoContext *vc = c->videoController;
|
||||||
for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
|
for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
|
||||||
AssDialogue *line = *cur;
|
AssDialogue *line = *cur;
|
||||||
int x1,y1,x2,y2,t1,t2;
|
Vector2D p1, p2;
|
||||||
bool hasMove;
|
int t1, t2;
|
||||||
|
|
||||||
GetLinePosition(line,x1,y1);
|
bool has_move = GetLineMove(line, p1, p2, t1, t2);
|
||||||
GetLineMove(line,hasMove,x1,y1,x2,y2,t1,t2);
|
|
||||||
parent->ToScriptCoords(&x1, &y1);
|
|
||||||
parent->ToScriptCoords(&x2, &y2);
|
|
||||||
|
|
||||||
if (hasMove) SetOverride(line, "\\pos",wxString::Format("(%i,%i)",x1,y1));
|
if (has_move)
|
||||||
else SetOverride(line, "\\move",wxString::Format("(%i,%i,%i,%i,%i,%i)",x1,y1,x1,y1,0,line->End.GetMS() - line->Start.GetMS()));
|
SetOverride(line, "\\pos", p1.PStr());
|
||||||
|
else {
|
||||||
|
p1 = GetLinePosition(line);
|
||||||
|
// Round the start and end times to exact frames
|
||||||
|
int start = vc->TimeAtFrame(vc->FrameAtTime(line->Start.GetMS(), agi::vfr::START)) - line->Start.GetMS();
|
||||||
|
int end = vc->TimeAtFrame(vc->FrameAtTime(line->Start.GetMS(), agi::vfr::END)) - line->Start.GetMS();
|
||||||
|
SetOverride(line, "\\move", wxString::Format("(%s,%s,%d,%d)", p1.Str(), p1.Str(), start, end));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Commit();
|
Commit();
|
||||||
Refresh();
|
OnFileChanged();
|
||||||
UpdateToggleButtons();
|
UpdateToggleButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,161 +105,142 @@ void VisualToolDrag::OnLineChanged() {
|
||||||
void VisualToolDrag::OnFileChanged() {
|
void VisualToolDrag::OnFileChanged() {
|
||||||
/// @todo it should be possible to preserve the selection in some cases
|
/// @todo it should be possible to preserve the selection in some cases
|
||||||
features.clear();
|
features.clear();
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
primary = NULL;
|
primary = 0;
|
||||||
|
active_feature = features.end();
|
||||||
|
|
||||||
for (int i = c->subsGrid->GetRows() - 1; i >=0; i--) {
|
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
||||||
AssDialogue *diag = c->subsGrid->GetDialogue(i);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it);
|
||||||
if (c->subsGrid->IsDisplayed(diag)) {
|
if (diag && IsDisplayed(diag))
|
||||||
MakeFeatures(diag);
|
MakeFeatures(diag);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateToggleButtons();
|
UpdateToggleButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::OnFrameChanged() {
|
void VisualToolDrag::OnFrameChanged() {
|
||||||
if (primary && !c->subsGrid->IsDisplayed(primary->line)) primary = NULL;
|
if (primary && !IsDisplayed(primary->line))
|
||||||
|
primary = 0;
|
||||||
|
|
||||||
feature_iterator feat = features.begin();
|
feature_iterator feat = features.begin();
|
||||||
feature_iterator end = features.end();
|
feature_iterator end = features.end();
|
||||||
|
|
||||||
for (int i = c->subsGrid->GetRows() - 1; i >=0; i--) {
|
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
||||||
AssDialogue *diag = c->subsGrid->GetDialogue(i);
|
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it);
|
||||||
if (c->subsGrid->IsDisplayed(diag)) {
|
if (!diag) continue;
|
||||||
|
|
||||||
|
if (IsDisplayed(diag)) {
|
||||||
// Features don't exist and should
|
// Features don't exist and should
|
||||||
if (feat == end || feat->line != diag) {
|
if (feat == end || feat->line != diag)
|
||||||
MakeFeatures(diag, feat);
|
MakeFeatures(diag, feat);
|
||||||
}
|
|
||||||
// Move past already existing features for the line
|
// Move past already existing features for the line
|
||||||
else {
|
else
|
||||||
while (feat != end && feat->line == diag) ++feat;
|
while (feat != end && feat->line == diag) ++feat;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Remove all features for this line (if any)
|
// Remove all features for this line (if any)
|
||||||
while (feat != end && feat->line == diag) {
|
while (feat != end && feat->line == diag) {
|
||||||
feat->line = NULL;
|
feat->line = 0;
|
||||||
RemoveSelection(feat);
|
RemoveSelection(feat);
|
||||||
feat = features.erase(feat);
|
feat = features.erase(feat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
active_feature = features.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) {
|
void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) {
|
||||||
c->selectionController->GetSelectedSet(selection);
|
c->selectionController->GetSelectedSet(selection);
|
||||||
if (!externalChange) return;
|
|
||||||
externalChange = false;
|
|
||||||
c->subsGrid->BeginBatch();
|
|
||||||
|
|
||||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
for (feature_iterator it = features.begin(); it != features.end(); ++it) {
|
||||||
// Remove all deselected lines
|
if (removed.count(it->line))
|
||||||
if (removed.find(cur->line) != removed.end()) {
|
sel_features.erase(it);
|
||||||
RemoveSelection(cur);
|
else if (added.count(it->line) && it->type == DRAG_START)
|
||||||
}
|
sel_features.insert(it);
|
||||||
// And add all newly selected lines
|
|
||||||
else if (added.find(cur->line) != added.end() && cur->type == DRAG_START) {
|
|
||||||
AddSelection(cur);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c->subsGrid->EndBatch();
|
|
||||||
externalChange = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::Draw() {
|
void VisualToolDrag::Draw() {
|
||||||
DrawAllFeatures();
|
DrawAllFeatures();
|
||||||
|
|
||||||
// Draw arrows
|
// Draw connecting lines
|
||||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||||
if (cur->type == DRAG_START) continue;
|
if (cur->type == DRAG_START) continue;
|
||||||
|
|
||||||
feature_iterator p2 = cur;
|
feature_iterator p2 = cur;
|
||||||
feature_iterator p1 = cur->parent;
|
feature_iterator p1 = cur->parent;
|
||||||
|
|
||||||
// Has arrow?
|
// Move end marker has an arrow; origin doesn't
|
||||||
bool hasArrow = p2->type == DRAG_END;
|
bool has_arrow = p2->type == DRAG_END;
|
||||||
int arrowLen = hasArrow ? 10 : 0;
|
int arrow_len = has_arrow ? 10 : 0;
|
||||||
|
|
||||||
// See if the distance between them is enough
|
// Don't show the connecting line if the features are very close
|
||||||
int dx = p2->x - p1->x;
|
Vector2D direction = p2->pos - p1->pos;
|
||||||
int dy = p2->y - p1->y;
|
if (direction.SquareLen() < (20 + arrow_len) * (20 + arrow_len)) continue;
|
||||||
int dist = (int)sqrt(double(dx*dx + dy*dy));
|
|
||||||
if (dist < 20+arrowLen) continue;
|
|
||||||
|
|
||||||
// Get end points
|
direction = direction.Unit();
|
||||||
int x1 = p1->x + dx*10/dist;
|
// Get the start and end points of the line
|
||||||
int x2 = p2->x - dx*(10+arrowLen)/dist;
|
Vector2D start = p1->pos + direction * 10;
|
||||||
int y1 = p1->y + dy*10/dist;
|
Vector2D end = p2->pos - direction * (10 + arrow_len);
|
||||||
int y2 = p2->y - dy*(10+arrowLen)/dist;
|
|
||||||
|
|
||||||
// Draw arrow
|
if (has_arrow) {
|
||||||
if (hasArrow) {
|
gl.SetLineColour(colour[3], 0.8f, 2);
|
||||||
// Calculate angle
|
|
||||||
double angle = atan2(double(y2-y1),double(x2-x1))+1.570796;
|
|
||||||
int sx = int(cos(angle)*4);
|
|
||||||
int sy = int(-sin(angle)*4);
|
|
||||||
|
|
||||||
// Arrow line
|
// Arrow line
|
||||||
SetLineColour(colour[3],0.8f,2);
|
gl.DrawLine(start, end);
|
||||||
DrawLine(x1,y1,x2,y2);
|
|
||||||
|
|
||||||
// Arrow head
|
// Arrow head
|
||||||
DrawLine(x2+sx,y2-sy,x2-sx,y2+sy);
|
Vector2D t_half_base_w = Vector2D(-direction.Y(), direction.X()) * 4;
|
||||||
DrawLine(x2+sx,y2-sy,x2+dx*10/dist,y2+dy*10/dist);
|
gl.DrawTriangle(end + direction * arrow_len, end + t_half_base_w, end - t_half_base_w);
|
||||||
DrawLine(x2-sx,y2+sy,x2+dx*10/dist,y2+dy*10/dist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw dashed line
|
// Draw dashed line
|
||||||
else {
|
else {
|
||||||
SetLineColour(colour[3],0.5f,2);
|
gl.SetLineColour(colour[3], 0.5f, 2);
|
||||||
DrawDashedLine(x1,y1,x2,y2,6);
|
gl.DrawDashedLine(start, end, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag) {
|
void VisualToolDrag::MakeFeatures(AssDialogue *diag) {
|
||||||
MakeFeatures(diag, features.end());
|
MakeFeatures(diag, features.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_iterator pos) {
|
void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_iterator pos) {
|
||||||
// Get position
|
Vector2D p1 = FromScriptCoords(GetLinePosition(diag));
|
||||||
int x1,x2,y1,y2;
|
|
||||||
int t1=0;
|
|
||||||
int t2=diag->End.GetMS()-diag->Start.GetMS();
|
|
||||||
int torgx,torgy;
|
|
||||||
bool hasMove;
|
|
||||||
GetLinePosition(diag,x1,y1,torgx,torgy);
|
|
||||||
GetLineMove(diag,hasMove,x1,y1,x2,y2,t1,t2);
|
|
||||||
|
|
||||||
// Create \pos feature
|
// Create \pos feature
|
||||||
Feature feat;
|
Feature feat;
|
||||||
feat.x = x1;
|
feat.pos = p1;
|
||||||
feat.y = y1;
|
|
||||||
feat.layer = 0;
|
feat.layer = 0;
|
||||||
feat.type = DRAG_START;
|
feat.type = DRAG_START;
|
||||||
feat.time = t1;
|
feat.time = 0;
|
||||||
feat.line = diag;
|
feat.line = diag;
|
||||||
feat.parent = features.end();
|
feat.parent = features.end();
|
||||||
features.insert(pos, feat);
|
features.insert(pos, feat);
|
||||||
feature_iterator cur = pos; --cur;
|
feature_iterator cur = pos; --cur;
|
||||||
feat.parent = cur;
|
feat.parent = cur;
|
||||||
if (selection.find(diag) != selection.end()) {
|
if (selection.count(diag))
|
||||||
AddSelection(cur);
|
sel_features.insert(cur);
|
||||||
}
|
|
||||||
|
Vector2D p2;
|
||||||
|
int t1, t2;
|
||||||
|
|
||||||
// Create move destination feature
|
// Create move destination feature
|
||||||
if (hasMove) {
|
if (GetLineMove(diag, p1, p2, t1, t2)) {
|
||||||
feat.x = x2;
|
feat.pos = FromScriptCoords(p2);
|
||||||
feat.y = y2;
|
|
||||||
feat.layer = 1;
|
feat.layer = 1;
|
||||||
feat.type = DRAG_END;
|
feat.type = DRAG_END;
|
||||||
|
feat.parent->time = t1;
|
||||||
feat.time = t2;
|
feat.time = t2;
|
||||||
feat.line = diag;
|
feat.line = diag;
|
||||||
features.insert(pos, feat);
|
features.insert(pos, feat);
|
||||||
feat.parent->parent = --pos; ++pos;
|
feat.parent->parent = --pos; ++pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create org feature
|
// Create org feature
|
||||||
if (torgx != x1 || torgy != y1) {
|
if (Vector2D org = GetLineOrigin(diag)) {
|
||||||
feat.x = torgx;
|
feat.pos = FromScriptCoords(org);
|
||||||
feat.y = torgy;
|
|
||||||
feat.layer = -1;
|
feat.layer = -1;
|
||||||
feat.type = DRAG_ORIGIN;
|
feat.type = DRAG_ORIGIN;
|
||||||
feat.time = 0;
|
feat.time = 0;
|
||||||
|
@ -291,94 +255,57 @@ bool VisualToolDrag::InitializeDrag(feature_iterator feature) {
|
||||||
// Set time of clicked feature to the current frame and shift all other
|
// Set time of clicked feature to the current frame and shift all other
|
||||||
// selected features by the same amount
|
// selected features by the same amount
|
||||||
if (feature->type != DRAG_ORIGIN) {
|
if (feature->type != DRAG_ORIGIN) {
|
||||||
int time = c->videoController->TimeAtFrame(frameNumber) - feature->line->Start.GetMS();
|
int time = c->videoController->TimeAtFrame(frame_number) - feature->line->Start.GetMS();
|
||||||
int change = time - feature->time;
|
int change = time - feature->time;
|
||||||
|
|
||||||
for (sel_iterator cur = selectedFeatures.begin(); cur != selectedFeatures.end(); ++cur) {
|
for (sel_iterator cur = sel_features.begin(); cur != sel_features.end(); ++cur) {
|
||||||
if ((*cur)->type != DRAG_ORIGIN) {
|
(*cur)->time += change;
|
||||||
(*cur)->time += change;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolDrag::CommitDrag(feature_iterator feature) {
|
void VisualToolDrag::UpdateDrag(feature_iterator feature) {
|
||||||
if (feature->type == DRAG_ORIGIN) {
|
if (feature->type == DRAG_ORIGIN) {
|
||||||
int x = feature->x;
|
SetOverride(feature->line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||||
int y = feature->y;
|
|
||||||
parent->ToScriptCoords(&x, &y);
|
|
||||||
SetOverride(feature->line, "\\org",wxString::Format("(%i,%i)",x,y));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
feature_iterator p = feature->parent;
|
feature_iterator end_feature = feature->parent;
|
||||||
if (feature->type == DRAG_END) {
|
if (feature->type == DRAG_END)
|
||||||
std::swap(feature, p);
|
std::swap(feature, end_feature);
|
||||||
}
|
|
||||||
|
|
||||||
int x1 = feature->x;
|
if (feature->parent == features.end())
|
||||||
int y1 = feature->y;
|
SetOverride(feature->line, "\\pos", ToScriptCoords(feature->pos).PStr());
|
||||||
parent->ToScriptCoords(&x1, &y1);
|
else
|
||||||
|
SetOverride(feature->line, "\\move",
|
||||||
// Position
|
wxString::Format("(%s,%s,%d,%d)",
|
||||||
if (feature->parent == features.end()) {
|
ToScriptCoords(feature->pos).Str(),
|
||||||
SetOverride(feature->line, "\\pos", wxString::Format("(%i,%i)", x1, y1));
|
ToScriptCoords(end_feature->pos).Str(),
|
||||||
}
|
feature->time, end_feature->time));
|
||||||
// Move
|
|
||||||
else {
|
|
||||||
int x2 = p->x;
|
|
||||||
int y2 = p->y;
|
|
||||||
parent->ToScriptCoords(&x2, &y2);
|
|
||||||
|
|
||||||
SetOverride(feature->line, "\\move", wxString::Format("(%i,%i,%i,%i,%i,%i)", x1, y1, x2, y2, feature->time, p->time));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool VisualToolDrag::Update() {
|
|
||||||
if (!leftDClick) return false;
|
|
||||||
|
|
||||||
int dx, dy;
|
void VisualToolDrag::OnDoubleClick() {
|
||||||
int vx = video.x;
|
Vector2D d = ToScriptCoords(mouse_pos) - (primary ? ToScriptCoords(primary->pos) : GetLinePosition(active_line));
|
||||||
int vy = video.y;
|
|
||||||
parent->ToScriptCoords(&vx, &vy);
|
|
||||||
if (primary) {
|
|
||||||
dx = primary->x;
|
|
||||||
dy = primary->y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!curDiag) return false;
|
|
||||||
GetLinePosition(curDiag, dx, dy);
|
|
||||||
}
|
|
||||||
parent->ToScriptCoords(&dx, &dy);
|
|
||||||
dx -= vx;
|
|
||||||
dy -= vy;
|
|
||||||
|
|
||||||
for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
|
Selection sel = c->selectionController->GetSelectedSet();
|
||||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, t1 = INT_MIN, t2 = INT_MIN, orgx, orgy;
|
for (Selection::const_iterator it = sel.begin(); it != sel.end(); ++it) {
|
||||||
bool isMove;
|
Vector2D p1, p2;
|
||||||
|
int t1, t2;
|
||||||
GetLinePosition(*cur, x1, y1, orgx, orgy);
|
if (GetLineMove(*it, p1, p2, t1, t2)) {
|
||||||
GetLineMove(*cur, isMove, x1, y1, x2, y2, t1, t2);
|
if (t1 > 0 || t2 > 0)
|
||||||
parent->ToScriptCoords(&x1, &y1);
|
SetOverride(*it, "\\move", wxString::Format("(%s,%s,%d,%d)", (p1 + d).Str(), (p2 + d).Str(), t1, t2));
|
||||||
parent->ToScriptCoords(&x2, &y2);
|
|
||||||
parent->ToScriptCoords(&orgx, &orgy);
|
|
||||||
|
|
||||||
if (isMove) {
|
|
||||||
if (t1 > INT_MIN && t2 > INT_MIN)
|
|
||||||
SetOverride(*cur, "\\move", wxString::Format("(%i,%i,%i,%i,%i,%i)", x1 - dx, y1 - dy, x2 - dx, y2 - dy, t1, t2));
|
|
||||||
else
|
else
|
||||||
SetOverride(*cur, "\\move", wxString::Format("(%i,%i,%i,%i)", x1, y1, x2, y2));
|
SetOverride(*it, "\\move", wxString::Format("(%s,%s)", (p1 + d).Str(), (p2 + d).Str()));
|
||||||
}
|
|
||||||
else {
|
|
||||||
SetOverride(*cur, "\\pos", wxString::Format("(%i,%i)", x1 - dx, y1 - dy));
|
|
||||||
}
|
|
||||||
if (orgx != x1 || orgy != y1) {
|
|
||||||
SetOverride(*cur, "\\org", wxString::Format("(%i,%i)", orgx - dx, orgy - dy));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SetOverride(*it, "\\pos", (GetLinePosition(*it) + d).PStr());
|
||||||
|
|
||||||
|
if (Vector2D org = GetLineOrigin(*it))
|
||||||
|
SetOverride(*it, "\\org", (org + d).PStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
Commit(_("positioning"));
|
Commit(_("positioning"));
|
||||||
|
|
||||||
OnFileChanged();
|
OnFileChanged();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -34,11 +21,6 @@
|
||||||
/// @ingroup visual_ts
|
/// @ingroup visual_ts
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
|
||||||
#include <wx/bmpbuttn.h>
|
|
||||||
#include <wx/toolbar.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "visual_feature.h"
|
#include "visual_feature.h"
|
||||||
#include "visual_tool.h"
|
#include "visual_tool.h"
|
||||||
|
|
||||||
|
@ -51,27 +33,26 @@ public:
|
||||||
VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0) { }
|
VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class wxBitmapButton;
|
||||||
|
class wxToolBar;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class VisualToolDrag
|
/// @class VisualToolDrag
|
||||||
/// @brief DOCME
|
/// @brief Moveable features for the positions of each visible line
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
||||||
/// The subtoolbar for the move/pos conversion button
|
/// The subtoolbar for the move/pos conversion button
|
||||||
wxToolBar *toolBar;
|
wxToolBar *toolbar;
|
||||||
/// The feature last clicked on for the double-click handler
|
/// The feature last clicked on for the double-click handler
|
||||||
/// Equal to curFeature during drags; possibly different at all other times
|
/// Equal to curFeature during drags; possibly different at all other times
|
||||||
/// Null if no features have been clicked on or the last clicked on one no
|
/// NNULL if no features have been clicked on or the last clicked on one no
|
||||||
/// longer exists
|
/// longer exists
|
||||||
Feature *primary;
|
Feature *primary;
|
||||||
/// The last announced selection set
|
/// The last announced selection set
|
||||||
Selection selection;
|
Selection selection;
|
||||||
int change;
|
|
||||||
|
|
||||||
/// When the button is pressed, will it convert the line to a move (vs. from
|
/// When the button is pressed, will it convert the line to a move (vs. from
|
||||||
/// move to pos)? Used to avoid changing the button's icon unnecessarily
|
/// move to pos)? Used to avoid changing the button's icon unnecessarily
|
||||||
bool toggleMoveOnMove;
|
bool button_is_move;
|
||||||
|
|
||||||
/// @brief Create the features for a line
|
/// @brief Create the features for a line
|
||||||
/// @param diag Line to create the features for
|
/// @param diag Line to create the features for
|
||||||
|
@ -79,23 +60,23 @@ class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
||||||
void MakeFeatures(AssDialogue *diag, feature_iterator pos);
|
void MakeFeatures(AssDialogue *diag, feature_iterator pos);
|
||||||
void MakeFeatures(AssDialogue *diag);
|
void MakeFeatures(AssDialogue *diag);
|
||||||
|
|
||||||
bool InitializeDrag(feature_iterator feature);
|
|
||||||
void CommitDrag(feature_iterator feature);
|
|
||||||
|
|
||||||
/// Set the pos/move button to the correct icon based on the active line
|
|
||||||
void UpdateToggleButtons();
|
|
||||||
|
|
||||||
// Overriding SubtitleSelectionListener inherited from base VisualTool<>
|
// Overriding SubtitleSelectionListener inherited from base VisualTool<>
|
||||||
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
||||||
|
|
||||||
void OnFrameChanged();
|
void OnFrameChanged();
|
||||||
void OnFileChanged();
|
void OnFileChanged();
|
||||||
void OnLineChanged();
|
void OnLineChanged();
|
||||||
|
void OnCoordinateSystemsChanged() { OnFileChanged(); }
|
||||||
|
|
||||||
|
bool InitializeDrag(feature_iterator feature);
|
||||||
|
void UpdateDrag(feature_iterator feature);
|
||||||
void Draw();
|
void Draw();
|
||||||
bool Update();
|
void OnDoubleClick();
|
||||||
public:
|
|
||||||
VisualToolDrag(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *toolbar);
|
|
||||||
|
|
||||||
|
/// Set the pos/move button to the correct icon based on the active line
|
||||||
|
void UpdateToggleButtons();
|
||||||
void OnSubTool(wxCommandEvent &event);
|
void OnSubTool(wxCommandEvent &event);
|
||||||
|
public:
|
||||||
|
VisualToolDrag(VideoDisplay *parent, agi::Context *context);
|
||||||
|
void SetToolbar(wxToolBar *tb);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -36,175 +23,152 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "include/aegisub/context.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "video_context.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_rotatexy.h"
|
#include "visual_tool_rotatexy.h"
|
||||||
|
|
||||||
VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, agi::Context *context)
|
||||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||||
{
|
{
|
||||||
features.resize(1);
|
features.resize(1);
|
||||||
org = &features.back();
|
org = &features.back();
|
||||||
org->type = DRAG_BIG_TRIANGLE;
|
org->type = DRAG_BIG_TRIANGLE;
|
||||||
DoRefresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateXY::Draw() {
|
void VisualToolRotateXY::Draw() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
// Pivot coordinates
|
|
||||||
int dx=0,dy=0;
|
|
||||||
if (dragging) GetLinePosition(curDiag,dx,dy);
|
|
||||||
else GetLinePosition(curDiag,dx,dy,org->x,org->y);
|
|
||||||
dx = org->x;
|
|
||||||
dy = org->y;
|
|
||||||
|
|
||||||
SetLineColour(colour[0]);
|
|
||||||
SetFillColour(colour[1],0.3f);
|
|
||||||
|
|
||||||
// Draw pivot
|
|
||||||
DrawAllFeatures();
|
DrawAllFeatures();
|
||||||
|
|
||||||
// Transform grid
|
// Transform grid
|
||||||
glMatrixMode(GL_MODELVIEW);
|
gl.SetOrigin(org->pos);
|
||||||
glPushMatrix();
|
gl.SetRotation(angle_x, angle_y, angle_z);
|
||||||
glLoadIdentity();
|
|
||||||
glTranslatef(dx,dy,0.f);
|
|
||||||
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
|
|
||||||
glMultMatrixf(matrix);
|
|
||||||
glScalef(1.f,1.f,8.f);
|
|
||||||
if (curAngleY != 0.f) glRotatef(curAngleY,0.f,-1.f,0.f);
|
|
||||||
if (curAngleX != 0.f) glRotatef(curAngleX,-1.f,0.f,0.f);
|
|
||||||
if (curAngleZ != 0.f) glRotatef(curAngleZ,0.f,0.f,-1.f);
|
|
||||||
|
|
||||||
// Draw grid
|
// Draw grid
|
||||||
glShadeModel(GL_SMOOTH);
|
gl.SetLineColour(colour[0], 0.5f, 2);
|
||||||
SetLineColour(colour[0],0.5f,2);
|
gl.SetModeLine();
|
||||||
SetModeLine();
|
float r = colour[0].Red() / 255.f;
|
||||||
float r = colour[0].Red()/255.f;
|
float g = colour[0].Green() / 255.f;
|
||||||
float g = colour[0].Green()/255.f;
|
float b = colour[0].Blue() / 255.f;
|
||||||
float b = colour[0].Blue()/255.f;
|
|
||||||
glBegin(GL_LINES);
|
std::vector<float> colors(11 * 8 * 4);
|
||||||
for (int i=0;i<11;i++) {
|
for (int i = 0; i < 88; ++i) {
|
||||||
float a = 1.f - abs(i-5)*0.18f;
|
colors[i * 4 + 0] = r;
|
||||||
int pos = 20*(i-5);
|
colors[i * 4 + 1] = g;
|
||||||
glColor4f(r,g,b,0.f);
|
colors[i * 4 + 2] = b;
|
||||||
glVertex2i(pos,120);
|
colors[i * 4 + 3] = (i + 3) % 4 > 1 ? 0 : (1.f - abs(i / 8 - 5) * 0.18f);
|
||||||
glColor4f(r,g,b,a);
|
|
||||||
glVertex2i(pos,0);
|
|
||||||
glVertex2i(pos,0);
|
|
||||||
glColor4f(r,g,b,0.f);
|
|
||||||
glVertex2i(pos,-120);
|
|
||||||
glVertex2i(120,pos);
|
|
||||||
glColor4f(r,g,b,a);
|
|
||||||
glVertex2i(0,pos);
|
|
||||||
glVertex2i(0,pos);
|
|
||||||
glColor4f(r,g,b,0.f);
|
|
||||||
glVertex2i(-120,pos);
|
|
||||||
}
|
}
|
||||||
glEnd();
|
|
||||||
|
std::vector<float> points(11 * 8 * 2);
|
||||||
|
for (int i = 0; i < 11; ++i) {
|
||||||
|
int pos = 20 * (i - 5);
|
||||||
|
|
||||||
|
points[i * 16 + 0] = pos;
|
||||||
|
points[i * 16 + 1] = 120;
|
||||||
|
|
||||||
|
points[i * 16 + 2] = pos;
|
||||||
|
points[i * 16 + 3] = 0;
|
||||||
|
|
||||||
|
points[i * 16 + 4] = pos;
|
||||||
|
points[i * 16 + 5] = 0;
|
||||||
|
|
||||||
|
points[i * 16 + 6] = pos;
|
||||||
|
points[i * 16 + 7] = -120;
|
||||||
|
|
||||||
|
points[i * 16 + 8] = 120;
|
||||||
|
points[i * 16 + 9] = pos;
|
||||||
|
|
||||||
|
points[i * 16 + 10] = 0;
|
||||||
|
points[i * 16 + 11] = pos;
|
||||||
|
|
||||||
|
points[i * 16 + 12] = 0;
|
||||||
|
points[i * 16 + 13] = pos;
|
||||||
|
|
||||||
|
points[i * 16 + 14] = -120;
|
||||||
|
points[i * 16 + 15] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.DrawLines(2, points, 4, colors);
|
||||||
|
|
||||||
// Draw vectors
|
// Draw vectors
|
||||||
SetLineColour(colour[3],1.f,2);
|
gl.SetLineColour(colour[3], 1.f, 2);
|
||||||
SetModeLine();
|
float vectors[] = {
|
||||||
glBegin(GL_LINES);
|
0.f, 0.f, 0.f,
|
||||||
glVertex3f(0.f,0.f,0.f);
|
50.f, 0.f, 0.f,
|
||||||
glVertex3f(50.f,0.f,0.f);
|
0.f, 0.f, 0.f,
|
||||||
glVertex3f(0.f,0.f,0.f);
|
0.f, 50.f, 0.f,
|
||||||
glVertex3f(0.f,50.f,0.f);
|
0.f, 0.f, 0.f,
|
||||||
glVertex3f(0.f,0.f,0.f);
|
0.f, 0.f, 50.f,
|
||||||
glVertex3f(0.f,0.f,50.f);
|
};
|
||||||
glEnd();
|
gl.DrawLines(3, vectors, 6);
|
||||||
|
|
||||||
// Draw arrow tops
|
// Draw arrow tops
|
||||||
glBegin(GL_TRIANGLE_FAN);
|
float arrows[] = {
|
||||||
glVertex3f(60.f,0.f,0.f);
|
60.f, 0.f, 0.f,
|
||||||
glVertex3f(50.f,-3.f,-3.f);
|
50.f, -3.f, -3.f,
|
||||||
glVertex3f(50.f,3.f,-3.f);
|
50.f, 3.f, -3.f,
|
||||||
glVertex3f(50.f,3.f,3.f);
|
50.f, 3.f, 3.f,
|
||||||
glVertex3f(50.f,-3.f,3.f);
|
50.f, -3.f, 3.f,
|
||||||
glVertex3f(50.f,-3.f,-3.f);
|
50.f, -3.f, -3.f,
|
||||||
glEnd();
|
|
||||||
glBegin(GL_TRIANGLE_FAN);
|
|
||||||
glVertex3f(0.f,60.f,0.f);
|
|
||||||
glVertex3f(-3.f,50.f,-3.f);
|
|
||||||
glVertex3f(3.f,50.f,-3.f);
|
|
||||||
glVertex3f(3.f,50.f,3.f);
|
|
||||||
glVertex3f(-3.f,50.f,3.f);
|
|
||||||
glVertex3f(-3.f,50.f,-3.f);
|
|
||||||
glEnd();
|
|
||||||
glBegin(GL_TRIANGLE_FAN);
|
|
||||||
glVertex3f(0.f,0.f,60.f);
|
|
||||||
glVertex3f(-3.f,-3.f,50.f);
|
|
||||||
glVertex3f(3.f,-3.f,50.f);
|
|
||||||
glVertex3f(3.f,3.f,50.f);
|
|
||||||
glVertex3f(-3.f,3.f,50.f);
|
|
||||||
glVertex3f(-3.f,-3.f,50.f);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glPopMatrix();
|
0.f, 60.f, 0.f,
|
||||||
glShadeModel(GL_FLAT);
|
-3.f, 50.f, -3.f,
|
||||||
|
3.f, 50.f, -3.f,
|
||||||
|
3.f, 50.f, 3.f,
|
||||||
|
-3.f, 50.f, 3.f,
|
||||||
|
-3.f, 50.f, -3.f,
|
||||||
|
|
||||||
|
0.f, 0.f, 60.f,
|
||||||
|
-3.f, -3.f, 50.f,
|
||||||
|
3.f, -3.f, 50.f,
|
||||||
|
3.f, 3.f, 50.f,
|
||||||
|
-3.f, 3.f, 50.f,
|
||||||
|
-3.f, -3.f, 50.f,
|
||||||
|
};
|
||||||
|
|
||||||
|
gl.DrawLines(3, arrows, 18);
|
||||||
|
|
||||||
|
gl.ResetTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolRotateXY::InitializeHold() {
|
bool VisualToolRotateXY::InitializeHold() {
|
||||||
startAngleX = (org->y-video.y)*2.f;
|
orig_x = angle_x;
|
||||||
startAngleY = (video.x-org->x)*2.f;
|
orig_y = angle_y;
|
||||||
origAngleX = curAngleX;
|
|
||||||
origAngleY = curAngleY;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateXY::UpdateHold() {
|
void VisualToolRotateXY::UpdateHold() {
|
||||||
float screenAngleX = (org->y-video.y)*2.f;
|
Vector2D delta = (mouse_pos - drag_start) * 2;
|
||||||
float screenAngleY = (video.x-org->x)*2.f;
|
if (shift_down)
|
||||||
|
delta = delta.SingleAxis();
|
||||||
|
|
||||||
// Deltas
|
angle_x = orig_x - delta.Y();
|
||||||
float deltaX = screenAngleX - startAngleX;
|
angle_y = orig_y + delta.X();
|
||||||
float deltaY = screenAngleY - startAngleY;
|
|
||||||
if (shiftDown) {
|
if (ctrl_down) {
|
||||||
if (fabs(deltaX) >= fabs(deltaY)) deltaY = 0.f;
|
angle_x = floorf(angle_x / 30.f + .5f) * 30.f;
|
||||||
else deltaX = 0.f;
|
angle_y = floorf(angle_y / 30.f + .5f) * 30.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate
|
angle_x = fmodf(angle_x + 360.f, 360.f);
|
||||||
curAngleX = fmodf(deltaX + origAngleX + 360.f, 360.f);
|
angle_y = fmodf(angle_y + 360.f, 360.f);
|
||||||
curAngleY = fmodf(deltaY + origAngleY + 360.f, 360.f);
|
|
||||||
|
|
||||||
// Oh Snap
|
SetSelectedOverride("\\frx", wxString::Format("(%0.3g)", angle_x));
|
||||||
if (ctrlDown) {
|
SetSelectedOverride("\\fry", wxString::Format("(%0.3g)", angle_y));
|
||||||
curAngleX = floorf(curAngleX/30.f+.5f)*30.f;
|
|
||||||
curAngleY = floorf(curAngleY/30.f+.5f)*30.f;
|
|
||||||
if (curAngleX > 359.f) curAngleX = 0.f;
|
|
||||||
if (curAngleY > 359.f) curAngleY = 0.f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateXY::CommitHold() {
|
void VisualToolRotateXY::UpdateDrag(feature_iterator feature) {
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||||
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
|
|
||||||
SetOverride(*cur, "\\frx",wxString::Format("(%0.3g)",curAngleX));
|
|
||||||
SetOverride(*cur, "\\fry",wxString::Format("(%0.3g)",curAngleY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolRotateXY::CommitDrag(feature_iterator feature) {
|
|
||||||
int x = feature->x;
|
|
||||||
int y = feature->y;
|
|
||||||
parent->ToScriptCoords(&x, &y);
|
|
||||||
SetOverride(curDiag, "\\org",wxString::Format("(%i,%i)",x,y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateXY::DoRefresh() {
|
void VisualToolRotateXY::DoRefresh() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
int posx, posy;
|
|
||||||
GetLinePosition(curDiag,posx,posy,org->x,org->y);
|
if (!(org->pos = GetLineOrigin(active_line)))
|
||||||
GetLineRotation(curDiag,curAngleX,curAngleY,curAngleZ);
|
org->pos = GetLinePosition(active_line);
|
||||||
|
org->pos = FromScriptCoords(org->pos);
|
||||||
|
|
||||||
|
GetLineRotation(active_line, angle_x, angle_y, angle_z);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -41,20 +28,20 @@
|
||||||
/// @class VisualToolRotateXY
|
/// @class VisualToolRotateXY
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
|
class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
|
||||||
float curAngleX,startAngleX,origAngleX;
|
float angle_x; /// Current x rotation
|
||||||
float curAngleY,startAngleY,origAngleY;
|
float angle_y; /// Current y rotation
|
||||||
float curAngleZ;
|
float angle_z; /// Current z rotation
|
||||||
|
|
||||||
|
float orig_x; ///< x rotation at the beginning of the current hold
|
||||||
|
float orig_y; ///< y rotation at the beginning of the current hold
|
||||||
|
|
||||||
Feature *org;
|
Feature *org;
|
||||||
|
|
||||||
|
void DoRefresh();
|
||||||
|
void Draw();
|
||||||
|
void UpdateDrag(feature_iterator feature);
|
||||||
bool InitializeHold();
|
bool InitializeHold();
|
||||||
void UpdateHold();
|
void UpdateHold();
|
||||||
void CommitHold();
|
|
||||||
|
|
||||||
void CommitDrag(feature_iterator feature);
|
|
||||||
|
|
||||||
void DoRefresh();
|
|
||||||
|
|
||||||
void Draw();
|
|
||||||
public:
|
public:
|
||||||
VisualToolRotateXY(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *);
|
VisualToolRotateXY(VideoDisplay *parent, agi::Context *context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -39,133 +26,110 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "include/aegisub/context.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "video_context.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_rotatez.h"
|
#include "visual_tool_rotatez.h"
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
static const float deg2rad = 3.1415926536f / 180.f;
|
static const float deg2rad = 3.1415926536f / 180.f;
|
||||||
static const float rad2deg = 180.f / 3.1415926536f;
|
static const float rad2deg = 180.f / 3.1415926536f;
|
||||||
|
|
||||||
VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context)
|
||||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||||
{
|
{
|
||||||
features.resize(1);
|
features.resize(1);
|
||||||
org = &features.back();
|
org = &features.back();
|
||||||
org->type = DRAG_BIG_TRIANGLE;
|
org->type = DRAG_BIG_TRIANGLE;
|
||||||
DoRefresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateZ::Draw() {
|
void VisualToolRotateZ::Draw() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
// Draw pivot
|
|
||||||
DrawAllFeatures();
|
DrawAllFeatures();
|
||||||
|
|
||||||
int radius = (int)sqrt(double((posx-org->x)*(posx-org->x)+(posy-org->y)*(posy-org->y)));
|
float radius = (pos - org->pos).Len();
|
||||||
int oRadius = radius;
|
float oRadius = radius;
|
||||||
if (radius < 50) radius = 50;
|
if (radius < 50)
|
||||||
|
radius = 50;
|
||||||
int deltax = int(cos(curAngle*deg2rad)*radius);
|
|
||||||
int deltay = int(-sin(curAngle*deg2rad)*radius);
|
|
||||||
|
|
||||||
// Set colours
|
|
||||||
SetLineColour(colour[0]);
|
|
||||||
SetFillColour(colour[1],0.3f);
|
|
||||||
|
|
||||||
// Set up the projection
|
// Set up the projection
|
||||||
glMatrixMode(GL_MODELVIEW);
|
gl.SetOrigin(org->pos);
|
||||||
glPushMatrix();
|
gl.SetRotation(rotation_x, rotation_y, 0);
|
||||||
glLoadIdentity();
|
gl.SetScale(scale);
|
||||||
glTranslatef(org->x,org->y,-1.f);
|
|
||||||
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
|
|
||||||
glMultMatrixf(matrix);
|
|
||||||
glScalef(1.f,1.f,8.f);
|
|
||||||
glRotatef(ry,0.f,-1.f,0.f);
|
|
||||||
glRotatef(rx,-1.f,0.f,0.f);
|
|
||||||
glScalef(scaleX/100.f,scaleY/100.f,1.f);
|
|
||||||
|
|
||||||
// Draw the circle
|
// Draw the circle
|
||||||
DrawRing(0,0,radius+4,radius-4);
|
gl.SetLineColour(colour[0]);
|
||||||
|
gl.SetFillColour(colour[1], 0.3f);
|
||||||
|
gl.DrawRing(Vector2D(), radius + 4, radius - 4);
|
||||||
|
|
||||||
// Draw markers around circle
|
// Draw markers around circle
|
||||||
int markers = 6;
|
int markers = 6;
|
||||||
float markStart = -90.f / markers;
|
float markStart = -90.f / markers;
|
||||||
float markEnd = markStart+(180.f/markers);
|
float markEnd = markStart + (180.f / markers);
|
||||||
for (int i=0;i<markers;i++) {
|
for (int i = 0; i < markers; ++i) {
|
||||||
float angle = i*(360.f/markers);
|
float angle = i * (360.f / markers);
|
||||||
DrawRing(0,0,radius+30,radius+12,radius/radius,angle+markStart,angle+markEnd);
|
gl.DrawRing(Vector2D(), radius+30, radius+12, 1.0, angle+markStart, angle+markEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the baseline
|
// Draw the baseline through the origin showing current rotation
|
||||||
SetLineColour(colour[3],1.f,2);
|
Vector2D angle_vec(Vector2D::FromAngle(angle * deg2rad));
|
||||||
DrawLine(deltax,deltay,-deltax,-deltay);
|
gl.SetLineColour(colour[3], 1, 2);
|
||||||
|
gl.DrawLine(angle_vec * -radius, angle_vec * radius);
|
||||||
|
|
||||||
// Draw the connection line
|
if (org->pos != pos) {
|
||||||
if (org->x != posx || org->y != posy) {
|
Vector2D rotated_pos = Vector2D::FromAngle(angle * deg2rad - (pos - org->pos).Angle()) * oRadius;
|
||||||
double angle = atan2(double(org->y-posy),double(posx-org->x)) + curAngle*deg2rad;
|
|
||||||
int fx = int(cos(angle)*oRadius);
|
// Draw the line from origin to rotated position
|
||||||
int fy = -int(sin(angle)*oRadius);
|
gl.DrawLine(Vector2D(), rotated_pos);
|
||||||
DrawLine(0,0,fx,fy);
|
|
||||||
int mdx = int(cos(curAngle*deg2rad)*20);
|
// Draw the line under the text
|
||||||
int mdy = int(-sin(curAngle*deg2rad)*20);
|
gl.DrawLine(rotated_pos - angle_vec * 20, rotated_pos + angle_vec * 20);
|
||||||
DrawLine(fx-mdx,fy-mdy,fx+mdx,fy+mdy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the rotation line
|
// Draw the fake features on the ring
|
||||||
SetLineColour(colour[0],1.f,1);
|
gl.SetLineColour(colour[0], 1.f, 1);
|
||||||
SetFillColour(colour[1],0.3f);
|
gl.SetFillColour(colour[1], 0.3f);
|
||||||
DrawCircle(deltax,deltay,4);
|
gl.DrawCircle(angle_vec * radius, 4);
|
||||||
|
gl.DrawCircle(angle_vec * -radius, 4);
|
||||||
|
|
||||||
glPopMatrix();
|
// Clear the projection
|
||||||
|
gl.ResetTransform();
|
||||||
|
|
||||||
// Draw line to mouse
|
// Draw line to mouse if it isn't over the origin feature
|
||||||
if (!dragging && curFeature == features.end() && video.x > INT_MIN && video.y > INT_MIN) {
|
if (mouse_pos && (mouse_pos - org->pos).SquareLen() > 100) {
|
||||||
SetLineColour(colour[0]);
|
gl.SetLineColour(colour[0]);
|
||||||
DrawLine(org->x,org->y,video.x,video.y);
|
gl.DrawLine(org->pos, mouse_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolRotateZ::InitializeHold() {
|
bool VisualToolRotateZ::InitializeHold() {
|
||||||
startAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
|
orig_angle = angle + (org->pos - mouse_pos).Angle() * rad2deg;
|
||||||
origAngle = curAngle;
|
|
||||||
curDiag->StripTag("\\frz");
|
|
||||||
curDiag->StripTag("\\fr");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateZ::UpdateHold() {
|
void VisualToolRotateZ::UpdateHold() {
|
||||||
float screenAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
|
angle = orig_angle - (org->pos - mouse_pos).Angle() * rad2deg;
|
||||||
curAngle = fmodf(screenAngle - startAngle + origAngle + 360.f, 360.f);
|
|
||||||
|
|
||||||
// Oh Snap
|
if (ctrl_down)
|
||||||
if (ctrlDown) {
|
angle = floorf(angle / 30.f + .5f) * 30.f;
|
||||||
curAngle = floorf(curAngle/30.f+.5f)*30.f;
|
|
||||||
if (curAngle > 359.f) curAngle = 0.f;
|
angle = fmodf(angle + 360.f, 360.f);
|
||||||
}
|
|
||||||
|
SetSelectedOverride("\\frz", wxString::Format("(%0.3g)", angle));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateZ::CommitHold() {
|
void VisualToolRotateZ::UpdateDrag(feature_iterator feature) {
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||||
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
|
|
||||||
SetOverride(*cur, "\\frz",wxString::Format("(%0.3g)",curAngle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolRotateZ::CommitDrag(feature_iterator feature) {
|
|
||||||
int x = feature->x;
|
|
||||||
int y = feature->y;
|
|
||||||
parent->ToScriptCoords(&x, &y);
|
|
||||||
SetOverride(curDiag, "\\org",wxString::Format("(%i,%i)",x,y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolRotateZ::DoRefresh() {
|
void VisualToolRotateZ::DoRefresh() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
GetLinePosition(curDiag, posx, posy, org->x, org->y);
|
|
||||||
GetLineRotation(curDiag, rx, ry, curAngle);
|
pos = FromScriptCoords(GetLinePosition(active_line));
|
||||||
GetLineScale(curDiag, scaleX, scaleY);
|
if (!(org->pos = GetLineOrigin(active_line)))
|
||||||
|
org->pos = pos;
|
||||||
|
else
|
||||||
|
org->pos = FromScriptCoords(org->pos);
|
||||||
|
|
||||||
|
GetLineRotation(active_line, rotation_x, rotation_y, angle);
|
||||||
|
GetLineScale(active_line, scale);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -37,29 +24,30 @@
|
||||||
#include "visual_feature.h"
|
#include "visual_feature.h"
|
||||||
#include "visual_tool.h"
|
#include "visual_tool.h"
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class VisualToolRotateZ
|
/// @class VisualToolRotateZ
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
|
class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
|
||||||
float curAngle, startAngle, origAngle;
|
float angle; ///< Current Z rotation
|
||||||
Feature *org;
|
float orig_angle; ///< Z rotation at the beginning of the current hold
|
||||||
int posx, posy;
|
Vector2D pos; ///< Position of the dialogue line
|
||||||
float rx, ry;
|
Vector2D scale; ///< Current scale
|
||||||
float scaleX, scaleY;
|
|
||||||
|
float rotation_x; ///< Current X rotation
|
||||||
|
float rotation_y; ///< Current Y rotation
|
||||||
|
|
||||||
|
Feature *org; ///< The origin feature
|
||||||
|
|
||||||
bool InitializeHold();
|
bool InitializeHold();
|
||||||
void UpdateHold();
|
void UpdateHold();
|
||||||
void CommitHold();
|
|
||||||
|
|
||||||
void CommitDrag(feature_iterator feature);
|
void UpdateDrag(feature_iterator feature);
|
||||||
|
|
||||||
void DoRefresh();
|
void DoRefresh();
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
bool Update() { return true; }
|
|
||||||
public:
|
public:
|
||||||
VisualToolRotateZ(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *);
|
VisualToolRotateZ(VideoDisplay *parent, agi::Context *context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -36,126 +23,95 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "include/aegisub/context.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "video_context.h"
|
|
||||||
#include "video_display.h"
|
|
||||||
#include "visual_tool_scale.h"
|
#include "visual_tool_scale.h"
|
||||||
|
|
||||||
VisualToolScale::VisualToolScale(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
#include "utils.h"
|
||||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
|
||||||
, curScaleX(0.f)
|
VisualToolScale::VisualToolScale(VideoDisplay *parent, agi::Context *context)
|
||||||
, origScaleX(0.f)
|
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||||
, curScaleY(0.f)
|
|
||||||
, origScaleY(0.f)
|
|
||||||
, startX(0)
|
|
||||||
, startY(0)
|
|
||||||
{
|
{
|
||||||
DoRefresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolScale::Draw() {
|
void VisualToolScale::Draw() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
int len = 160;
|
// The length in pixels of the 100% zoom
|
||||||
int dx = mid(len/2+10,posx,video.w-len/2-30);
|
static const int base_len = 160;
|
||||||
int dy = mid(len/2+10,posy,video.h-len/2-30);
|
// The width of the y scale guide/height of the x scale guide
|
||||||
|
static const int guide_size = 10;
|
||||||
|
|
||||||
SetLineColour(colour[0]);
|
// Ensure that the scaling UI is comfortably visible on screen
|
||||||
SetFillColour(colour[1],0.3f);
|
Vector2D base_point = pos
|
||||||
|
.Max(Vector2D(base_len / 2 + guide_size, base_len / 2 + guide_size))
|
||||||
|
.Min(video_res - base_len / 2 - guide_size * 3);
|
||||||
|
|
||||||
// Transform grid
|
// Set the origin to the base point and apply the line's rotation
|
||||||
glMatrixMode(GL_MODELVIEW);
|
gl.SetOrigin(base_point);
|
||||||
glPushMatrix();
|
gl.SetRotation(rx, ry, rz);
|
||||||
glLoadIdentity();
|
|
||||||
glTranslatef(dx,dy,0.f);
|
|
||||||
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
|
|
||||||
glMultMatrixf(matrix);
|
|
||||||
glScalef(1.f,1.f,8.f);
|
|
||||||
if (ry != 0.f) glRotatef(ry,0.f,-1.f,0.f);
|
|
||||||
if (rx != 0.f) glRotatef(rx,-1.f,0.f,0.f);
|
|
||||||
if (rz != 0.f) glRotatef(rz,0.f,0.f,-1.f);
|
|
||||||
|
|
||||||
// Scale parameters
|
Vector2D scale_half_length = scale * base_len / 200;
|
||||||
int lenx = int(1.6 * curScaleX);
|
float minor_dim_offset = base_len / 2 + guide_size * 1.5f;
|
||||||
int leny = int(1.6 * curScaleY);
|
|
||||||
int drawX = len/2 + 10;
|
|
||||||
int drawY = len/2 + 10;
|
|
||||||
|
|
||||||
// Draw length markers
|
// The ends of the current scale amount lines
|
||||||
SetLineColour(colour[3],1.f,2);
|
Vector2D x_p1(minor_dim_offset, -scale_half_length.Y());
|
||||||
DrawLine(-lenx/2,drawY+10,lenx/2,drawY+10);
|
Vector2D x_p2(minor_dim_offset, scale_half_length.Y());
|
||||||
DrawLine(drawX+10,-leny/2,drawX+10,leny/2);
|
Vector2D y_p1(-scale_half_length.X(), minor_dim_offset);
|
||||||
SetLineColour(colour[0],1.f,1);
|
Vector2D y_p2(scale_half_length.X(), minor_dim_offset);
|
||||||
SetFillColour(colour[1],0.3f);
|
|
||||||
DrawCircle(lenx/2,drawY+10,4);
|
|
||||||
DrawCircle(drawX+10,-leny/2,4);
|
|
||||||
|
|
||||||
// Draw horizontal scale
|
// Current scale amount lines
|
||||||
SetLineColour(colour[0],1.f,1);
|
gl.SetLineColour(colour[3], 1.f, 2);
|
||||||
DrawRectangle(-len/2,drawY,len/2+1,drawY+5);
|
gl.DrawLine(x_p1, x_p2);
|
||||||
SetLineColour(colour[0],1.f,2);
|
gl.DrawLine(y_p1, y_p2);
|
||||||
DrawLine(-len/2+1,drawY+5,-len/2+1,drawY+15);
|
|
||||||
DrawLine(len/2,drawY+5,len/2,drawY+15);
|
|
||||||
|
|
||||||
// Draw vertical scale
|
// Fake features at the end of the lines
|
||||||
SetLineColour(colour[0],1.f,1);
|
gl.SetLineColour(colour[0], 1.f, 1);
|
||||||
DrawRectangle(drawX,-len/2,drawX+5,len/2+1);
|
gl.SetFillColour(colour[1], 0.3f);
|
||||||
SetLineColour(colour[0],1.f,2);
|
gl.DrawCircle(x_p1, 4);
|
||||||
DrawLine(drawX+5,-len/2+1,drawX+15,-len/2+1);
|
gl.DrawCircle(x_p2, 4);
|
||||||
DrawLine(drawX+5,len/2,drawX+15,len/2);
|
gl.DrawCircle(y_p1, 4);
|
||||||
|
gl.DrawCircle(y_p2, 4);
|
||||||
|
|
||||||
glPopMatrix();
|
// Draw the guides
|
||||||
|
int half_len = base_len / 2;
|
||||||
|
gl.SetLineColour(colour[0], 1.f, 1);
|
||||||
|
gl.DrawRectangle(Vector2D(half_len, -half_len), Vector2D(half_len + guide_size, half_len));
|
||||||
|
gl.DrawRectangle(Vector2D(-half_len, half_len), Vector2D(half_len, half_len + guide_size));
|
||||||
|
|
||||||
|
// Draw the feet
|
||||||
|
gl.SetLineColour(colour[0], 1.f, 2);
|
||||||
|
gl.DrawLine(Vector2D(half_len + guide_size, -half_len), Vector2D(half_len + guide_size + guide_size / 2, -half_len));
|
||||||
|
gl.DrawLine(Vector2D(half_len + guide_size, half_len), Vector2D(half_len + guide_size + guide_size / 2, half_len));
|
||||||
|
gl.DrawLine(Vector2D(-half_len, half_len + guide_size), Vector2D(-half_len, half_len + guide_size + guide_size / 2));
|
||||||
|
gl.DrawLine(Vector2D(half_len, half_len + guide_size), Vector2D(half_len, half_len + guide_size + guide_size / 2));
|
||||||
|
|
||||||
|
gl.ResetTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolScale::InitializeHold() {
|
bool VisualToolScale::InitializeHold() {
|
||||||
startX = video.x;
|
initial_scale = scale;
|
||||||
startY = video.y;
|
|
||||||
origScaleX = curScaleX;
|
|
||||||
origScaleY = curScaleY;
|
|
||||||
curDiag->StripTag("\\fscx");
|
|
||||||
curDiag->StripTag("\\fscy");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolScale::UpdateHold() {
|
void VisualToolScale::UpdateHold() {
|
||||||
// Deltas
|
Vector2D delta = mouse_pos - drag_start;
|
||||||
int deltaX = video.x - startX;
|
if (shift_down)
|
||||||
int deltaY = startY - video.y;
|
delta = delta.SingleAxis();
|
||||||
if (shiftDown) {
|
|
||||||
if (abs(deltaX) >= abs(deltaY)) deltaY = 0;
|
|
||||||
else deltaX = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate
|
scale = Vector2D().Max(delta * 1.25f + initial_scale);
|
||||||
curScaleX = std::max(deltaX*1.25f + origScaleX, 0.f);
|
if (ctrl_down)
|
||||||
curScaleY = std::max(deltaY*1.25f + origScaleY, 0.f);
|
scale = scale.Round(25.f);
|
||||||
|
|
||||||
// Oh Snap
|
SetSelectedOverride("\\fscx", wxString::Format("(%0.3g)", scale.X()));
|
||||||
if (ctrlDown) {
|
SetSelectedOverride("\\fscy", wxString::Format("(%0.3g)", scale.Y()));
|
||||||
curScaleX = floorf(curScaleX/25.f+.5f)*25.f;
|
|
||||||
curScaleY = floorf(curScaleY/25.f+.5f)*25.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolScale::CommitHold() {
|
|
||||||
Selection sel = c->selectionController->GetSelectedSet();
|
|
||||||
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
|
|
||||||
SetOverride(*cur, "\\fscx",wxString::Format("(%0.3g)",curScaleX));
|
|
||||||
SetOverride(*cur, "\\fscy",wxString::Format("(%0.3g)",curScaleY));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolScale::DoRefresh() {
|
void VisualToolScale::DoRefresh() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
GetLineScale(curDiag, curScaleX, curScaleY);
|
GetLineScale(active_line, scale);
|
||||||
GetLinePosition(curDiag, posx, posy);
|
GetLineRotation(active_line, rx, ry, rz);
|
||||||
GetLineRotation(curDiag, rx, ry, rz);
|
pos = FromScriptCoords(GetLinePosition(active_line));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -41,20 +28,19 @@
|
||||||
/// @class VisualToolScale
|
/// @class VisualToolScale
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
class VisualToolScale : public VisualTool<VisualDraggableFeature> {
|
class VisualToolScale : public VisualTool<VisualDraggableFeature> {
|
||||||
float curScaleX, origScaleX;
|
Vector2D scale; ///< The current scale
|
||||||
float curScaleY, origScaleY;
|
Vector2D initial_scale; ///< The scale at the beginning of the current hold
|
||||||
|
Vector2D pos; ///< Position of the line
|
||||||
int startX, startY;
|
|
||||||
int posx, posy;
|
|
||||||
float rx, ry, rz;
|
|
||||||
|
|
||||||
|
float rx; ///< X rotation
|
||||||
|
float ry; ///< Y rotation
|
||||||
|
float rz; ///< Z rotation
|
||||||
|
|
||||||
bool InitializeHold();
|
bool InitializeHold();
|
||||||
void UpdateHold();
|
void UpdateHold();
|
||||||
void CommitHold();
|
|
||||||
|
|
||||||
void DoRefresh();
|
void DoRefresh();
|
||||||
void Draw();
|
void Draw();
|
||||||
public:
|
public:
|
||||||
VisualToolScale(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *);
|
VisualToolScale(VideoDisplay *parent, agi::Context *context);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -38,30 +25,18 @@
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <wx/toolbar.h>
|
#include <wx/toolbar.h>
|
||||||
|
|
||||||
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
|
|
||||||
#include <OpenGL/glext.h>
|
|
||||||
#else
|
|
||||||
#include "gl/glext.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
/// Noop macro, this should never be defined in a header.
|
|
||||||
#define APIENTRY
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "video_display.h"
|
|
||||||
|
|
||||||
/// Button IDs
|
/// Button IDs
|
||||||
enum {
|
enum {
|
||||||
BUTTON_DRAG = VISUAL_SUB_TOOL_START,
|
BUTTON_DRAG = 1300,
|
||||||
BUTTON_LINE,
|
BUTTON_LINE,
|
||||||
BUTTON_BICUBIC,
|
BUTTON_BICUBIC,
|
||||||
BUTTON_CONVERT,
|
BUTTON_CONVERT,
|
||||||
|
@ -72,34 +47,28 @@ enum {
|
||||||
BUTTON_LAST // Leave this at the end and don't use it
|
BUTTON_LAST // Leave this at the end and don't use it
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class C, class O, class M>
|
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context)
|
||||||
static void for_each_iter(C &container, O obj, M method) {
|
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, context)
|
||||||
typename C::iterator end = container.end();
|
, spline(*this)
|
||||||
for (typename C::iterator cur = container.begin(); cur != end; ++cur) {
|
{
|
||||||
(obj ->* method)(cur);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar * toolBar)
|
void VisualToolVectorClip::SetToolbar(wxToolBar *toolBar) {
|
||||||
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, context, video)
|
this->toolBar = toolBar;
|
||||||
, spline(*parent)
|
toolBar->AddTool(BUTTON_DRAG, _("Drag"), GETIMAGE(visual_vector_clip_drag_24), _("Drag control points."), wxITEM_CHECK);
|
||||||
, toolBar(toolBar)
|
toolBar->AddTool(BUTTON_LINE, _("Line"), GETIMAGE(visual_vector_clip_line_24), _("Appends a line."), wxITEM_CHECK);
|
||||||
{
|
toolBar->AddTool(BUTTON_BICUBIC, _("Bicubic"), GETIMAGE(visual_vector_clip_bicubic_24), _("Appends a bezier bicubic curve."), wxITEM_CHECK);
|
||||||
toolBar->AddTool(BUTTON_DRAG,_("Drag"),GETIMAGE(visual_vector_clip_drag_24),_("Drag control points."),wxITEM_CHECK);
|
|
||||||
toolBar->AddTool(BUTTON_LINE,_("Line"),GETIMAGE(visual_vector_clip_line_24),_("Appends a line."),wxITEM_CHECK);
|
|
||||||
toolBar->AddTool(BUTTON_BICUBIC,_("Bicubic"),GETIMAGE(visual_vector_clip_bicubic_24),_("Appends a bezier bicubic curve."),wxITEM_CHECK);
|
|
||||||
toolBar->AddSeparator();
|
toolBar->AddSeparator();
|
||||||
toolBar->AddTool(BUTTON_CONVERT,_("Convert"),GETIMAGE(visual_vector_clip_convert_24),_("Converts a segment between line and bicubic."),wxITEM_CHECK);
|
toolBar->AddTool(BUTTON_CONVERT, _("Convert"), GETIMAGE(visual_vector_clip_convert_24), _("Converts a segment between line and bicubic."), wxITEM_CHECK);
|
||||||
toolBar->AddTool(BUTTON_INSERT,_("Insert"),GETIMAGE(visual_vector_clip_insert_24),_("Inserts a control point."),wxITEM_CHECK);
|
toolBar->AddTool(BUTTON_INSERT, _("Insert"), GETIMAGE(visual_vector_clip_insert_24), _("Inserts a control point."), wxITEM_CHECK);
|
||||||
toolBar->AddTool(BUTTON_REMOVE,_("Remove"),GETIMAGE(visual_vector_clip_remove_24),_("Removes a control point."),wxITEM_CHECK);
|
toolBar->AddTool(BUTTON_REMOVE, _("Remove"), GETIMAGE(visual_vector_clip_remove_24), _("Removes a control point."), wxITEM_CHECK);
|
||||||
toolBar->AddSeparator();
|
toolBar->AddSeparator();
|
||||||
toolBar->AddTool(BUTTON_FREEHAND,_("Freehand"),GETIMAGE(visual_vector_clip_freehand_24),_("Draws a freehand shape."),wxITEM_CHECK);
|
toolBar->AddTool(BUTTON_FREEHAND, _("Freehand"), GETIMAGE(visual_vector_clip_freehand_24), _("Draws a freehand shape."), wxITEM_CHECK);
|
||||||
toolBar->AddTool(BUTTON_FREEHAND_SMOOTH,_("Freehand smooth"),GETIMAGE(visual_vector_clip_freehand_smooth_24),_("Draws a smoothed freehand shape."),wxITEM_CHECK);
|
toolBar->AddTool(BUTTON_FREEHAND_SMOOTH, _("Freehand smooth"), GETIMAGE(visual_vector_clip_freehand_smooth_24), _("Draws a smoothed freehand shape."), wxITEM_CHECK);
|
||||||
toolBar->ToggleTool(BUTTON_DRAG,true);
|
toolBar->ToggleTool(BUTTON_DRAG, true);
|
||||||
toolBar->Realize();
|
toolBar->Realize();
|
||||||
toolBar->Show(true);
|
toolBar->Show(true);
|
||||||
|
toolBar->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VisualToolVectorClip::OnSubTool, this);
|
||||||
DoRefresh();
|
|
||||||
SetMode(features.empty());
|
SetMode(features.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,35 +76,23 @@ void VisualToolVectorClip::OnSubTool(wxCommandEvent &event) {
|
||||||
SetMode(event.GetId() - BUTTON_DRAG);
|
SetMode(event.GetId() - BUTTON_DRAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::SetMode(int newMode) {
|
void VisualToolVectorClip::SetMode(int new_mode) {
|
||||||
// Manually enforce radio behavior as we want one selection in the bar
|
// Manually enforce radio behavior as we want one selection in the bar
|
||||||
// rather than one per group
|
// rather than one per group
|
||||||
for (int i=BUTTON_DRAG;i<BUTTON_LAST;i++) {
|
for (int i = BUTTON_DRAG; i < BUTTON_LAST; i++)
|
||||||
toolBar->ToggleTool(i,i == newMode + BUTTON_DRAG);
|
toolBar->ToggleTool(i, i == new_mode + BUTTON_DRAG);
|
||||||
}
|
|
||||||
mode = newMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substitute for glMultiDrawArrays for sub-1.4 OpenGL
|
mode = new_mode;
|
||||||
// Not required on OS X.
|
|
||||||
#ifndef __APPLE__
|
|
||||||
static void APIENTRY glMultiDrawArraysFallback(GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount) {
|
|
||||||
for (int i = 0; i < primcount; ++i) {
|
|
||||||
glDrawArrays(mode, *first++, *count++);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool is_move(SplineCurve const& c) {
|
static bool is_move(SplineCurve const& c) {
|
||||||
return c.type == CURVE_POINT;
|
return c.type == SplineCurve::POINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::Draw() {
|
void VisualToolVectorClip::Draw() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
if (spline.empty()) return;
|
if (spline.empty()) return;
|
||||||
|
|
||||||
GL_EXT(PFNGLMULTIDRAWARRAYSPROC, glMultiDrawArrays);
|
|
||||||
|
|
||||||
// Parse vector
|
// Parse vector
|
||||||
std::vector<float> points;
|
std::vector<float> points;
|
||||||
std::vector<int> start;
|
std::vector<int> start;
|
||||||
|
@ -145,77 +102,32 @@ void VisualToolVectorClip::Draw() {
|
||||||
assert(!start.empty());
|
assert(!start.empty());
|
||||||
assert(!count.empty());
|
assert(!count.empty());
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
gl.SetLineColour(colour[3], 1.f, 2);
|
||||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
gl.SetFillColour(wxColour(0, 0, 0), 0.5f);
|
||||||
|
|
||||||
// The following is nonzero winding-number PIP based on stencils
|
gl.DrawMultiPolygon(points, start, count, video_res, !inverse);
|
||||||
|
|
||||||
// Draw to stencil only
|
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
glColorMask(0, 0, 0, 0);
|
|
||||||
|
|
||||||
// GL_INCR_WRAP was added in 1.4, so instead set the entire stencil to 128
|
|
||||||
// and wobble from there
|
|
||||||
glStencilFunc(GL_NEVER, 128, 0xFF);
|
|
||||||
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
|
||||||
DrawRectangle(0,0,video.w,video.h);
|
|
||||||
|
|
||||||
// Increment the winding number for each forward facing triangle
|
|
||||||
glStencilOp(GL_INCR, GL_INCR, GL_INCR);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
|
|
||||||
|
|
||||||
// Decrement the winding number for each backfacing triangle
|
|
||||||
glStencilOp(GL_DECR, GL_DECR, GL_DECR);
|
|
||||||
glCullFace(GL_FRONT);
|
|
||||||
glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
|
|
||||||
// Draw the actual rectangle
|
|
||||||
glColorMask(1,1,1,1);
|
|
||||||
SetLineColour(colour[3],0.f);
|
|
||||||
SetFillColour(wxColour(0,0,0),0.5f);
|
|
||||||
|
|
||||||
// VSFilter draws when the winding number is nonzero, so we want to draw the
|
|
||||||
// mask when the winding number is zero (where 128 is zero due to the lack of
|
|
||||||
// wrapping combined with unsigned numbers)
|
|
||||||
glStencilFunc(inverse ? GL_NOTEQUAL : GL_EQUAL, 128, 0xFF);
|
|
||||||
DrawRectangle(0,0,video.w,video.h);
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
|
||||||
|
|
||||||
// Draw lines
|
|
||||||
SetFillColour(colour[3],0.f);
|
|
||||||
SetLineColour(colour[3],1.f,2);
|
|
||||||
SetModeLine();
|
|
||||||
glMultiDrawArrays(GL_LINE_LOOP, &start[0], &count[0], start.size());
|
|
||||||
|
|
||||||
Vector2D pt;
|
Vector2D pt;
|
||||||
float t;
|
float t;
|
||||||
Spline::iterator highCurve;
|
Spline::iterator highlighted_curve;
|
||||||
spline.GetClosestParametricPoint(Vector2D(video.x, video.y), highCurve, t, pt);
|
spline.GetClosestParametricPoint(mouse_pos, highlighted_curve, t, pt);
|
||||||
|
|
||||||
// Draw highlighted line
|
// Draw highlighted line
|
||||||
if ((mode == 3 || mode == 4) && curFeature == features.end() && points.size() > 2) {
|
if ((mode == 3 || mode == 4) && active_feature == features.end() && points.size() > 2) {
|
||||||
std::vector<float> highPoints;
|
std::vector<float> highlighted_points;
|
||||||
spline.GetPointList(highPoints, highCurve);
|
spline.GetPointList(highlighted_points, highlighted_curve);
|
||||||
if (!highPoints.empty()) {
|
if (!highlighted_points.empty()) {
|
||||||
glVertexPointer(2, GL_FLOAT, 0, &highPoints[0]);
|
gl.SetLineColour(colour[2], 1.f, 2);
|
||||||
SetLineColour(colour[2], 1.f, 2);
|
gl.DrawLineStrip(2, highlighted_points);
|
||||||
SetModeLine();
|
|
||||||
glDrawArrays(GL_LINE_STRIP, 0, highPoints.size() / 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
|
|
||||||
// Draw lines connecting the bicubic features
|
// Draw lines connecting the bicubic features
|
||||||
SetLineColour(colour[3],0.9f,1);
|
gl.SetLineColour(colour[3], 0.9f, 1);
|
||||||
for (Spline::iterator cur=spline.begin();cur!=spline.end();cur++) {
|
for (Spline::iterator cur = spline.begin(); cur != spline.end(); ++cur) {
|
||||||
if (cur->type == CURVE_BICUBIC) {
|
if (cur->type == SplineCurve::BICUBIC) {
|
||||||
DrawDashedLine(cur->p1.x,cur->p1.y,cur->p2.x,cur->p2.y,6);
|
gl.DrawDashedLine(cur->p1, cur->p2, 6);
|
||||||
DrawDashedLine(cur->p3.x,cur->p3.y,cur->p4.x,cur->p4.y,6);
|
gl.DrawDashedLine(cur->p3, cur->p4, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,94 +135,84 @@ void VisualToolVectorClip::Draw() {
|
||||||
|
|
||||||
// Draw preview of inserted line
|
// Draw preview of inserted line
|
||||||
if (mode == 1 || mode == 2) {
|
if (mode == 1 || mode == 2) {
|
||||||
if (spline.size() && video.x > INT_MIN && video.y > INT_MIN) {
|
if (spline.size() && mouse_pos) {
|
||||||
Spline::reverse_iterator c0 = std::find_if(spline.rbegin(), spline.rend(), is_move);
|
Spline::reverse_iterator c0 = std::find_if(spline.rbegin(), spline.rend(), is_move);
|
||||||
SplineCurve *c1 = &spline.back();
|
SplineCurve *c1 = &spline.back();
|
||||||
DrawDashedLine(video.x,video.y,c0->p1.x,c0->p1.y,6);
|
gl.DrawDashedLine(mouse_pos, c0->p1, 6);
|
||||||
DrawDashedLine(video.x,video.y,c1->EndPoint().x,c1->EndPoint().y,6);
|
gl.DrawDashedLine(mouse_pos, c1->EndPoint(), 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw preview of insert point
|
// Draw preview of insert point
|
||||||
if (mode == 4) DrawCircle(pt.x,pt.y,4);
|
if (mode == 4)
|
||||||
|
gl.DrawCircle(pt, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
|
void VisualToolVectorClip::MakeFeature(Spline::iterator cur) {
|
||||||
Feature feat;
|
Feature feat;
|
||||||
if (cur->type == CURVE_POINT) {
|
feat.curve = cur;
|
||||||
feat.x = (int)cur->p1.x;
|
|
||||||
feat.y = (int)cur->p1.y;
|
if (cur->type == SplineCurve::POINT) {
|
||||||
|
feat.pos = cur->p1;
|
||||||
feat.type = DRAG_SMALL_CIRCLE;
|
feat.type = DRAG_SMALL_CIRCLE;
|
||||||
feat.curve = cur;
|
|
||||||
feat.point = 0;
|
feat.point = 0;
|
||||||
features.push_back(feat);
|
|
||||||
}
|
}
|
||||||
|
else if (cur->type == SplineCurve::LINE) {
|
||||||
else if (cur->type == CURVE_LINE) {
|
feat.pos = cur->p2;
|
||||||
feat.x = (int)cur->p2.x;
|
|
||||||
feat.y = (int)cur->p2.y;
|
|
||||||
feat.type = DRAG_SMALL_CIRCLE;
|
feat.type = DRAG_SMALL_CIRCLE;
|
||||||
feat.curve = cur;
|
|
||||||
feat.point = 1;
|
feat.point = 1;
|
||||||
features.push_back(feat);
|
|
||||||
}
|
}
|
||||||
|
else if (cur->type == SplineCurve::BICUBIC) {
|
||||||
else if (cur->type == CURVE_BICUBIC) {
|
|
||||||
// Control points
|
// Control points
|
||||||
feat.x = (int)cur->p2.x;
|
feat.pos = cur->p2;
|
||||||
feat.y = (int)cur->p2.y;
|
|
||||||
feat.curve = cur;
|
|
||||||
feat.point = 1;
|
feat.point = 1;
|
||||||
feat.type = DRAG_SMALL_SQUARE;
|
feat.type = DRAG_SMALL_SQUARE;
|
||||||
features.push_back(feat);
|
features.push_back(feat);
|
||||||
|
|
||||||
feat.x = (int)cur->p3.x;
|
feat.pos = cur->p3;
|
||||||
feat.y = (int)cur->p3.y;
|
|
||||||
feat.point = 2;
|
feat.point = 2;
|
||||||
features.push_back(feat);
|
features.push_back(feat);
|
||||||
|
|
||||||
// End point
|
// End point
|
||||||
feat.x = (int)cur->p4.x;
|
feat.pos = cur->p4;
|
||||||
feat.y = (int)cur->p4.y;
|
|
||||||
feat.type = DRAG_SMALL_CIRCLE;
|
feat.type = DRAG_SMALL_CIRCLE;
|
||||||
feat.point = 3;
|
feat.point = 3;
|
||||||
features.push_back(feat);
|
|
||||||
}
|
}
|
||||||
|
features.push_back(feat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::MakeFeatures() {
|
void VisualToolVectorClip::MakeFeatures() {
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
features.clear();
|
features.clear();
|
||||||
for_each_iter(spline, this, &VisualToolVectorClip::MakeFeature);
|
active_feature = features.end();
|
||||||
|
for (Spline::iterator it = spline.begin(); it != spline.end(); ++it)
|
||||||
|
MakeFeature(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::Save() {
|
void VisualToolVectorClip::Save() {
|
||||||
SetOverride(curDiag, inverse ? "\\iclip" : "\\clip", "(" + spline.EncodeToASS() + ")");
|
SetOverride(active_line, inverse ? "\\iclip" : "\\clip", "(" + spline.EncodeToASS() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::UpdateDrag(feature_iterator feature) {
|
void VisualToolVectorClip::UpdateDrag(feature_iterator feature) {
|
||||||
spline.MovePoint(feature->curve,feature->point,Vector2D(feature->x,feature->y));
|
spline.MovePoint(feature->curve, feature->point, feature->pos);
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolVectorClip::CommitDrag(feature_iterator) {
|
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
||||||
if (mode != 5) return true;
|
if (mode != 5) return true;
|
||||||
|
|
||||||
if (feature->curve->type == CURVE_BICUBIC && (feature->point == 1 || feature->point == 2)) {
|
if (feature->curve->type == SplineCurve::BICUBIC && (feature->point == 1 || feature->point == 2)) {
|
||||||
// Deleting bicubic curve handles, so convert to line
|
// Deleting bicubic curve handles, so convert to line
|
||||||
feature->curve->type = CURVE_LINE;
|
feature->curve->type = SplineCurve::LINE;
|
||||||
feature->curve->p2 = feature->curve->p4;
|
feature->curve->p2 = feature->curve->p4;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Spline::iterator next = feature->curve;
|
Spline::iterator next = feature->curve;
|
||||||
next++;
|
next++;
|
||||||
if (next != spline.end()) {
|
if (next != spline.end()) {
|
||||||
if (feature->curve->type == CURVE_POINT) {
|
if (feature->curve->type == SplineCurve::POINT) {
|
||||||
next->p1 = next->EndPoint();
|
next->p1 = next->EndPoint();
|
||||||
next->type = CURVE_POINT;
|
next->type = SplineCurve::POINT;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
next->p1 = feature->curve->p1;
|
next->p1 = feature->curve->p1;
|
||||||
|
@ -319,7 +221,7 @@ bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
||||||
|
|
||||||
spline.erase(feature->curve);
|
spline.erase(feature->curve);
|
||||||
}
|
}
|
||||||
curFeature = features.end();
|
active_feature = features.end();
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
MakeFeatures();
|
MakeFeatures();
|
||||||
|
@ -333,21 +235,20 @@ bool VisualToolVectorClip::InitializeHold() {
|
||||||
if (mode == 1 || mode == 2) {
|
if (mode == 1 || mode == 2) {
|
||||||
SplineCurve curve;
|
SplineCurve curve;
|
||||||
|
|
||||||
// Set start position
|
// New spline beginning at the clicked point
|
||||||
if (!spline.empty()) {
|
if (spline.empty()) {
|
||||||
curve.p1 = spline.back().EndPoint();
|
curve.p1 = mouse_pos;
|
||||||
curve.type = mode == 1 ? CURVE_LINE : CURVE_BICUBIC;
|
curve.type = SplineCurve::POINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First point
|
|
||||||
else {
|
else {
|
||||||
curve.p1 = Vector2D(video.x,video.y);
|
// Continue from the spline in progress
|
||||||
curve.type = CURVE_POINT;
|
// Don't bother setting p2 as UpdateHold will handle that
|
||||||
|
curve.p1 = spline.back().EndPoint();
|
||||||
|
curve.type = mode == 1 ? SplineCurve::LINE : SplineCurve::BICUBIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert
|
|
||||||
spline.push_back(curve);
|
spline.push_back(curve);
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
MakeFeature(--spline.end());
|
MakeFeature(--spline.end());
|
||||||
UpdateHold();
|
UpdateHold();
|
||||||
return true;
|
return true;
|
||||||
|
@ -359,93 +260,85 @@ bool VisualToolVectorClip::InitializeHold() {
|
||||||
Vector2D pt;
|
Vector2D pt;
|
||||||
Spline::iterator curve;
|
Spline::iterator curve;
|
||||||
float t;
|
float t;
|
||||||
spline.GetClosestParametricPoint(Vector2D(video.x,video.y),curve,t,pt);
|
spline.GetClosestParametricPoint(mouse_pos, curve, t, pt);
|
||||||
|
|
||||||
// Convert
|
// Convert line <-> bicubic
|
||||||
if (mode == 3) {
|
if (mode == 3) {
|
||||||
if (curve != spline.end()) {
|
if (curve != spline.end()) {
|
||||||
if (curve->type == CURVE_LINE) {
|
if (curve->type == SplineCurve::LINE) {
|
||||||
curve->type = CURVE_BICUBIC;
|
curve->type = SplineCurve::BICUBIC;
|
||||||
curve->p4 = curve->p2;
|
curve->p4 = curve->p2;
|
||||||
curve->p2 = curve->p1 * 0.75 + curve->p4 * 0.25;
|
curve->p2 = curve->p1 * 0.75 + curve->p4 * 0.25;
|
||||||
curve->p3 = curve->p1 * 0.25 + curve->p4 * 0.75;
|
curve->p3 = curve->p1 * 0.25 + curve->p4 * 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (curve->type == CURVE_BICUBIC) {
|
else if (curve->type == SplineCurve::BICUBIC) {
|
||||||
curve->type = CURVE_LINE;
|
curve->type = SplineCurve::LINE;
|
||||||
curve->p2 = curve->p4;
|
curve->p2 = curve->p4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert
|
// Insert
|
||||||
else {
|
else {
|
||||||
// Check if there is at least one curve to split
|
|
||||||
if (spline.empty()) return false;
|
if (spline.empty()) return false;
|
||||||
|
|
||||||
// Split the curve
|
// Split the curve
|
||||||
if (curve == spline.end()) {
|
if (curve == spline.end()) {
|
||||||
SplineCurve ct;
|
SplineCurve ct(spline.back().EndPoint(), spline.front().p1);
|
||||||
ct.type = CURVE_LINE;
|
ct.p2 = ct.p1 * (1 - t) + ct.p2 * t;
|
||||||
ct.p1 = spline.back().EndPoint();
|
|
||||||
ct.p2 = spline.front().p1;
|
|
||||||
ct.p2 = ct.p1*(1-t) + ct.p2*t;
|
|
||||||
spline.push_back(ct);
|
spline.push_back(ct);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SplineCurve c2;
|
SplineCurve c2;
|
||||||
curve->Split(*curve,c2,t);
|
curve->Split(*curve, c2, t);
|
||||||
spline.insert(++curve, c2);
|
spline.insert(++curve, c2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit
|
|
||||||
Save();
|
Save();
|
||||||
MakeFeatures();
|
MakeFeatures();
|
||||||
Commit();
|
Commit();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Freehand
|
// Freehand spline draw
|
||||||
if (mode == 6 || mode == 7) {
|
if (mode == 6 || mode == 7) {
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
features.clear();
|
features.clear();
|
||||||
|
active_feature = features.end();
|
||||||
spline.clear();
|
spline.clear();
|
||||||
SplineCurve curve;
|
spline.push_back(SplineCurve(mouse_pos));
|
||||||
curve.type = CURVE_POINT;
|
|
||||||
curve.p1.x = video.x;
|
|
||||||
curve.p1.y = video.y;
|
|
||||||
spline.push_back(curve);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @todo box selection?
|
||||||
|
if (mode == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to do for mode 5 (remove)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::UpdateHold() {
|
void VisualToolVectorClip::UpdateHold() {
|
||||||
// Insert line
|
|
||||||
if (mode == 1) {
|
if (mode == 1) {
|
||||||
spline.back().EndPoint() = Vector2D(video.x,video.y);
|
spline.back().EndPoint() = mouse_pos;
|
||||||
features.back().x = video.x;
|
features.back().pos = mouse_pos;
|
||||||
features.back().y = video.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert bicubic
|
// Insert bicubic
|
||||||
else if (mode == 2) {
|
else if (mode == 2) {
|
||||||
SplineCurve &curve = spline.back();
|
SplineCurve &curve = spline.back();
|
||||||
curve.EndPoint() = Vector2D(video.x,video.y);
|
curve.EndPoint() = mouse_pos;
|
||||||
|
|
||||||
// Control points
|
// Control points
|
||||||
if (spline.size() > 1) {
|
if (spline.size() > 1) {
|
||||||
std::list<SplineCurve>::reverse_iterator iter = spline.rbegin();
|
SplineCurve &c0 = spline.back();
|
||||||
iter++;
|
float len = (curve.p4 - curve.p1).Len();
|
||||||
SplineCurve &c0 = *iter;
|
curve.p2 = (c0.type == SplineCurve::LINE ? c0.p2 - c0.p1 : c0.p4 - c0.p3).Unit() * (0.25f * len) + curve.p1;
|
||||||
Vector2D prevVector;
|
|
||||||
float len = (curve.p4-curve.p1).Len();
|
|
||||||
if (c0.type == CURVE_LINE) prevVector = c0.p2-c0.p1;
|
|
||||||
else prevVector = c0.p4-c0.p3;
|
|
||||||
curve.p2 = prevVector.Unit() * (0.25f*len) + curve.p1;
|
|
||||||
}
|
}
|
||||||
else curve.p2 = curve.p1 * 0.75 + curve.p4 * 0.25;
|
else
|
||||||
|
curve.p2 = curve.p1 * 0.75 + curve.p4 * 0.25;
|
||||||
curve.p3 = curve.p1 * 0.25 + curve.p4 * 0.75;
|
curve.p3 = curve.p1 * 0.25 + curve.p4 * 0.75;
|
||||||
MakeFeatures();
|
MakeFeatures();
|
||||||
}
|
}
|
||||||
|
@ -454,27 +347,19 @@ void VisualToolVectorClip::UpdateHold() {
|
||||||
else if (mode == 6 || mode == 7) {
|
else if (mode == 6 || mode == 7) {
|
||||||
// See if distance is enough
|
// See if distance is enough
|
||||||
Vector2D const& last = spline.back().EndPoint();
|
Vector2D const& last = spline.back().EndPoint();
|
||||||
int len = (int)Vector2D(last.x-video.x, last.y-video.y).Len();
|
float len = (last - mouse_pos).SquareLen();
|
||||||
if (mode == 6 && len < 30) return;
|
if (mode == 6 && len < 900) return;
|
||||||
if (mode == 7 && len < 60) return;
|
if (mode == 7 && len < 3600) return;
|
||||||
|
|
||||||
// Generate curve and add it
|
spline.push_back(SplineCurve(last, mouse_pos));
|
||||||
SplineCurve curve;
|
|
||||||
curve.type = CURVE_LINE;
|
|
||||||
curve.p1 = Vector2D(last.x,last.y);
|
|
||||||
curve.p2 = Vector2D(video.x,video.y);
|
|
||||||
spline.push_back(curve);
|
|
||||||
MakeFeature(--spline.end());
|
MakeFeature(--spline.end());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void VisualToolVectorClip::CommitHold() {
|
|
||||||
if (mode == 3 || mode == 4) return;
|
if (mode == 3 || mode == 4) return;
|
||||||
|
|
||||||
// Smooth spline
|
// Smooth spline
|
||||||
if (!holding && mode == 7) {
|
if (!holding && mode == 7)
|
||||||
spline.Smooth();
|
spline.Smooth();
|
||||||
}
|
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
|
|
||||||
|
@ -486,11 +371,11 @@ void VisualToolVectorClip::CommitHold() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::DoRefresh() {
|
void VisualToolVectorClip::DoRefresh() {
|
||||||
if (!curDiag) return;
|
if (!active_line) return;
|
||||||
|
|
||||||
wxString vect;
|
wxString vect;
|
||||||
int scale;
|
int scale;
|
||||||
vect = GetLineVectorClip(curDiag,scale,inverse);
|
vect = GetLineVectorClip(active_line, scale, inverse);
|
||||||
spline.DecodeFromASS(vect);
|
spline.DecodeFromASS(vect);
|
||||||
|
|
||||||
MakeFeatures();
|
MakeFeatures();
|
||||||
|
@ -498,6 +383,7 @@ void VisualToolVectorClip::DoRefresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualToolVectorClip::SelectAll() {
|
void VisualToolVectorClip::SelectAll() {
|
||||||
ClearSelection();
|
sel_features.clear();
|
||||||
for_each_iter(features, this, &VisualToolVectorClip::AddSelection);
|
for (feature_iterator it = features.begin(); it != features.end(); ++it)
|
||||||
|
sel_features.insert(it);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
// All rights reserved.
|
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
// modification, are permitted provided that the following conditions are met:
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright notice,
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
// this list of conditions and the following disclaimer.
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
// and/or other materials provided with the distribution.
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
// may be used to endorse or promote products derived from this software
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
|
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
//
|
//
|
||||||
|
@ -43,8 +30,7 @@ class wxToolBar;
|
||||||
/// @class VisualToolVectorClipDraggableFeature
|
/// @class VisualToolVectorClipDraggableFeature
|
||||||
/// @brief VisualDraggableFeature with information about a feature's location
|
/// @brief VisualDraggableFeature with information about a feature's location
|
||||||
/// in the spline
|
/// in the spline
|
||||||
class VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
|
struct VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
|
||||||
public:
|
|
||||||
/// Which curve in the spline this feature is a point on
|
/// Which curve in the spline this feature is a point on
|
||||||
Spline::iterator curve;
|
Spline::iterator curve;
|
||||||
/// 0-3; indicates which part of the curve this point is
|
/// 0-3; indicates which part of the curve this point is
|
||||||
|
@ -77,17 +63,15 @@ class VisualToolVectorClip : public VisualTool<VisualToolVectorClipDraggableFeat
|
||||||
|
|
||||||
bool InitializeHold();
|
bool InitializeHold();
|
||||||
void UpdateHold();
|
void UpdateHold();
|
||||||
void CommitHold();
|
|
||||||
|
|
||||||
void UpdateDrag(feature_iterator feature);
|
void UpdateDrag(feature_iterator feature);
|
||||||
void CommitDrag(feature_iterator feature);
|
|
||||||
bool InitializeDrag(feature_iterator feature);
|
bool InitializeDrag(feature_iterator feature);
|
||||||
|
|
||||||
void DoRefresh();
|
void DoRefresh();
|
||||||
void Draw();
|
void Draw();
|
||||||
bool Update() { return mode >= 1 && mode <= 4; }
|
|
||||||
public:
|
public:
|
||||||
VisualToolVectorClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *toolbar);
|
VisualToolVectorClip(VideoDisplay *parent, agi::Context *context);
|
||||||
|
void SetToolbar(wxToolBar *tb);
|
||||||
|
|
||||||
/// Subtoolbar button click handler
|
/// Subtoolbar button click handler
|
||||||
void OnSubTool(wxCommandEvent &event);
|
void OnSubTool(wxCommandEvent &event);
|
||||||
|
|
Loading…
Reference in a new issue