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"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\command\vis_tool.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Preferences"
|
||||
|
|
|
@ -288,6 +288,7 @@
|
|||
<ClCompile Include="$(SrcDir)command\timecode.cpp" />
|
||||
<ClCompile Include="$(SrcDir)command\tool.cpp" />
|
||||
<ClCompile Include="$(SrcDir)command\video.cpp" />
|
||||
<ClCompile Include="$(SrcDir)command\vis_tool.cpp" />
|
||||
<ClCompile Include="$(SrcDir)compat.cpp" />
|
||||
<ClCompile Include="$(SrcDir)dialog_about.cpp" />
|
||||
<ClCompile Include="$(SrcDir)dialog_attachments.cpp" />
|
||||
|
|
|
@ -1196,6 +1196,9 @@
|
|||
<ClCompile Include="$(SrcDir)command\video.cpp">
|
||||
<Filter>Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)command\vis_tool.cpp">
|
||||
<Filter>Commands</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)pen.cpp">
|
||||
<Filter>Utilities\UI utilities</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -160,6 +160,7 @@
|
|||
#include <wx/msgdlg.h>
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/numformatter.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/power.h>
|
||||
#include <wx/protocol/http.h>
|
||||
|
@ -170,11 +171,11 @@
|
|||
#include <wx/regex.h>
|
||||
#include <wx/sashwin.h>
|
||||
#include <wx/scrolbar.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/stackwalk.h>
|
||||
#include <wx/statbmp.h>
|
||||
#include <wx/statbox.h>
|
||||
|
|
|
@ -121,6 +121,8 @@ protected:
|
|||
void AdjustScrollbar();
|
||||
void SetColumnWidths();
|
||||
|
||||
bool IsDisplayed(const AssDialogue *line) const;
|
||||
|
||||
// Re-implement functions from BaseSelectionController to add batching
|
||||
void AnnounceActiveLineChanged(AssDialogue *new_line);
|
||||
void AnnounceSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
||||
|
@ -139,7 +141,6 @@ public:
|
|||
void EndBatch();
|
||||
void SetByFrame(bool state);
|
||||
|
||||
bool IsDisplayed(const AssDialogue *line) const;
|
||||
void SelectRow(int row, bool addToSelected = false, bool select=true);
|
||||
int GetFirstSelRow() const;
|
||||
wxArrayInt GetSelection() const;
|
||||
|
|
|
@ -21,7 +21,8 @@ SRC = \
|
|||
time.cpp \
|
||||
timecode.cpp \
|
||||
tool.cpp \
|
||||
video.cpp
|
||||
video.cpp \
|
||||
vis_tool.cpp
|
||||
|
||||
SRC += \
|
||||
icon.cpp \
|
||||
|
|
|
@ -88,6 +88,7 @@ namespace cmd {
|
|||
void init_timecode();
|
||||
void init_tool();
|
||||
void init_video();
|
||||
void init_visual_tools();
|
||||
|
||||
void init_builtin_commands() {
|
||||
LOG_D("command/init") << "Populating command map";
|
||||
|
@ -104,6 +105,7 @@ namespace cmd {
|
|||
init_timecode();
|
||||
init_tool();
|
||||
init_video();
|
||||
init_visual_tools();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
|
|
@ -198,6 +198,13 @@ INSERT_ICON("video/opt/autoscroll", toggle_video_autoscroll)
|
|||
INSERT_ICON("video/play", button_play)
|
||||
INSERT_ICON("video/play/line", button_playline)
|
||||
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/out", zoom_out_button)
|
||||
|
||||
|
|
|
@ -238,10 +238,7 @@ struct video_copy_coordinates : public validator_video_loaded {
|
|||
|
||||
void operator()(agi::Context *c) {
|
||||
if (wxTheClipboard->Open()) {
|
||||
int x, y;
|
||||
c->videoBox->videoDisplay->GetMousePosition(&x, &y);
|
||||
c->videoBox->videoDisplay->ToScriptCoords(&x, &y);
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%d,%d", x, y)));
|
||||
wxTheClipboard->SetData(new wxTextDataObject(c->videoBox->videoDisplay->GetMousePosition().Str()));
|
||||
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 "validators.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "video_provider_manager.h"
|
||||
|
||||
DialogProperties::DialogProperties(agi::Context *c)
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include "selection_controller.h"
|
||||
#include "subs_edit_ctrl.h"
|
||||
#include "subs_grid.h"
|
||||
#include "video_display.h"
|
||||
|
||||
// IDs
|
||||
enum {
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
#include "utils.h"
|
||||
#include "validators.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
||||
/// Window IDs
|
||||
enum {
|
||||
|
|
|
@ -342,20 +342,30 @@ void OpenGLTextTexture::Insert(OpenGLTextGlyph &glyph) {
|
|||
|
||||
/// Draw a glyph at (x,y)
|
||||
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);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(x1,y1); glVertex2f(0,0); // Top-left
|
||||
glTexCoord2f(x1,y2); glVertex2f(0,h); // Bottom-left
|
||||
glTexCoord2f(x2,y2); glVertex2f(w,h); // Bottom-right
|
||||
glTexCoord2f(x2,y1); glVertex2f(w,0); // Top-right
|
||||
glEnd();
|
||||
float tex_coords[] = {
|
||||
x1, y1,
|
||||
x1, y2,
|
||||
x2, y2,
|
||||
x2, y1
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -42,303 +29,417 @@
|
|||
#ifndef AGI_PRE
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "gl/glext.h"
|
||||
#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() {
|
||||
r1 = g1 = b1 = a1 = 1.0f;
|
||||
r2 = g2 = b2 = a2 = 1.0f;
|
||||
lw = 1;
|
||||
line_r = line_g = line_b = line_a = 1.f;
|
||||
fill_r = fill_g = fill_b = fill_a = 1.f;
|
||||
line_width = 1;
|
||||
transform_pushed = false;
|
||||
smooth = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Draw line
|
||||
/// @param x1
|
||||
/// @param y1
|
||||
/// @param x2
|
||||
/// @param y2
|
||||
///
|
||||
void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) const {
|
||||
void OpenGLWrapper::DrawLine(Vector2D p1, Vector2D p2) const {
|
||||
SetModeLine();
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(x1,y1);
|
||||
glVertex2f(x2,y2);
|
||||
glEnd();
|
||||
VertexArray buf(2, 2);
|
||||
buf.Set(0, p1);
|
||||
buf.Set(1, p2);
|
||||
buf.Draw(GL_LINES);
|
||||
}
|
||||
|
||||
static inline Vector2D interp(Vector2D p1, Vector2D p2, float t) {
|
||||
return t * p1 + (1 - t) * p2;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Draw line
|
||||
/// @param x1
|
||||
/// @param y1
|
||||
/// @param x2
|
||||
/// @param y2
|
||||
/// @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::DrawDashedLine(Vector2D p1, Vector2D p2, float step) const {
|
||||
float dist = (p2 - p1).Len();
|
||||
step /= dist;
|
||||
dist -= step;
|
||||
for (float t = 0; t < 1.f; t += 2 * step) {
|
||||
DrawLine(interp(p1, p2, t), interp(p1, p2, t + step));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @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::DrawEllipse(Vector2D center, Vector2D radius) const {
|
||||
DrawRing(center, radius.Y(), radius.Y(), radius.X() / radius.Y());
|
||||
}
|
||||
|
||||
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
|
||||
if (a2 != 0.0) {
|
||||
if (fill_a != 0.0) {
|
||||
SetModeFill();
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(x1,y1);
|
||||
glVertex2f(x2,y1);
|
||||
glVertex2f(x2,y2);
|
||||
glVertex2f(x1,y2);
|
||||
glEnd();
|
||||
buf.Draw(GL_QUADS, false);
|
||||
}
|
||||
|
||||
// Outline
|
||||
if (a1 != 0.0) {
|
||||
if (line_a != 0.0) {
|
||||
SetModeLine();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(x1,y1);
|
||||
glVertex2f(x2,y1);
|
||||
glVertex2f(x2,y2);
|
||||
glVertex2f(x1,y2);
|
||||
glEnd();
|
||||
buf.Draw(GL_LINE_LOOP);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if (a2 != 0.0) {
|
||||
if (fill_a != 0.0) {
|
||||
SetModeFill();
|
||||
glBegin(GL_TRIANGLES);
|
||||
glVertex2f(x1,y1);
|
||||
glVertex2f(x2,y2);
|
||||
glVertex2f(x3,y3);
|
||||
glEnd();
|
||||
buf.Draw(GL_TRIANGLES, false);
|
||||
}
|
||||
|
||||
// Outline
|
||||
if (a1 != 0.0) {
|
||||
if (line_a != 0.0) {
|
||||
SetModeLine();
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex2f(x1,y1);
|
||||
glVertex2f(x2,y2);
|
||||
glVertex2f(x3,y3);
|
||||
glEnd();
|
||||
buf.Draw(GL_LINE_LOOP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Draw ring (annulus)
|
||||
/// @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;
|
||||
}
|
||||
void OpenGLWrapper::DrawRing(Vector2D center, float r1, float r2, float ar, float arc_start, float arc_end) const {
|
||||
if (r2 > r1)
|
||||
std::swap(r1, r2);
|
||||
|
||||
// Arc range
|
||||
bool hasEnds = arcStart != arcEnd;
|
||||
float pi = 3.1415926535897932384626433832795f;
|
||||
arcEnd *= pi / 180.f;
|
||||
arcStart *= pi / 180.f;
|
||||
if (arcEnd <= arcStart) arcEnd += 2.0f*pi;
|
||||
float range = arcEnd - arcStart;
|
||||
bool needs_end_caps = arc_start != arc_end;
|
||||
|
||||
arc_end *= deg2rad;
|
||||
arc_start *= deg2rad;
|
||||
if (arc_end <= arc_start)
|
||||
arc_end += 2.f * pi;
|
||||
float range = arc_end - arc_start;
|
||||
|
||||
// Math
|
||||
int steps = int((r1 + r1*ar) * range / (2.0f*pi))*4;
|
||||
if (steps < 12) steps = 12;
|
||||
//float end = arcEnd;
|
||||
float step = range/steps;
|
||||
float curAngle = arcStart;
|
||||
int steps = std::max<int>(((r1 + r1 * ar) * range / (2.f * pi)) * 4, 12);
|
||||
float step = range / steps;
|
||||
float cur_angle = arc_start;
|
||||
|
||||
// Fill
|
||||
if (a2 != 0.0) {
|
||||
VertexArray buf(2, steps);
|
||||
|
||||
Vector2D scale_inner = Vector2D(ar, 1) * r1;
|
||||
Vector2D scale_outer = Vector2D(ar, 1) * r2;
|
||||
|
||||
if (fill_a != 0.0) {
|
||||
SetModeFill();
|
||||
|
||||
// Annulus
|
||||
if (r1 != r2) {
|
||||
glBegin(GL_QUADS);
|
||||
for (int i=0;i<steps;i++) {
|
||||
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
|
||||
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
|
||||
curAngle += step;
|
||||
glVertex2f(x+sin(curAngle)*r2*ar,y+cos(curAngle)*r2);
|
||||
glVertex2f(x+sin(curAngle)*r1*ar,y+cos(curAngle)*r1);
|
||||
buf.SetSize(2, (steps + 1) * 2);
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
Vector2D offset = Vector2D::FromAngle(cur_angle);
|
||||
buf.Set(i * 2 + 0, center + offset * scale_inner);
|
||||
buf.Set(i * 2 + 1, center + offset * scale_outer);
|
||||
cur_angle += step;
|
||||
}
|
||||
glEnd();
|
||||
buf.Draw(GL_QUAD_STRIP);
|
||||
}
|
||||
|
||||
// Circle
|
||||
else {
|
||||
glBegin(GL_POLYGON);
|
||||
for (int i=0;i<steps;i++) {
|
||||
glVertex2f(x+sin(curAngle)*r1,y+cos(curAngle)*r1);
|
||||
curAngle += step;
|
||||
buf.SetSize(2, steps);
|
||||
for (int i = 0; i < steps; i++) {
|
||||
buf.Set(i, center + Vector2D::FromAngle(cur_angle) * scale_inner);
|
||||
cur_angle += step;
|
||||
}
|
||||
glEnd();
|
||||
buf.Draw(GL_POLYGON);
|
||||
}
|
||||
|
||||
// Reset angle
|
||||
curAngle = arcStart;
|
||||
cur_angle = arc_start;
|
||||
}
|
||||
|
||||
// Outlines
|
||||
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();
|
||||
if (line_a == 0.0) return;
|
||||
|
||||
// Inner
|
||||
if (r1 != r2) {
|
||||
curAngle = arcStart;
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (int i=0;i<steps;i++) {
|
||||
glVertex2f(x+sin(curAngle)*r2,y+cos(curAngle)*r2);
|
||||
curAngle += step;
|
||||
}
|
||||
glEnd();
|
||||
// Outer
|
||||
steps++;
|
||||
buf.SetSize(2, steps);
|
||||
|
||||
// End caps
|
||||
if (hasEnds) {
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(x+sin(arcStart)*r1,y+cos(arcStart)*r1);
|
||||
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();
|
||||
}
|
||||
}
|
||||
SetModeLine();
|
||||
for (int i = 0; i < steps; i++) {
|
||||
buf.Set(i, center + Vector2D::FromAngle(cur_angle) * scale_outer);
|
||||
cur_angle += step;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Set line colour
|
||||
/// @param col
|
||||
/// @param alpha
|
||||
/// @param 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::SetLineColour(wxColour col, float alpha, int width) {
|
||||
line_r = col.Red() / 255.f;
|
||||
line_g = col.Green() / 255.f;
|
||||
line_b = col.Blue() / 255.f;
|
||||
line_a = alpha;
|
||||
line_width = width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Set fill colour
|
||||
/// @param col
|
||||
/// @param 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;
|
||||
void OpenGLWrapper::SetFillColour(wxColour col, float alpha) {
|
||||
fill_r = col.Red() / 255.f;
|
||||
fill_g = col.Green() / 255.f;
|
||||
fill_b = col.Blue() / 255.f;
|
||||
fill_a = alpha;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Line
|
||||
///
|
||||
void OpenGLWrapper::SetModeLine() const {
|
||||
glColor4f(r1,g1,b1,a1);
|
||||
glColor4f(line_r, line_g, line_b, line_a);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
glLineWidth(lw);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glLineWidth(line_width);
|
||||
if (smooth)
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
else
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Fill
|
||||
///
|
||||
void OpenGLWrapper::SetModeFill() const {
|
||||
glColor4f(r2,g2,b2,a2);
|
||||
if (a2 == 1.0f) glDisable(GL_BLEND);
|
||||
glColor4f(fill_r, fill_g, fill_b, fill_a);
|
||||
if (fill_a == 1.f) glDisable(GL_BLEND);
|
||||
else {
|
||||
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);
|
||||
|
||||
|
||||
/// @brief Is extension supported?
|
||||
/// @param ext
|
||||
/// @return
|
||||
///
|
||||
bool OpenGLWrapper::IsExtensionSupported(const char *ext) {
|
||||
char *extList = (char*) glGetString(GL_EXTENSIONS);
|
||||
if (!extList) return false;
|
||||
return strstr(extList, ext) != NULL;
|
||||
// GL_LINE_SMOOTH combines badly with inverting
|
||||
smooth = false;
|
||||
}
|
||||
|
||||
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
|
||||
wxMutex OpenGLWrapper::glMutex;
|
||||
void OpenGLWrapper::DrawLines(size_t dim, std::vector<float> const& lines, size_t c_dim, std::vector<float> const& colors) {
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -34,41 +21,13 @@
|
|||
/// @ingroup video_output
|
||||
///
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
/// DOCME
|
||||
typedef GLuint GLhandleARB;
|
||||
#endif
|
||||
#include "vector2d.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/thread.h>
|
||||
#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); \
|
||||
}
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
class wxColour;
|
||||
|
||||
/// DOCME
|
||||
/// @class OpenGLWrapper
|
||||
|
@ -76,55 +35,51 @@ typedef GLuint GLhandleARB;
|
|||
///
|
||||
/// DOCME
|
||||
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
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
float r1,g1,b1,a1;
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
float r2,g2,b2,a2;
|
||||
|
||||
/// DOCME
|
||||
int lw;
|
||||
bool transform_pushed;
|
||||
void PrepareTransform();
|
||||
|
||||
public:
|
||||
OpenGLWrapper();
|
||||
|
||||
|
||||
/// DOCME
|
||||
static wxMutex glMutex;
|
||||
|
||||
void SetLineColour(wxColour col,float alpha=1.0f,int width=1);
|
||||
void SetFillColour(wxColour col,float alpha=1.0f);
|
||||
void SetLineColour(wxColour col, float alpha = 1.0f, int width = 1);
|
||||
void SetFillColour(wxColour col, float alpha = 1.0f);
|
||||
void SetModeLine() 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
|
||||
/// @param x
|
||||
/// @param y
|
||||
/// @param radius
|
||||
///
|
||||
void DrawCircle(float x,float y,float radius) const { DrawEllipse(x,y,radius,radius); }
|
||||
void DrawRectangle(float x1,float y1,float x2,float y2) const;
|
||||
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 SetInvert();
|
||||
void ClearInvert();
|
||||
|
||||
void SetScale(Vector2D scale);
|
||||
void SetOrigin(Vector2D origin);
|
||||
void SetRotation(float x, float y, float z);
|
||||
void ResetTransform();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,5 +34,5 @@ namespace toolbar {
|
|||
/// @param context Project context
|
||||
/// @param hotkey Hotkey context for the tooltip
|
||||
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"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool crosshair" : [
|
||||
"video/tool/cross" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "A"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool drag" : [
|
||||
"video/tool/drag" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "S"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool rectangle clip" : [
|
||||
"video/tool/clip" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "H"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool rotate xy" : [
|
||||
"video/tool/rotate/xy" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "F"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool rotate z" : [
|
||||
"video/tool/rotate/z" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "D"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool scale" : [
|
||||
"video/tool/scale" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "G"
|
||||
}
|
||||
],
|
||||
"visual typesetting set tool vector clip" : [
|
||||
"video/tool/vector_clip" : [
|
||||
{
|
||||
"modifiers" : [],
|
||||
"key" : "J"
|
||||
|
|
|
@ -61,5 +61,16 @@
|
|||
"",
|
||||
"app/options",
|
||||
"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"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <limits>
|
||||
|
||||
#include <wx/tokenzr.h>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "spline.h"
|
||||
#include "utils.h"
|
||||
#include "video_display.h"
|
||||
|
||||
/// @brief Spline constructor
|
||||
Spline::Spline(const VideoDisplay &scale) : scale(scale) {
|
||||
#include "utils.h"
|
||||
#include "visual_tool.h"
|
||||
|
||||
Spline::Spline(const VisualToolBase &scale) : scale(scale) {
|
||||
}
|
||||
|
||||
/// @brief Encode to ASS
|
||||
wxString Spline::EncodeToASS() {
|
||||
wxString result;
|
||||
char lastCommand = 0;
|
||||
result.reserve(size() * 10);
|
||||
char last = 0;
|
||||
|
||||
// Insert each element
|
||||
for (iterator cur=begin();cur!=end();cur++) {
|
||||
// Each curve
|
||||
for (iterator cur = begin(); cur != end(); ++cur) {
|
||||
switch (cur->type) {
|
||||
case CURVE_POINT: {
|
||||
if (lastCommand != 'm') {
|
||||
case SplineCurve::POINT:
|
||||
if (last != 'm') {
|
||||
result += "m ";
|
||||
lastCommand = 'm';
|
||||
last = 'm';
|
||||
}
|
||||
int x = cur->p1.x;
|
||||
int y = cur->p1.y;
|
||||
scale.ToScriptCoords(&x, &y);
|
||||
result += wxString::Format("%i %i ", x, y);
|
||||
result += scale.ToScriptCoords(cur->p1).DStr(' ');
|
||||
break;
|
||||
}
|
||||
case CURVE_LINE: {
|
||||
if (lastCommand != 'l') {
|
||||
|
||||
case SplineCurve::LINE:
|
||||
if (last != 'l') {
|
||||
result += "l ";
|
||||
lastCommand = 'l';
|
||||
last = 'l';
|
||||
}
|
||||
int x = cur->p2.x;
|
||||
int y = cur->p2.y;
|
||||
scale.ToScriptCoords(&x, &y);
|
||||
result += wxString::Format("%i %i ", x, y);
|
||||
result += scale.ToScriptCoords(cur->p2).DStr(' ');
|
||||
break;
|
||||
}
|
||||
case CURVE_BICUBIC: {
|
||||
if (lastCommand != 'b') {
|
||||
|
||||
case SplineCurve::BICUBIC:
|
||||
if (last != 'b') {
|
||||
result += "b ";
|
||||
lastCommand = 'b';
|
||||
last = 'b';
|
||||
}
|
||||
int x2 = cur->p2.x;
|
||||
int y2 = cur->p2.y;
|
||||
int x3 = cur->p3.x;
|
||||
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);
|
||||
result += scale.ToScriptCoords(cur->p2).DStr(' ');
|
||||
result += scale.ToScriptCoords(cur->p3).DStr(' ');
|
||||
result += scale.ToScriptCoords(cur->p4).DStr(' ');
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
result += " ";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief Decode from ASS
|
||||
/// @param str
|
||||
void Spline::DecodeFromASS(wxString str) {
|
||||
// Clear current
|
||||
clear();
|
||||
std::vector<int> stack;
|
||||
std::vector<float> stack;
|
||||
|
||||
// Prepare
|
||||
char lastCommand = 'm';
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
char command = 'm';
|
||||
Vector2D pt;
|
||||
|
||||
// Tokenize the string
|
||||
wxStringTokenizer tkn(str," ");
|
||||
wxStringTokenizer tkn(str, " ");
|
||||
while (tkn.HasMoreTokens()) {
|
||||
wxString token = tkn.GetNextToken();
|
||||
|
||||
// Got a number
|
||||
if (token.IsNumber()) {
|
||||
long n;
|
||||
token.ToLong(&n);
|
||||
double n;
|
||||
if (token.ToCDouble(&n)) {
|
||||
stack.push_back(n);
|
||||
|
||||
// Move
|
||||
if (stack.size() == 2 && lastCommand == 'm') {
|
||||
scale.FromScriptCoords(&stack[0], &stack[1]);
|
||||
SplineCurve curve;
|
||||
x = curve.p1.x = stack[0];
|
||||
y = curve.p1.y = stack[1];
|
||||
curve.type = CURVE_POINT;
|
||||
if (stack.size() == 2 && command == 'm') {
|
||||
pt = scale.FromScriptCoords(Vector2D(stack[0], stack[1]));
|
||||
stack.clear();
|
||||
push_back(curve);
|
||||
|
||||
push_back(pt);
|
||||
}
|
||||
|
||||
// Line
|
||||
if (stack.size() == 2 && lastCommand == 'l') {
|
||||
scale.FromScriptCoords(&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();
|
||||
if (stack.size() == 2 && command == 'l') {
|
||||
SplineCurve curve(pt, scale.FromScriptCoords(Vector2D(stack[0], stack[1])));
|
||||
push_back(curve);
|
||||
|
||||
pt = curve.p2;
|
||||
stack.clear();
|
||||
}
|
||||
|
||||
// Bicubic
|
||||
else if (stack.size() == 6 && lastCommand == 'b') {
|
||||
scale.FromScriptCoords(&stack[0], &stack[1]);
|
||||
scale.FromScriptCoords(&stack[2], &stack[3]);
|
||||
scale.FromScriptCoords(&stack[4], &stack[5]);
|
||||
SplineCurve curve;
|
||||
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();
|
||||
else if (stack.size() == 6 && command == 'b') {
|
||||
SplineCurve curve(pt,
|
||||
scale.FromScriptCoords(Vector2D(stack[0], stack[1])),
|
||||
scale.FromScriptCoords(Vector2D(stack[2], stack[3])),
|
||||
scale.FromScriptCoords(Vector2D(stack[4], stack[5])));
|
||||
push_back(curve);
|
||||
}
|
||||
|
||||
// Close
|
||||
else if (lastCommand == 'c') {
|
||||
pt = curve.p4;
|
||||
stack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Got something else
|
||||
else {
|
||||
if (token == "m") lastCommand = 'm';
|
||||
else if (token == "l") lastCommand = 'l';
|
||||
else if (token == "b") lastCommand = 'b';
|
||||
else if (token == "n") lastCommand = 'n';
|
||||
else if (token == "s") lastCommand = 's';
|
||||
else if (token == "c") lastCommand = 'c';
|
||||
else if (token.size() == 1) {
|
||||
command = token[0];
|
||||
stack.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Moves a specific point in the spline
|
||||
/// @param curveIndex
|
||||
/// @param point
|
||||
/// @param pos
|
||||
void Spline::MovePoint(iterator curve,int point,Vector2D const& pos) {
|
||||
void Spline::MovePoint(iterator curve,int point,Vector2D pos) {
|
||||
iterator prev = curve;
|
||||
if (curve != begin()) --prev;
|
||||
iterator next = curve;
|
||||
++next;
|
||||
if (next != end() && next->type == CURVE_POINT) next = end();
|
||||
if (next != end() && next->type == SplineCurve::POINT)
|
||||
next = end();
|
||||
|
||||
// Modify
|
||||
if (point == 0) {
|
||||
curve->p1 = pos;
|
||||
if (curve != begin() && curve->type != CURVE_POINT) prev->EndPoint() = pos;
|
||||
if (next != end() && curve->type == CURVE_POINT) next->p1 = pos;
|
||||
if (curve != begin() && curve->type != SplineCurve::POINT)
|
||||
prev->EndPoint() = pos;
|
||||
if (next != end() && curve->type == SplineCurve::POINT)
|
||||
next->p1 = pos;
|
||||
}
|
||||
else if (point == 1) {
|
||||
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) {
|
||||
curve->p3 = pos;
|
||||
}
|
||||
else if (point == 3) {
|
||||
curve->p4 = pos;
|
||||
if (next != end()) next->p1 = pos;
|
||||
if (next != end())
|
||||
next->p1 = pos;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Gets a list of points in the curve
|
||||
/// @param points
|
||||
/// @param pointCurve
|
||||
static int render_bicubic(Spline::iterator cur, std::vector<float> &points) {
|
||||
int len = int(
|
||||
(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) {
|
||||
points.clear();
|
||||
first.clear();
|
||||
|
@ -232,106 +204,65 @@ void Spline::GetPointList(std::vector<float>& points, std::vector<int>& first, s
|
|||
int curCount = 0;
|
||||
|
||||
// Generate points for each curve
|
||||
for (iterator cur = begin();cur!=end();cur++) {
|
||||
for (iterator cur = begin(); cur != end(); ++cur) {
|
||||
switch (cur->type) {
|
||||
case CURVE_POINT:
|
||||
if (curCount > 0) {
|
||||
case SplineCurve::POINT:
|
||||
if (curCount > 0)
|
||||
count.push_back(curCount);
|
||||
}
|
||||
|
||||
// start new path
|
||||
first.push_back(points.size() / 2);
|
||||
points.push_back(cur->p1.x);
|
||||
points.push_back(cur->p1.y);
|
||||
points.push_back(cur->p1.X());
|
||||
points.push_back(cur->p1.Y());
|
||||
curCount = 1;
|
||||
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
|
||||
int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
|
||||
int steps = len/8;
|
||||
|
||||
// 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;
|
||||
case SplineCurve::LINE:
|
||||
points.push_back(cur->p2.X());
|
||||
points.push_back(cur->p2.Y());
|
||||
++curCount;
|
||||
break;
|
||||
}
|
||||
|
||||
case SplineCurve::BICUBIC:
|
||||
curCount += render_bicubic(cur, points);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
count.push_back(curCount);
|
||||
}
|
||||
|
||||
void Spline::GetPointList(std::vector<float> &points, iterator curve) {
|
||||
points.clear();
|
||||
if (curve == end()) return;
|
||||
switch (curve->type) {
|
||||
case CURVE_LINE:
|
||||
points.push_back(curve->p1.x);
|
||||
points.push_back(curve->p1.y);
|
||||
points.push_back(curve->p2.x);
|
||||
points.push_back(curve->p2.y);
|
||||
case SplineCurve::LINE:
|
||||
points.push_back(curve->p1.X());
|
||||
points.push_back(curve->p1.Y());
|
||||
points.push_back(curve->p2.X());
|
||||
points.push_back(curve->p2.Y());
|
||||
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
|
||||
int len = (int)((p2-p1).Len() + (p3-p2).Len() + (p4-p3).Len());
|
||||
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);
|
||||
}
|
||||
case SplineCurve::BICUBIC:
|
||||
render_bicubic(curve, points);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief t value and curve of the point closest to reference
|
||||
/// @param reference
|
||||
/// @param curve
|
||||
/// @param t
|
||||
/// @param pt
|
||||
void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve,float &t,Vector2D &pt) {
|
||||
void Spline::GetClosestParametricPoint(Vector2D reference,iterator &curve,float &t,Vector2D &pt) {
|
||||
curve = end();
|
||||
t = 0.f;
|
||||
if (empty()) return;
|
||||
|
||||
// Close the shape
|
||||
SplineCurve pad;
|
||||
pad.p1 = back().EndPoint();
|
||||
pad.p2 = front().p1;
|
||||
pad.type = CURVE_LINE;
|
||||
push_back(pad);
|
||||
push_back(SplineCurve(back().EndPoint(), front().p1));
|
||||
|
||||
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);
|
||||
Vector2D p1 = cur->GetPoint(param);
|
||||
float dist = (p1-reference).SquareLen();
|
||||
|
@ -351,19 +282,14 @@ void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve
|
|||
pop_back();
|
||||
}
|
||||
|
||||
/// @brief Point closest to reference
|
||||
/// @param reference
|
||||
/// @return
|
||||
Vector2D Spline::GetClosestPoint(Vector2D const& reference) {
|
||||
Vector2D Spline::GetClosestPoint(Vector2D reference) {
|
||||
iterator curve;
|
||||
float t;
|
||||
Vector2D point;
|
||||
GetClosestParametricPoint(reference,curve,t,point);
|
||||
GetClosestParametricPoint(reference, curve, t, point);
|
||||
return point;
|
||||
}
|
||||
|
||||
/// @brief Smoothes the spline
|
||||
/// @param smooth
|
||||
void Spline::Smooth(float smooth) {
|
||||
// See if there are enough curves
|
||||
if (size() < 3) return;
|
||||
|
@ -371,13 +297,12 @@ void Spline::Smooth(float smooth) {
|
|||
// Smooth curve
|
||||
iterator curve1 = end();
|
||||
--curve1;
|
||||
for (iterator cur = begin(); cur != end();) {
|
||||
for (iterator cur = begin(); cur != end(); ) {
|
||||
iterator curve0 = curve1;
|
||||
curve1 = cur;
|
||||
cur++;
|
||||
++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"
|
||||
|
||||
class VideoDisplay;
|
||||
class VisualToolBase;
|
||||
|
||||
/// DOCME
|
||||
/// @class Spline
|
||||
/// @brief DOCME
|
||||
class Spline : private std::list<SplineCurve> {
|
||||
private:
|
||||
const VideoDisplay &scale;
|
||||
const VisualToolBase &scale;
|
||||
public:
|
||||
Spline(const VideoDisplay &scale);
|
||||
Spline(const VisualToolBase &scale);
|
||||
|
||||
/// Encode to an ASS vector drawing
|
||||
wxString EncodeToASS();
|
||||
|
||||
/// Decode an ASS vector drawing
|
||||
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);
|
||||
|
||||
/// Gets a list of points in the curve
|
||||
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 GetClosestParametricPoint(Vector2D const& reference, iterator& curve, float &t, Vector2D &point);
|
||||
Vector2D GetClosestPoint(Vector2D const& reference);
|
||||
Vector2D GetClosestControlPoint(Vector2D const& reference);
|
||||
/// Get t value and curve of the point closest to reference
|
||||
void GetClosestParametricPoint(Vector2D reference, iterator& curve, float &t, Vector2D &point);
|
||||
/// 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
|
||||
using std::list<SplineCurve>::value_type;
|
||||
|
|
|
@ -34,145 +34,103 @@
|
|||
/// @ingroup visual_ts
|
||||
///
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#include "spline_curve.h"
|
||||
#include "utils.h"
|
||||
|
||||
/// @brief Curve constructor
|
||||
///
|
||||
SplineCurve::SplineCurve() {
|
||||
type = CURVE_INVALID;
|
||||
#ifndef AGI_PRE
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#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
|
||||
/// @param c1
|
||||
/// @param c2
|
||||
/// @param t
|
||||
///
|
||||
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;
|
||||
void SplineCurve::Split(SplineCurve &c1, SplineCurve &c2, float t) {
|
||||
if (type == LINE) {
|
||||
c1 = SplineCurve(p1, p1 * (1 - t) + p2 * t);
|
||||
c2 = SplineCurve(c1.p2, 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
|
||||
else if (type == CURVE_BICUBIC) {
|
||||
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;
|
||||
c1 = SplineCurve(p1, p12, p123, p1234);
|
||||
c2 = SplineCurve(p1234, p234, p34, p4);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Based on http://antigrain.com/research/bezier_interpolation/index.html Smoothes the curve
|
||||
/// @param P0
|
||||
/// @param P3
|
||||
/// @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;
|
||||
void SplineCurve::Smooth(Vector2D p0, Vector2D p3, float smooth) {
|
||||
if (type != LINE || p1 == p2) return;
|
||||
smooth = mid(0.f, smooth, 1.f);
|
||||
|
||||
// Calculate intermediate points
|
||||
Vector2D c1 = (P0+P1)/2.f;
|
||||
Vector2D c2 = (P1+P2)/2.f;
|
||||
Vector2D c3 = (P2+P3)/2.f;
|
||||
float len1 = (P1-P0).Len();
|
||||
float len2 = (P2-P1).Len();
|
||||
float len3 = (P3-P2).Len();
|
||||
float k1 = len1/(len1+len2);
|
||||
float k2 = len2/(len2+len3);
|
||||
Vector2D m1 = c1+(c2-c1)*k1;
|
||||
Vector2D m2 = c2+(c3-c2)*k2;
|
||||
Vector2D c1 = (p0 + p1) / 2.f;
|
||||
Vector2D c2 = (p1 + p2) / 2.f;
|
||||
Vector2D c3 = (p2 + p3) / 2.f;
|
||||
|
||||
float len1 = (p1 - p0).Len();
|
||||
float len2 = (p2 - p1).Len();
|
||||
float len3 = (p3 - p2).Len();
|
||||
|
||||
float k1 = len1 / (len1 + len2);
|
||||
float k2 = len2 / (len2 + len3);
|
||||
|
||||
Vector2D m1 = c1 + (c2 - c1) * k1;
|
||||
Vector2D m2 = c2 + (c3 - c2) * k2;
|
||||
|
||||
// Set curve points
|
||||
p4 = p2;
|
||||
p2 = m1+(c2-m1)*smooth + P1 - m1;
|
||||
p3 = m2+(c2-m2)*smooth + P2 - m2;
|
||||
type = CURVE_BICUBIC;
|
||||
p3 = m2 + (c2 - m2) * smooth + p2 - m2;
|
||||
p2 = m1 + (c2 - m1) * smooth + p1 - m1;
|
||||
type = BICUBIC;
|
||||
}
|
||||
|
||||
/// @brief Get a point
|
||||
/// @param t
|
||||
/// @return
|
||||
///
|
||||
Vector2D SplineCurve::GetPoint(float t) const {
|
||||
if (type == CURVE_POINT) return p1;
|
||||
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;
|
||||
}
|
||||
float u = 1.f - 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() {
|
||||
switch (type) {
|
||||
case CURVE_POINT: return p1;
|
||||
case CURVE_LINE: return p2;
|
||||
case CURVE_BICUBIC: return p4;
|
||||
default: return p1;
|
||||
case POINT: return p1;
|
||||
case LINE: return p2;
|
||||
case BICUBIC: return p4;
|
||||
default: return p1;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Get point closest to reference
|
||||
/// @param ref
|
||||
/// @return
|
||||
///
|
||||
Vector2D SplineCurve::GetClosestPoint(Vector2D const& ref) const {
|
||||
Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const {
|
||||
return GetPoint(GetClosestParam(ref));
|
||||
}
|
||||
|
||||
/// @brief Get value of parameter closest to point
|
||||
/// @param ref
|
||||
/// @return
|
||||
///
|
||||
float SplineCurve::GetClosestParam(Vector2D const& ref) const {
|
||||
if (type == CURVE_LINE) {
|
||||
return GetClosestSegmentPart(p1,p2,ref);
|
||||
}
|
||||
if (type == CURVE_BICUBIC) {
|
||||
float SplineCurve::GetClosestParam(Vector2D ref) const {
|
||||
if (type == LINE)
|
||||
return GetClosestSegmentPart(p1, p2, ref);
|
||||
|
||||
if (type == BICUBIC) {
|
||||
int steps = 100;
|
||||
float bestDist = 80000000.f;
|
||||
float bestDist = std::numeric_limits<float>::max();
|
||||
float bestT = 0.f;
|
||||
for (int i=0;i<=steps;i++) {
|
||||
float t = float(i)/float(steps);
|
||||
float dist = (GetPoint(t)-ref).Len();
|
||||
for (int i = 0; i <= steps; ++i) {
|
||||
float t = i / float(steps);
|
||||
float dist = (GetPoint(t) - ref).SquareLen();
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
bestT = t;
|
||||
|
@ -180,45 +138,30 @@ float SplineCurve::GetClosestParam(Vector2D const& ref) const {
|
|||
}
|
||||
return bestT;
|
||||
}
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
/// @brief Quick distance
|
||||
/// @param ref
|
||||
/// @return
|
||||
///
|
||||
float SplineCurve::GetQuickDistance(Vector2D const& ref) const {
|
||||
using std::min;
|
||||
if (type == CURVE_BICUBIC) {
|
||||
float len1 = GetClosestSegmentDistance(p1,p2,ref);
|
||||
float len2 = GetClosestSegmentDistance(p2,p3,ref);
|
||||
float len3 = GetClosestSegmentDistance(p3,p4,ref);
|
||||
float len4 = GetClosestSegmentDistance(p4,p1,ref);
|
||||
float len5 = GetClosestSegmentDistance(p1,p3,ref);
|
||||
float len6 = GetClosestSegmentDistance(p2,p4,ref);
|
||||
return min(min(min(len1,len2),min(len3,len4)),min(len5,len6));
|
||||
float SplineCurve::GetQuickDistance(Vector2D ref) const {
|
||||
if (type == BICUBIC) {
|
||||
float lens[] = {
|
||||
GetClosestSegmentDistance(p1, p2, ref),
|
||||
GetClosestSegmentDistance(p2, p3, ref),
|
||||
GetClosestSegmentDistance(p3, p4, ref),
|
||||
GetClosestSegmentDistance(p4, p1, ref),
|
||||
GetClosestSegmentDistance(p1, p3, ref),
|
||||
GetClosestSegmentDistance(p2, p4, ref)
|
||||
};
|
||||
return *std::min_element(lens, lens + 6);
|
||||
}
|
||||
|
||||
// Something else
|
||||
else return (GetClosestPoint(ref)-ref).Len();
|
||||
return (GetClosestPoint(ref) - ref).Len();
|
||||
}
|
||||
|
||||
/// @brief Closest t in segment p1-p2 to point p3
|
||||
/// @param pt1
|
||||
/// @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);
|
||||
float SplineCurve::GetClosestSegmentPart(Vector2D pt1, Vector2D pt2, Vector2D 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
|
||||
/// @param pt1
|
||||
/// @param pt2
|
||||
/// @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();
|
||||
float SplineCurve::GetClosestSegmentDistance(Vector2D pt1, Vector2D pt2, Vector2D pt3) const {
|
||||
float t = GetClosestSegmentPart(pt1, pt2, pt3);
|
||||
return (pt1 * (1.f - t) + pt2 * t - pt3).Len();
|
||||
}
|
||||
|
|
|
@ -34,57 +34,54 @@
|
|||
/// @ingroup visual_ts
|
||||
///
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "vector2d.h"
|
||||
|
||||
/// DOCME
|
||||
enum CurveType {
|
||||
|
||||
/// DOCME
|
||||
CURVE_INVALID,
|
||||
|
||||
/// DOCME
|
||||
CURVE_POINT,
|
||||
|
||||
/// DOCME
|
||||
CURVE_LINE,
|
||||
|
||||
/// DOCME
|
||||
CURVE_BICUBIC
|
||||
};
|
||||
|
||||
/// DOCME
|
||||
/// @class SplineCurve
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class SplineCurve {
|
||||
private:
|
||||
float GetClosestSegmentPart(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
|
||||
float GetClosestSegmentDistance(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
|
||||
/// Closest t in segment p1-p2 to point p3
|
||||
float GetClosestSegmentPart(Vector2D p1, Vector2D p2, Vector2D p3) const;
|
||||
|
||||
/// Closest distance between p3 and segment p1-p2
|
||||
float GetClosestSegmentDistance(Vector2D p1, Vector2D p2, Vector2D p3) const;
|
||||
public:
|
||||
enum CurveType {
|
||||
POINT,
|
||||
LINE,
|
||||
BICUBIC
|
||||
};
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
Vector2D p1,p2,p3,p4;
|
||||
Vector2D p1;
|
||||
Vector2D p2;
|
||||
Vector2D p3;
|
||||
Vector2D p4;
|
||||
|
||||
/// DOCME
|
||||
CurveType type;
|
||||
|
||||
SplineCurve();
|
||||
void Split(SplineCurve &c1,SplineCurve &c2,float t=0.5);
|
||||
void Smooth(Vector2D const& prev,Vector2D const& next,float smooth=1.0f);
|
||||
SplineCurve(Vector2D p1 = Vector2D());
|
||||
SplineCurve(Vector2D p1, Vector2D p2);
|
||||
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& EndPoint();
|
||||
Vector2D GetClosestPoint(Vector2D const& ref) const;
|
||||
float GetClosestParam(Vector2D const& ref) const;
|
||||
float GetQuickDistance(Vector2D const& ref) const;
|
||||
/// Get point on the curve closest to reference
|
||||
Vector2D GetClosestPoint(Vector2D 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 "validators.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
||||
enum {
|
||||
BUTTON_BOLD = 1300,
|
||||
|
|
|
@ -166,8 +166,8 @@ namespace {
|
|||
}
|
||||
|
||||
public:
|
||||
Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context)
|
||||
: wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_HORIZONTAL)
|
||||
Toolbar(wxWindow *parent, std::string const& name, agi::Context *c, std::string const& ht_context, bool vertical)
|
||||
: wxToolBar(parent, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | (vertical ? wxTB_VERTICAL : wxTB_HORIZONTAL))
|
||||
, name(name)
|
||||
, context(c)
|
||||
, ht_context(ht_context)
|
||||
|
@ -182,10 +182,10 @@ namespace {
|
|||
|
||||
namespace toolbar {
|
||||
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) {
|
||||
return new Toolbar(parent, name, c, 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, vertical);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -34,238 +21,77 @@
|
|||
/// @ingroup utility visual_ts
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "vector2d.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <limits>
|
||||
|
||||
/// @brief Null constructor
|
||||
///
|
||||
Vector2D::Vector2D () {
|
||||
x = y = 0;
|
||||
#include <wx/numformatter.h>
|
||||
#endif
|
||||
|
||||
Vector2D operator *(float f, Vector2D v) {
|
||||
return Vector2D(v.X() * f, v.Y() * f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @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(f / v.X(), f / v.Y());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @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(v.X() + f, v.Y() + f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Assignment
|
||||
/// @param param
|
||||
///
|
||||
void Vector2D::operator = (const Vector2D param) {
|
||||
x = param.x;
|
||||
y = param.y;
|
||||
Vector2D operator -(float f, Vector2D v) {
|
||||
return Vector2D(f - v.X(), f - v.Y());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Comparison
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
bool Vector2D::operator == (const Vector2D param) const {
|
||||
return ((x == param.x) && (y == param.y));
|
||||
Vector2D Vector2D::Unit() const {
|
||||
float len = Len();
|
||||
if (len == 0)
|
||||
return Vector2D(0, 0);
|
||||
return *this / len;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
bool Vector2D::operator != (const Vector2D param) const {
|
||||
return ((x != param.x) || (y == param.y));
|
||||
Vector2D Vector2D::SingleAxis() const {
|
||||
if (abs(x) < abs(y))
|
||||
return Vector2D(0, y);
|
||||
else
|
||||
return Vector2D(x, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Adition
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator + (const Vector2D param) const {
|
||||
return Vector2D(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 DOCME
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator += (const Vector2D param) {
|
||||
x += param.x;
|
||||
y += param.y;
|
||||
return *this;
|
||||
Vector2D Vector2D::Min(Vector2D param) const {
|
||||
return Vector2D(std::min(x, param.x), std::min(y, param.y));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Subtraction
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator - (const Vector2D param) const {
|
||||
return Vector2D(x - param.x,y - param.y);
|
||||
Vector2D Vector2D::Round(float step) const {
|
||||
return Vector2D(floorf(x / step + .5f) * step, floorf(y / step + .5f) * step);
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator -= (const Vector2D param) {
|
||||
x -= param.x;
|
||||
y -= param.y;
|
||||
return *this;
|
||||
Vector2D::operator unspecified_bool_type() const {
|
||||
return *this == Bad() ? 0 : &Vector2D::x;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Negate
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator - () const {
|
||||
return Vector2D(-x,-y);
|
||||
Vector2D Vector2D::Bad() {
|
||||
return Vector2D(std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Multiplication by scalar
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator * (float param) const {
|
||||
return Vector2D(x * param,y * param);
|
||||
wxString Vector2D::PStr(char sep) const {
|
||||
return "(" + Str(sep) + ")";
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param param
|
||||
/// @return
|
||||
///
|
||||
Vector2D Vector2D::operator *= (float param) {
|
||||
x *= param;
|
||||
y *= param;
|
||||
return *this;
|
||||
wxString Vector2D::DStr(char sep) const {
|
||||
return wxString::Format("%d%c%d", (int)x, sep, (int)y);
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param f
|
||||
/// @param v
|
||||
/// @return
|
||||
///
|
||||
Vector2D operator * (float f,const Vector2D &v) {
|
||||
return Vector2D(v.x * f,v.y * f);
|
||||
wxString Vector2D::Str(char sep) const {
|
||||
return
|
||||
wxNumberFormatter::ToString(x, 3, wxNumberFormatter::Style_NoTrailingZeroes) +
|
||||
sep +
|
||||
wxNumberFormatter::ToString(y, 3, wxNumberFormatter::Style_NoTrailingZeroes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -34,8 +21,13 @@
|
|||
/// @ingroup utility visual_ts
|
||||
///
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <cmath>
|
||||
|
||||
#include <wx/gdicmn.h>
|
||||
#endif
|
||||
|
||||
/// DOCME
|
||||
/// @class Vector2D
|
||||
|
@ -43,53 +35,62 @@
|
|||
///
|
||||
/// DOCME
|
||||
class Vector2D {
|
||||
float x, y;
|
||||
|
||||
typedef float Vector2D::*unspecified_bool_type;
|
||||
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
|
||||
float x,y;
|
||||
bool operator ==(const Vector2D r) const { return x == r.x && y == r.y; }
|
||||
bool operator !=(const Vector2D r) const { return x != r.x || y != r.y; }
|
||||
operator unspecified_bool_type() const;
|
||||
|
||||
Vector2D ();
|
||||
Vector2D (float _x,float _y);
|
||||
Vector2D (const Vector2D &vec);
|
||||
Vector2D operator -() const { return Vector2D(-x, -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 *(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);
|
||||
bool operator == (const Vector2D param) const;
|
||||
bool operator != (const Vector2D param) const;
|
||||
Vector2D Unit() const;
|
||||
Vector2D SingleAxis() const;
|
||||
|
||||
Vector2D operator - () const;
|
||||
Vector2D operator + (const Vector2D param) const;
|
||||
Vector2D operator - (const Vector2D param) const;
|
||||
Vector2D operator * (float param) const;
|
||||
Vector2D operator / (float param) const;
|
||||
Vector2D Perpendicular() const { return Vector2D(-y, x); }
|
||||
|
||||
Vector2D operator += (const Vector2D param);
|
||||
Vector2D operator -= (const Vector2D param);
|
||||
Vector2D operator *= (float param);
|
||||
Vector2D operator /= (float param);
|
||||
Vector2D Max(Vector2D param) const;
|
||||
Vector2D Min(Vector2D param) const;
|
||||
Vector2D Round(float step) const;
|
||||
|
||||
Vector2D Unit () const;
|
||||
float Cross (const Vector2D param) const;
|
||||
float Dot (const Vector2D param) const;
|
||||
float Cross(const Vector2D param) const { return x * param.y - y * param.x; }
|
||||
float Dot(const Vector2D param) const { return x * param.x + y * param.y; }
|
||||
|
||||
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
|
||||
/// @return
|
||||
///
|
||||
float Length () const { return Len(); }
|
||||
float SquareLen () const;
|
||||
/// Get as string with given separator
|
||||
wxString Str(char sep = ',') const;
|
||||
/// Get as string surrounded by parentheses with given separator
|
||||
wxString PStr(char sep = ',') const;
|
||||
/// Get as string with given separator with values rounded to ints
|
||||
wxString DStr(char sep = ',') const;
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
float SquareLength () const { return SquareLen(); }
|
||||
static Vector2D FromAngle(float angle) { return Vector2D(cos(-angle), sin(-angle)); }
|
||||
static Vector2D Bad();
|
||||
};
|
||||
|
||||
|
||||
////////////////////
|
||||
// Global operators
|
||||
Vector2D operator * (float f,const Vector2D &v);
|
||||
Vector2D operator / (float f,const Vector2D &v);
|
||||
|
||||
|
||||
Vector2D operator * (float f, Vector2D v);
|
||||
Vector2D operator / (float f, Vector2D v);
|
||||
Vector2D operator + (float f, Vector2D v);
|
||||
Vector2D operator - (float f, Vector2D v);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#endif
|
||||
|
||||
#include "include/aegisub/context.h"
|
||||
#include "include/aegisub/toolbar.h"
|
||||
|
||||
#include "ass_dialogue.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);
|
||||
|
||||
// Typesetting buttons
|
||||
visualToolBar = new wxToolBar(this,-1,wxDefaultPosition,wxDefaultSize,wxTB_VERTICAL|wxTB_FLAT|wxTB_NODIVIDER);
|
||||
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();
|
||||
visualToolBar = toolbar::GetToolbar(this, "visual_tools", context, "Video", true);
|
||||
// Avoid ugly themed background on Vista and possibly also Win7
|
||||
visualToolBar->SetBackgroundStyle(wxBG_STYLE_COLOUR);
|
||||
visualToolBar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
|
||||
|
||||
// Display
|
||||
videoDisplay = new VideoDisplay(this,isDetached,zoomBox,this,context);
|
||||
|
||||
// Top sizer
|
||||
|
|
|
@ -92,14 +92,3 @@ public:
|
|||
VideoBox(wxWindow *parent, bool isDetached, agi::Context *context);
|
||||
~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);
|
||||
|
||||
Seek(n);
|
||||
GetFrameAsync(frame_n);
|
||||
Seek(frame_n);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return provider->GetFrame(n, videoFPS.TimeAtFrame(n)/1000.0, raw);
|
||||
return provider->GetFrame(n, videoFPS.TimeAtFrame(n) / 1000.0, raw);
|
||||
}
|
||||
|
||||
int VideoContext::GetWidth() const {
|
||||
|
@ -326,10 +327,6 @@ void VideoContext::SaveSnapshot(bool raw) {
|
|||
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() {
|
||||
if (!videoProvider.get() || isPlaying || frame_n == videoProvider->GetFrameCount())
|
||||
return;
|
||||
|
|
|
@ -232,13 +232,6 @@ public:
|
|||
/// @param end Type of time
|
||||
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
|
||||
void Play();
|
||||
/// Play the next frame then stop
|
||||
|
|
|
@ -56,13 +56,13 @@
|
|||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include "include/aegisub/context.h"
|
||||
#include "include/aegisub/hotkey.h"
|
||||
#include "include/aegisub/menu.h"
|
||||
|
||||
#include "video_display.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 "threaded_frame_source.h"
|
||||
#include "utils.h"
|
||||
|
@ -70,13 +70,6 @@
|
|||
#include "video_box.h"
|
||||
#include "video_context.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
|
||||
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)
|
||||
, alwaysShowTools(OPT_GET("Tool/Visual/Always Show"))
|
||||
, con(c)
|
||||
, currentFrame(-1)
|
||||
, w(8), h(8), viewport_x(0), viewport_width(0), viewport_bottom(0), viewport_top(0), viewport_height(0)
|
||||
, w(8)
|
||||
, 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)
|
||||
, videoOut(new VideoOutGL())
|
||||
, activeMode(Video_Mode_Standard)
|
||||
, toolBar(box->visualSubToolBar)
|
||||
, scriptW(INT_MIN)
|
||||
, scriptH(INT_MIN)
|
||||
, zoomBox(zoomBox)
|
||||
, box(box)
|
||||
, freeSize(freeSize)
|
||||
|
@ -120,34 +116,29 @@ VideoDisplay::VideoDisplay(
|
|||
|
||||
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
||||
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);
|
||||
slots.push_back(con->videoController->AddSeekListener(&VideoDisplay::SetFrame, this));
|
||||
slots.push_back(con->videoController->AddVideoOpenListener(&VideoDisplay::OnVideoOpen, 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));
|
||||
if (freeSize) {
|
||||
Bind(wxEVT_SIZE, &VideoDisplay::OnSizeEvent, this);
|
||||
}
|
||||
Bind(wxEVT_CONTEXT_MENU, &VideoDisplay::OnContextMenu, this);
|
||||
Bind(wxEVT_ENTER_WINDOW, &VideoDisplay::OnMouseEvent, 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_DOWN, &VideoDisplay::OnMouseEvent, this);
|
||||
Bind(wxEVT_LEFT_UP, &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);
|
||||
|
||||
SetCursor(wxNullCursor);
|
||||
|
||||
if (con->videoController->IsLoaded()) {
|
||||
con->videoController->GetScriptSize(scriptW, scriptH);
|
||||
if (con->videoController->IsLoaded())
|
||||
OnVideoOpen();
|
||||
}
|
||||
}
|
||||
|
||||
VideoDisplay::~VideoDisplay () {
|
||||
|
@ -163,25 +154,6 @@ bool VideoDisplay::InitContext() {
|
|||
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) {
|
||||
if (!InitContext()) return;
|
||||
|
||||
|
@ -207,16 +179,10 @@ void VideoDisplay::UploadFrameData(FrameReadyEvent &evt) {
|
|||
|
||||
void VideoDisplay::OnVideoOpen() {
|
||||
if (!con->videoController->IsLoaded()) return;
|
||||
if (!tool.get())
|
||||
cmd::call("video/tool/cross", con);
|
||||
UpdateSize();
|
||||
if (!tool.get()) tool.reset(new VisualToolCross(this, con, video, toolBar));
|
||||
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();
|
||||
con->videoController->JumpToFrame(0);
|
||||
}
|
||||
|
||||
void VideoDisplay::Render() try {
|
||||
|
@ -225,7 +191,7 @@ void VideoDisplay::Render() try {
|
|||
assert(wxIsMainThread());
|
||||
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(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
|
||||
// 16:9 or wider
|
||||
if (ar > 1.75) {
|
||||
DrawOverscanMask(w * 0.1, h * 0.05, wxColor(30,70,200),0.5);
|
||||
DrawOverscanMask(w * 0.035, h * 0.035, wxColor(30,70,200),0.5);
|
||||
DrawOverscanMask(.1f, .05f);
|
||||
DrawOverscanMask(0.035f, 0.035f);
|
||||
}
|
||||
|
||||
// Less wide than 16:9 (use 4:3 standard)
|
||||
else {
|
||||
DrawOverscanMask(w * 0.067, h * 0.05, wxColor(30,70,200),0.5);
|
||||
DrawOverscanMask(w * 0.033, h * 0.035, wxColor(30,70,200),0.5);
|
||||
DrawOverscanMask(.067f, .05f);
|
||||
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())
|
||||
tool->Draw();
|
||||
}
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
catch (const VideoOutException &err) {
|
||||
catch (const agi::Exception &err) {
|
||||
wxLogError(
|
||||
"An error occurred trying to render the video frame on the screen.\n"
|
||||
"Error message reported: %s",
|
||||
err.GetMessage());
|
||||
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.");
|
||||
err.GetChainedMessage());
|
||||
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 gapH = sizeH+rad1;
|
||||
int gapV = sizeV+rad1;
|
||||
int rad2 = sqrt(double(gapH*gapH + gapV*gapV)) + 1;
|
||||
Vector2D gap = size + rad1;
|
||||
int rad2 = gap.Len() + 1;
|
||||
Vector2D v(w, h);
|
||||
Vector2D igap = v - gap;
|
||||
Vector2D isize = v - size;
|
||||
|
||||
OpenGLWrapper gl;
|
||||
E(gl.SetFillColour(color, alpha));
|
||||
gl.SetLineColour(wxColor(0, 0, 0), 0.0, 1);
|
||||
gl.SetFillColour(wxColor(30, 70, 200), .5f);
|
||||
gl.SetLineColour(*wxBLACK, 0, 1);
|
||||
|
||||
// Draw sides
|
||||
E(gl.DrawRectangle(gapH, 0, w-gapH, sizeV)); // Top
|
||||
E(gl.DrawRectangle(w-sizeH, gapV, w, h-gapV)); // Right
|
||||
E(gl.DrawRectangle(gapH, h-sizeV, w-gapH, h)); // Bottom
|
||||
E(gl.DrawRectangle(0, gapV, sizeH, h-gapV)); // Left
|
||||
gl.DrawRectangle(Vector2D(gap, 0), Vector2D(igap, size)); // Top
|
||||
gl.DrawRectangle(Vector2D(isize, gap), Vector2D(v, igap)); // Right
|
||||
gl.DrawRectangle(Vector2D(gap, isize), Vector2D(igap, v)); // Bottom
|
||||
gl.DrawRectangle(Vector2D(0, gap), Vector2D(size, igap)); // Left
|
||||
|
||||
// Draw rounded corners
|
||||
E(gl.DrawRing(gapH, gapV, rad1, rad2, 1.0, 180.0, 270.0)); // Top-left
|
||||
E(gl.DrawRing(w-gapH, gapV, rad1, rad2, 1.0, 90.0, 180.0)); // Top-right
|
||||
E(gl.DrawRing(w-gapH, h-gapV, rad1, rad2, 1.0, 0.0, 90.0)); // Bottom-right
|
||||
E(gl.DrawRing(gapH, h-gapV, rad1, rad2, 1.0,270.0,360.0)); // Bottom-left
|
||||
gl.DrawRing(gap, rad1, rad2, 1.f, 90.f, 180.f); // Top-left
|
||||
gl.DrawRing(Vector2D(igap, gap), rad1, rad2, 1.f, 0.f, 90.f); // Top-right
|
||||
gl.DrawRing(v - gap, rad1, rad2, 1.f, 270.f, 360.f); // Bottom-right
|
||||
gl.DrawRing(Vector2D(gap, igap), rad1, rad2, 1.f, 180.f, 270.f); // Bottom-left
|
||||
|
||||
E(glDisable(GL_BLEND));
|
||||
}
|
||||
|
@ -323,7 +271,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
|||
|
||||
if (freeSize) {
|
||||
GetClientSize(&w,&h);
|
||||
viewport_x = 0;
|
||||
viewport_left = 0;
|
||||
viewport_bottom = 0;
|
||||
viewport_top = 0;
|
||||
viewport_width = w;
|
||||
|
@ -336,7 +284,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
|||
// Window is wider than video, blackbox left/right
|
||||
if (displayAr - videoAr > 0.01f) {
|
||||
int delta = w - videoAr * h;
|
||||
viewport_x = delta / 2;
|
||||
viewport_left = delta / 2;
|
||||
viewport_width = w - delta;
|
||||
}
|
||||
|
||||
|
@ -359,7 +307,7 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
|||
// Cap the canvas size to the window size
|
||||
int cw = std::min(w, maxW), ch = std::min(h, maxH);
|
||||
|
||||
viewport_x = 0;
|
||||
viewport_left = 0;
|
||||
viewport_bottom = ch - h;
|
||||
viewport_top = 0;
|
||||
viewport_width = w;
|
||||
|
@ -380,11 +328,8 @@ void VideoDisplay::UpdateSize(int arType, double arValue) {
|
|||
SetEvtHandlerEnabled(true);
|
||||
}
|
||||
|
||||
con->videoController->GetScriptSize(scriptW, scriptH);
|
||||
video.w = w;
|
||||
video.h = h;
|
||||
|
||||
if (tool.get()) tool->Refresh();
|
||||
if (tool.get())
|
||||
tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
|
||||
|
||||
Refresh(false);
|
||||
}
|
||||
|
@ -403,20 +348,13 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
if (event.ButtonDown())
|
||||
SetFocus();
|
||||
|
||||
video.x = event.GetX();
|
||||
video.y = event.GetY();
|
||||
mouse_pos = event.GetPosition();
|
||||
|
||||
tool->OnMouseEvent(event);
|
||||
}
|
||||
|
||||
void VideoDisplay::OnMouseEnter(wxMouseEvent& event) {
|
||||
ShowCursor(activeMode != Video_Mode_Standard);
|
||||
tool->OnMouseEvent(event);
|
||||
}
|
||||
|
||||
void VideoDisplay::OnMouseLeave(wxMouseEvent& event) {
|
||||
video.x = INT_MIN;
|
||||
video.y = INT_MIN;
|
||||
mouse_pos = Vector2D::Bad();
|
||||
tool->OnMouseEvent(event);
|
||||
}
|
||||
|
||||
|
@ -429,33 +367,22 @@ void VideoDisplay::OnMouseWheel(wxMouseEvent& event) {
|
|||
|
||||
void VideoDisplay::OnContextMenu(wxContextMenuEvent&) {
|
||||
if (!context_menu.get()) context_menu.reset(menu::GetMenu("video_context", con));
|
||||
ShowCursor(true);
|
||||
SetCursor(wxNullCursor);
|
||||
menu::OpenPopupMenu(context_menu.get(), this);
|
||||
}
|
||||
|
||||
void VideoDisplay::OnKeyDown(wxKeyEvent &event) {
|
||||
/// @todo
|
||||
int kc = event.GetKeyCode();
|
||||
if (kc == 'A') SetMode(Video_Mode_Standard);
|
||||
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;
|
||||
}
|
||||
event.StopPropagation();
|
||||
if (hotkey::check("Video", con, event.GetKeyCode(), event.GetUnicodeKey(), event.GetModifiers()))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void VideoDisplay::SetZoom(double value) {
|
||||
zoomValue = std::max(value, .125);
|
||||
zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
|
||||
UpdateSize();
|
||||
}
|
||||
|
||||
void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
|
||||
wxString strValue = zoomBox->GetValue();
|
||||
strValue.EndsWith("%", &strValue);
|
||||
|
@ -466,57 +393,19 @@ void VideoDisplay::SetZoomFromBox(wxCommandEvent &) {
|
|||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
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;
|
||||
|
||||
void VideoDisplay::SetTool(VisualToolBase *new_tool) {
|
||||
toolBar->ClearTools();
|
||||
toolBar->Realize();
|
||||
toolBar->Show(false);
|
||||
|
||||
if (!box->visualToolBar->GetToolState(mode)) {
|
||||
box->visualToolBar->ToggleTool(mode, true);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
tool.reset(new_tool);
|
||||
tool->SetToolbar(toolBar);
|
||||
tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
|
||||
|
||||
// Update size as the new typesetting tool may have changed the subtoolbar size
|
||||
UpdateSize();
|
||||
ShowCursor(activeMode != Video_Mode_Standard);
|
||||
}
|
||||
|
||||
void VideoDisplay::ToScriptCoords(int *x, int *y) const {
|
||||
int sx = *x - viewport_x > 0 ? viewport_width : -viewport_width;
|
||||
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;
|
||||
Vector2D VideoDisplay::GetMousePosition() const {
|
||||
return mouse_pos ? tool->ToScriptCoords(mouse_pos) : mouse_pos;
|
||||
}
|
||||
|
|
|
@ -44,12 +44,14 @@
|
|||
#include <libaegisub/scoped_ptr.h>
|
||||
#include <libaegisub/signal.h>
|
||||
|
||||
#include "vector2d.h"
|
||||
|
||||
// Prototypes
|
||||
class FrameReadyEvent;
|
||||
class VideoBox;
|
||||
class VideoContext;
|
||||
class VideoOutGL;
|
||||
class IVisualTool;
|
||||
class VisualToolBase;
|
||||
class wxComboBox;
|
||||
class wxTextCtrl;
|
||||
class wxToolBar;
|
||||
|
@ -59,14 +61,6 @@ namespace agi {
|
|||
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
|
||||
/// @brief DOCME
|
||||
class VideoDisplay : public wxGLCanvas {
|
||||
|
@ -87,8 +81,10 @@ class VideoDisplay : public wxGLCanvas {
|
|||
/// The height of the canvas in screen pixels
|
||||
int h;
|
||||
|
||||
Vector2D mouse_pos;
|
||||
|
||||
/// 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
|
||||
int viewport_width;
|
||||
/// 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;
|
||||
|
||||
/// The active visual typesetting tool
|
||||
agi::scoped_ptr<IVisualTool> tool;
|
||||
/// The current tool's ID
|
||||
int activeMode;
|
||||
agi::scoped_ptr<VisualToolBase> tool;
|
||||
/// The toolbar used by individual typesetting tools
|
||||
wxToolBar* toolBar;
|
||||
|
||||
/// The OpenGL context for this display
|
||||
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
|
||||
wxComboBox *zoomBox;
|
||||
|
||||
|
@ -131,11 +118,9 @@ class VideoDisplay : public wxGLCanvas {
|
|||
bool freeSize;
|
||||
|
||||
/// @brief Draw an overscan mask
|
||||
/// @param sizeH The amount of horizontal overscan on one side
|
||||
/// @param sizeV The amount of vertical overscan on one side
|
||||
/// @param colour The color of the mask
|
||||
/// @param alpha The alpha of the mask
|
||||
void DrawOverscanMask(int sizeH, int sizeV, wxColor color, double alpha) const;
|
||||
/// @param horizontal_percent The percent of the video reserved horizontally
|
||||
/// @param vertical_percent The percent of the video reserved vertically
|
||||
void DrawOverscanMask(float horizontal_percent, float vertical_percent) const;
|
||||
|
||||
/// Upload the image for the current frame to the video card
|
||||
void UploadFrameData(FrameReadyEvent&);
|
||||
|
@ -144,21 +129,8 @@ class VideoDisplay : public wxGLCanvas {
|
|||
/// @return Could the context be set?
|
||||
bool InitContext();
|
||||
|
||||
/// @brief Set this video display to the given frame
|
||||
/// @frameNumber The desired frame number
|
||||
void SetFrame(int frameNumber);
|
||||
|
||||
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
|
||||
void UpdateSize(int arType = -1, double arValue = -1.);
|
||||
/// @brief Set the zoom level to that indicated by the dropdown
|
||||
|
@ -169,11 +141,9 @@ class VideoDisplay : public wxGLCanvas {
|
|||
/// @brief Mouse event handler
|
||||
void OnMouseEvent(wxMouseEvent& event);
|
||||
void OnMouseWheel(wxMouseEvent& event);
|
||||
void OnMouseEnter(wxMouseEvent& event);
|
||||
void OnMouseLeave(wxMouseEvent& event);
|
||||
/// @brief Recalculate video positioning and scaling when the available area or zoom changes
|
||||
void OnSizeEvent(wxSizeEvent &event);
|
||||
void OnMode(const wxCommandEvent &event);
|
||||
void OnContextMenu(wxContextMenuEvent&);
|
||||
|
||||
public:
|
||||
|
@ -195,17 +165,8 @@ public:
|
|||
/// @brief Get the current zoom level
|
||||
double GetZoom() const { return zoomValue; }
|
||||
|
||||
/// @brief Convert a point from screen to script coordinate frame
|
||||
/// @param x x coordinate; in/out
|
||||
/// @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 script coordinates
|
||||
Vector2D GetMousePosition() const;
|
||||
|
||||
/// Get the last seen position of the mouse in screen coordinates
|
||||
/// @param[out] x x coordinate
|
||||
/// @param[out] y y coordinate
|
||||
void GetMousePosition(int *x, int *y) const;
|
||||
void SetTool(VisualToolBase *new_tool);
|
||||
};
|
||||
|
|
|
@ -40,69 +40,89 @@
|
|||
#include "visual_feature.h"
|
||||
|
||||
VisualDraggableFeature::VisualDraggableFeature()
|
||||
: type(DRAG_NONE)
|
||||
, x(INT_MIN)
|
||||
, y(INT_MIN)
|
||||
, origX(INT_MIN)
|
||||
, origY(INT_MIN)
|
||||
: start(Vector2D::Bad())
|
||||
, type(DRAG_NONE)
|
||||
, pos(Vector2D::Bad())
|
||||
, 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) {
|
||||
case DRAG_BIG_SQUARE:
|
||||
return !(mx < x-8 || mx > x+8 || my < y-8 || my > y+8);
|
||||
case DRAG_BIG_CIRCLE: {
|
||||
int dx = mx-x;
|
||||
int dy = my-y;
|
||||
return dx*dx + dy*dy <= 64;
|
||||
}
|
||||
return fabs(delta.X()) < 8 && fabs(delta.Y()) < 8;
|
||||
|
||||
case DRAG_BIG_CIRCLE:
|
||||
return delta.SquareLen() < 64;
|
||||
|
||||
case DRAG_BIG_TRIANGLE: {
|
||||
int _my = my+2;
|
||||
if (_my < y-8 || _my > y+8) return false;
|
||||
int dx = mx-x;
|
||||
int dy = _my-y-8;
|
||||
return (16*dx+9*dy < 0 && 16*dx-9*dy > 0);
|
||||
if (delta.Y() < -10 || delta.Y() > 6) return false;
|
||||
float dy = delta.Y() - 6;
|
||||
return 16 * delta.X() + 9 * dy < 0 && 16 * delta.X() - 9 * dy > 0;
|
||||
}
|
||||
|
||||
case DRAG_SMALL_SQUARE:
|
||||
return !(mx < x-4 || mx > x+4 || my < y-4 || my > y+4);
|
||||
case DRAG_SMALL_CIRCLE: {
|
||||
int dx = mx-x;
|
||||
int dy = my-y;
|
||||
return dx*dx + dy*dy <= 16;
|
||||
}
|
||||
return fabs(delta.X()) < 4 && fabs(delta.Y()) < 4;
|
||||
|
||||
case DRAG_SMALL_CIRCLE:
|
||||
return delta.SquareLen() < 16;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDraggableFeature::Draw(OpenGLWrapper const& gl) const {
|
||||
if (!pos) return;
|
||||
|
||||
switch (type) {
|
||||
case DRAG_BIG_SQUARE:
|
||||
gl.DrawRectangle(x-8,y-8,x+8,y+8);
|
||||
gl.DrawLine(x,y-16,x,y+16);
|
||||
gl.DrawLine(x-16,y,x+16,y);
|
||||
gl.DrawRectangle(pos - 8, pos + 8);
|
||||
gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
|
||||
gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
|
||||
break;
|
||||
|
||||
case DRAG_BIG_CIRCLE:
|
||||
gl.DrawCircle(x,y,8);
|
||||
gl.DrawLine(x,y-16,x,y+16);
|
||||
gl.DrawLine(x-16,y,x+16,y);
|
||||
gl.DrawCircle(pos, 8);
|
||||
gl.DrawLine(pos - Vector2D(0, 16), pos + Vector2D(0, 16));
|
||||
gl.DrawLine(pos - Vector2D(16, 0), pos + Vector2D(16, 0));
|
||||
break;
|
||||
|
||||
case DRAG_BIG_TRIANGLE:
|
||||
gl.DrawTriangle(x-9,y-6,x+9,y-6,x,y+10);
|
||||
gl.DrawLine(x,y,x,y-16);
|
||||
gl.DrawLine(x,y,x-14,y+8);
|
||||
gl.DrawLine(x,y,x+14,y+8);
|
||||
gl.DrawTriangle(pos - Vector2D(9, 6), pos + Vector2D(9, -6), pos + Vector2D(0, 10));
|
||||
gl.DrawLine(pos, pos + Vector2D(0, -16));
|
||||
gl.DrawLine(pos, pos + Vector2D(-14, 8));
|
||||
gl.DrawLine(pos, pos + Vector2D(14, 8));
|
||||
break;
|
||||
|
||||
case DRAG_SMALL_SQUARE:
|
||||
gl.DrawRectangle(x-4,y-4,x+4,y+4);
|
||||
gl.DrawRectangle(pos - 4, pos + 4);
|
||||
break;
|
||||
|
||||
case DRAG_SMALL_CIRCLE:
|
||||
gl.DrawCircle(x,y,4);
|
||||
gl.DrawCircle(pos, 4);
|
||||
break;
|
||||
default:
|
||||
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
|
||||
|
||||
#include "vector2d.h"
|
||||
|
||||
class OpenGLWrapper;
|
||||
class AssDialogue;
|
||||
|
||||
|
@ -65,6 +67,8 @@ enum DraggableFeatureType {
|
|||
/// @class VisualDraggableFeature
|
||||
/// @brief Onscreen control used by many visual tools which doesn't do much
|
||||
class VisualDraggableFeature {
|
||||
Vector2D start; ///< position before the last operation began
|
||||
|
||||
public:
|
||||
/// @brief Constructor
|
||||
VisualDraggableFeature();
|
||||
|
@ -72,21 +76,23 @@ public:
|
|||
/// Shape of feature
|
||||
DraggableFeatureType type;
|
||||
|
||||
int x; /// x coordinate
|
||||
int y; /// y coordinate
|
||||
|
||||
int origX; /// x coordindate before the last operation began
|
||||
int origY; /// y coordindate before the last operation began
|
||||
Vector2D pos;
|
||||
|
||||
int layer; /// Layer; Higher = above
|
||||
|
||||
AssDialogue* line; /// The dialogue line this feature is for
|
||||
|
||||
/// @brief Is the given point over this feature?
|
||||
/// @param mx x coordinate to test
|
||||
/// @param my y coordinate to test
|
||||
bool IsMouseOver(int x,int y) const;
|
||||
/// @param mouse_pos Position of the mouse
|
||||
bool IsMouseOver(Vector2D mouse_pos) const;
|
||||
|
||||
/// @brief Draw this feature
|
||||
/// @param gl OpenGLWrapper to use
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -40,6 +27,8 @@
|
|||
#include <wx/glcanvas.h>
|
||||
#endif
|
||||
|
||||
#include "visual_tool.h"
|
||||
|
||||
#include "ass_dialogue.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_override.h"
|
||||
|
@ -47,133 +36,219 @@
|
|||
#include "ass_time.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "main.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "video_provider_manager.h"
|
||||
#include "visual_feature.h"
|
||||
#include "visual_tool.h"
|
||||
#include "visual_tool_clip.h"
|
||||
#include "visual_tool_drag.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>
|
||||
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, agi::Context *context, VideoState const& video)
|
||||
: dragStartX(0)
|
||||
, dragStartY(0)
|
||||
, commitId(-1)
|
||||
, selChanged(false)
|
||||
, selectedFeatures(selFeatures)
|
||||
, c(context)
|
||||
using std::tr1::placeholders::_1;
|
||||
|
||||
const wxColour VisualToolBase::colour[4] = {wxColour(106,32,19), wxColour(255,169,40), wxColour(255,253,185), wxColour(187,0,0)};
|
||||
|
||||
VisualToolBase::VisualToolBase(VideoDisplay *parent, agi::Context *context)
|
||||
: c(context)
|
||||
, parent(parent)
|
||||
, holding(false)
|
||||
, active_line(0)
|
||||
, dragging(false)
|
||||
, externalChange(true)
|
||||
, video(video)
|
||||
, leftClick(false)
|
||||
, leftDClick(false)
|
||||
, shiftDown(false)
|
||||
, ctrlDown(false)
|
||||
, altDown(false)
|
||||
, frame_number(c->videoController->GetFrameN())
|
||||
, left_click(false)
|
||||
, left_double(false)
|
||||
, shift_down(false)
|
||||
, ctrl_down(false)
|
||||
, alt_down(false)
|
||||
, file_changed_connection(c->ass->AddCommitListener(&VisualToolBase::OnCommit, this))
|
||||
, commit_id(-1)
|
||||
{
|
||||
frameNumber = c->videoController->GetFrameN();
|
||||
curDiag = GetActiveDialogueLine();
|
||||
int script_w, script_h;
|
||||
c->ass->GetResolution(script_w, script_h);
|
||||
script_res = Vector2D(script_w, script_h);
|
||||
active_line = GetActiveDialogueLine();
|
||||
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>
|
||||
VisualTool<FeatureType>::~VisualTool() {
|
||||
c->selectionController->RemoveSelectionListener(this);
|
||||
VisualTool<FeatureType>::VisualTool(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualToolBase(parent, context)
|
||||
, sel_changed(false)
|
||||
{
|
||||
active_feature = features.begin();
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
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()) {
|
||||
Update();
|
||||
mouse_pos = Vector2D::Bad();
|
||||
parent->Render();
|
||||
return;
|
||||
}
|
||||
else if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool()) {
|
||||
needRender = true;
|
||||
}
|
||||
externalChange = false;
|
||||
|
||||
leftClick = event.ButtonDown(wxMOUSE_BTN_LEFT);
|
||||
leftDClick = event.LeftDClick();
|
||||
shiftDown = event.m_shiftDown;
|
||||
#ifdef __APPLE__
|
||||
ctrlDown = event.m_metaDown; // Cmd key
|
||||
#else
|
||||
ctrlDown = event.m_controlDown;
|
||||
#endif
|
||||
altDown = event.m_altDown;
|
||||
if (event.Entering() && !OPT_GET("Tool/Visual/Always Show")->GetBool())
|
||||
need_render = true;
|
||||
|
||||
if (!dragging) {
|
||||
feature_iterator oldHigh = curFeature;
|
||||
GetHighlightedFeature();
|
||||
if (curFeature != oldHigh) needRender = true;
|
||||
feature_iterator prev_feature = active_feature;
|
||||
|
||||
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) {
|
||||
// continue drag
|
||||
if (event.LeftIsDown()) {
|
||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
||||
(*cur)->x = (video.x - dragStartX + (*cur)->origX);
|
||||
(*cur)->y = (video.y - dragStartY + (*cur)->origY);
|
||||
if (shiftDown) {
|
||||
if (abs(video.x - dragStartX) > abs(video.y - dragStartY)) {
|
||||
(*cur)->y = (*cur)->origY;
|
||||
}
|
||||
else {
|
||||
(*cur)->x = (*cur)->origX;
|
||||
}
|
||||
}
|
||||
UpdateDrag(*cur);
|
||||
CommitDrag(*cur);
|
||||
}
|
||||
for_each(sel_features, bind(&FeatureType::UpdateDrag, _1,
|
||||
mouse_pos - drag_start, shift_down));
|
||||
for_each(sel_features, bind(&VisualTool<FeatureType>::UpdateDrag, this, _1));
|
||||
Commit();
|
||||
needRender = true;
|
||||
need_render = true;
|
||||
}
|
||||
// end drag
|
||||
else {
|
||||
dragging = false;
|
||||
|
||||
// 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
|
||||
if (!selChanged) {
|
||||
if (ctrlDown) {
|
||||
// deselect this feature
|
||||
RemoveSelection(curFeature);
|
||||
}
|
||||
else {
|
||||
SetSelection(curFeature);
|
||||
}
|
||||
if (!sel_changed) {
|
||||
if (ctrl_down)
|
||||
RemoveSelection(active_feature);
|
||||
else
|
||||
SetSelection(active_feature, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
||||
CommitDrag(*cur);
|
||||
}
|
||||
Commit();
|
||||
}
|
||||
|
||||
curFeature = features.end();
|
||||
active_feature = features.end();
|
||||
parent->ReleaseMouse();
|
||||
parent->SetFocus();
|
||||
}
|
||||
}
|
||||
else if (holding) {
|
||||
// continue hold
|
||||
if (event.LeftIsDown()) {
|
||||
UpdateHold();
|
||||
needRender = true;
|
||||
need_render = true;
|
||||
}
|
||||
// end hold
|
||||
else {
|
||||
|
@ -182,422 +257,318 @@ void VisualTool<FeatureType>::OnMouseEvent(wxMouseEvent &event) {
|
|||
parent->ReleaseMouse();
|
||||
parent->SetFocus();
|
||||
}
|
||||
CommitHold();
|
||||
Commit();
|
||||
|
||||
}
|
||||
else if (leftClick) {
|
||||
else if (left_click) {
|
||||
drag_start = mouse_pos;
|
||||
|
||||
// start drag
|
||||
if (curFeature != features.end()) {
|
||||
if (selFeatures.find(curFeature) == selFeatures.end()) {
|
||||
selChanged = true;
|
||||
if (ctrlDown) {
|
||||
AddSelection(curFeature);
|
||||
}
|
||||
else {
|
||||
SetSelection(curFeature);
|
||||
}
|
||||
if (active_feature != features.end()) {
|
||||
if (!sel_features.count(active_feature)) {
|
||||
sel_changed = true;
|
||||
SetSelection(active_feature, !ctrl_down);
|
||||
}
|
||||
else {
|
||||
selChanged = false;
|
||||
}
|
||||
if (curFeature->line) c->selectionController->SetActiveLine(curFeature->line);
|
||||
else
|
||||
sel_changed = false;
|
||||
|
||||
if (InitializeDrag(curFeature)) {
|
||||
dragStartX = video.x;
|
||||
dragStartY = video.y;
|
||||
for (selection_iterator cur = selFeatures.begin(); cur != selFeatures.end(); ++cur) {
|
||||
(*cur)->origX = (*cur)->x;
|
||||
(*cur)->origY = (*cur)->y;
|
||||
}
|
||||
if (active_feature->line)
|
||||
c->selectionController->SetActiveLine(active_feature->line);
|
||||
|
||||
if (InitializeDrag(active_feature)) {
|
||||
for_each(sel_features, bind(&VisualDraggableFeature::StartDrag, _1));
|
||||
dragging = true;
|
||||
parent->CaptureMouse();
|
||||
}
|
||||
}
|
||||
// start hold
|
||||
else {
|
||||
if (!altDown) {
|
||||
ClearSelection();
|
||||
if (!alt_down) {
|
||||
sel_features.clear();
|
||||
Selection sel;
|
||||
sel.insert(c->selectionController->GetActiveLine());
|
||||
c->selectionController->SetSelectedSet(sel);
|
||||
needRender = true;
|
||||
need_render = true;
|
||||
}
|
||||
if (curDiag && InitializeHold()) {
|
||||
if (active_line && InitializeHold()) {
|
||||
holding = true;
|
||||
parent->CaptureMouse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Update() || needRender) parent->Render();
|
||||
externalChange = true;
|
||||
if (active_line && left_double)
|
||||
OnDoubleClick();
|
||||
|
||||
if (!event.LeftIsDown()) {
|
||||
// Only coalesce the changes made in a single drag
|
||||
commitId = -1;
|
||||
}
|
||||
}
|
||||
//if (need_render)
|
||||
parent->Render();
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::Commit(wxString message) {
|
||||
externalChange = false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Only coalesce the changes made in a single drag
|
||||
if (!event.LeftIsDown())
|
||||
commit_id = -1;
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
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) {
|
||||
int fill;
|
||||
if (cur == curFeature)
|
||||
int fill = 1;
|
||||
if (cur == active_feature)
|
||||
fill = 2;
|
||||
else if (selFeatures.find(cur) != selFeatures.end())
|
||||
else if (sel_features.count(cur))
|
||||
fill = 3;
|
||||
else
|
||||
fill = 1;
|
||||
SetFillColour(colour[fill],0.6f);
|
||||
cur->Draw(*this);
|
||||
gl.SetFillColour(colour[fill], 0.6f);
|
||||
cur->Draw(gl);
|
||||
}
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::Refresh() {
|
||||
if (externalChange) {
|
||||
curDiag = GetActiveDialogueLine();
|
||||
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;
|
||||
void VisualTool<FeatureType>::SetSelection(feature_iterator feat, bool clear) {
|
||||
if (clear)
|
||||
sel_features.clear();
|
||||
|
||||
if (sel_features.insert(feat).second && feat->line) {
|
||||
Selection sel;
|
||||
sel.insert(line);
|
||||
c->selectionController->SetSelectedSet(sel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if (!clear)
|
||||
sel = c->selectionController->GetSelectedSet();
|
||||
if (sel.insert(feat->line).second)
|
||||
c->selectionController->SetSelectedSet(sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::RemoveSelection(feature_iterator feat) {
|
||||
if (selFeatures.erase(feat) > 0 && feat->line) {
|
||||
// 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();
|
||||
if (!sel_features.erase(feat) || !feat->line) return;
|
||||
|
||||
// Don't deselect the only selected line
|
||||
if (sel.size() <= 1) 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);
|
||||
}
|
||||
for (selection_iterator it = sel_features.begin(); it != sel_features.end(); ++it) {
|
||||
if ((*it)->line == feat->line) return;
|
||||
}
|
||||
|
||||
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>
|
||||
void VisualTool<FeatureType>::ClearSelection() {
|
||||
selFeatures.clear();
|
||||
lineSelCount.clear();
|
||||
}
|
||||
//////// PARSERS
|
||||
|
||||
enum TagFoundType {
|
||||
TAG_NOT_FOUND = 0,
|
||||
PRIMARY_TAG_FOUND,
|
||||
ALT_TAG_FOUND
|
||||
typedef const std::vector<AssOverrideParameter*> * param_vec;
|
||||
|
||||
// Parse line on creation and unparse at the end of scope
|
||||
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
|
||||
/// @param line Line to get the value from
|
||||
/// @param tag Tag to get the value of
|
||||
/// @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++) {
|
||||
// Find a tag's parameters in a line or return NULL if it's not found
|
||||
static param_vec find_tag(const AssDialogue *line, wxString tag_name) {
|
||||
for (size_t i = 0; i < line->Blocks.size(); ++i) {
|
||||
const AssDialogueBlockOverride *ovr = dynamic_cast<const AssDialogueBlockOverride*>(line->Blocks[i]);
|
||||
if (!ovr) continue;
|
||||
|
||||
for (size_t j=0; j < ovr->Tags.size(); j++) {
|
||||
const AssOverrideTag *cur = ovr->Tags[j];
|
||||
if ((cur->Name == tag || cur->Name == alt) && cur->Params.size() >= n) {
|
||||
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;
|
||||
}
|
||||
for (size_t j = 0; j < ovr->Tags.size(); ++j) {
|
||||
if (ovr->Tags[j]->Name == tag_name)
|
||||
return &ovr->Tags[j]->Params;
|
||||
}
|
||||
}
|
||||
return TAG_NOT_FOUND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::GetLinePosition(AssDialogue *diag,int &x, int &y) {
|
||||
int orgx,orgy;
|
||||
GetLinePosition(diag,x,y,orgx,orgy);
|
||||
// Get a Vector2D from the given tag parameters, or Vector2D::Bad() if they are not valid
|
||||
static Vector2D vec_or_bad(param_vec tag, size_t x_idx, size_t y_idx) {
|
||||
if (!tag ||
|
||||
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>
|
||||
void VisualTool<FeatureType>::GetLinePosition(AssDialogue *diag,int &x, int &y, int &orgx, int &orgy) {
|
||||
Vector2D VisualToolBase::GetLinePosition(AssDialogue *diag) {
|
||||
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];
|
||||
for (int i=0;i<4;i++) margin[i] = diag->Margin[i];
|
||||
std::copy(diag->Margin, diag->Margin + 4, margin);
|
||||
int align = 2;
|
||||
|
||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
||||
if (style) {
|
||||
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
|
||||
align = style->alignment;
|
||||
for (int i=0;i<4;i++) {
|
||||
if (margin[i] == 0) margin[i] = style->Margin[i];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (margin[i] == 0)
|
||||
margin[i] = style->Margin[i];
|
||||
}
|
||||
}
|
||||
|
||||
int sw,sh;
|
||||
c->videoController->GetScriptSize(sw,sh);
|
||||
param_vec align_tag;
|
||||
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
|
||||
margin[1] = sw - margin[1];
|
||||
margin[3] = sh - margin[2];
|
||||
|
||||
// Overrides processing
|
||||
diag->ParseASSTags();
|
||||
|
||||
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];
|
||||
// \a -> \an values mapping
|
||||
static int align_mapping[] = { 2, 1, 2, 3, 7, 7, 8, 9, 7, 4, 5, 6 };
|
||||
if (static_cast<size_t>(align) < sizeof(align_mapping) / sizeof(int))
|
||||
align = align_mapping[align];
|
||||
else
|
||||
align = 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)) {
|
||||
orgx = x;
|
||||
orgy = y;
|
||||
}
|
||||
else {
|
||||
parent->FromScriptCoords(&orgx, &orgy);
|
||||
}
|
||||
// Calculate positions
|
||||
int x, y;
|
||||
if (hor == 0)
|
||||
x = margin[0];
|
||||
else if (hor == 1)
|
||||
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>
|
||||
void VisualTool<FeatureType>::GetLineMove(AssDialogue *diag,bool &hasMove,int &x1,int &y1,int &x2,int &y2,int &t1,int &t2) {
|
||||
diag->ParseASSTags();
|
||||
|
||||
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();
|
||||
Vector2D VisualToolBase::GetLineOrigin(AssDialogue *diag) {
|
||||
scoped_tag_parse parse(diag);
|
||||
return vec_or_bad(find_tag(diag, "\\org"), 0, 1);
|
||||
}
|
||||
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::GetLineRotation(AssDialogue *diag,float &rx,float &ry,float &rz) {
|
||||
bool VisualToolBase::GetLineMove(AssDialogue *diag, Vector2D &p1, Vector2D &p2, int &t1, int &t2) {
|
||||
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;
|
||||
|
||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
||||
if (style) {
|
||||
if (AssStyle *style = c->ass->GetStyle(diag->Style))
|
||||
rz = style->angle;
|
||||
}
|
||||
|
||||
diag->ParseASSTags();
|
||||
scoped_tag_parse parse(diag);
|
||||
|
||||
get_value<float>(diag, "\\frx", 1, &rx);
|
||||
get_value<float>(diag, "\\fry", 1, &ry);
|
||||
get_value<float>(diag, "\\frz", 1, &rz);
|
||||
|
||||
diag->ClearBlocks();
|
||||
if (param_vec tag = find_tag(diag, "\\frx"))
|
||||
rx = tag->front()->Get<float>(rx);
|
||||
if (param_vec tag = find_tag(diag, "\\fry"))
|
||||
ry = tag->front()->Get<float>(ry);
|
||||
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 VisualTool<FeatureType>::GetLineScale(AssDialogue *diag,float &scalX,float &scalY) {
|
||||
scalX = scalY = 100.f;
|
||||
void VisualToolBase::GetLineScale(AssDialogue *diag, Vector2D &scale) {
|
||||
float x = 100.f, y = 100.f;
|
||||
|
||||
AssStyle *style = c->ass->GetStyle(diag->Style);
|
||||
if (style) {
|
||||
scalX = style->scalex;
|
||||
scalY = style->scaley;
|
||||
if (AssStyle *style = c->ass->GetStyle(diag->Style)) {
|
||||
x = style->scalex;
|
||||
y = style->scaley;
|
||||
}
|
||||
|
||||
diag->ParseASSTags();
|
||||
scoped_tag_parse parse(diag);
|
||||
|
||||
get_value<float>(diag, "\\fscx", 1, &scalX);
|
||||
get_value<float>(diag, "\\fscy", 1, &scalY);
|
||||
if (param_vec tag = find_tag(diag, "\\fscx"))
|
||||
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 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;
|
||||
void VisualToolBase::GetLineClip(AssDialogue *diag, Vector2D &p1, Vector2D &p2, bool &inverse) {
|
||||
inverse = false;
|
||||
|
||||
diag->ParseASSTags();
|
||||
inverse = get_value<int>(diag, "\\clip", 4, &x1, &y1, &x2, &y2) == ALT_TAG_FOUND;
|
||||
diag->ClearBlocks();
|
||||
scoped_tag_parse parse(diag);
|
||||
param_vec tag = find_tag(diag, "\\iclip");
|
||||
if (tag)
|
||||
inverse = true;
|
||||
else
|
||||
tag = find_tag(diag, "\\clip");
|
||||
|
||||
parent->FromScriptCoords(&x1, &y1);
|
||||
parent->FromScriptCoords(&x2, &y2);
|
||||
if (tag && tag->size() == 4) {
|
||||
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 VisualTool<FeatureType>::GetLineVectorClip(AssDialogue *diag,int &scale,bool &inverse) {
|
||||
wxString VisualToolBase::GetLineVectorClip(AssDialogue *diag, int &scale, bool &inverse) {
|
||||
scoped_tag_parse parse(diag);
|
||||
|
||||
scale = 1;
|
||||
inverse = false;
|
||||
diag->ParseASSTags();
|
||||
|
||||
int x1, y1, x2, y2;
|
||||
TagFoundType res = get_value<int>(diag, "\\clip", 4, &x1, &y1, &x2, &y2);
|
||||
if (res) {
|
||||
inverse = res == ALT_TAG_FOUND;
|
||||
diag->ClearBlocks();
|
||||
return wxString::Format("m %d %d l %d %d %d %d %d %d", x1, y1, x2, y1, x2, y2, x1, y2);
|
||||
param_vec tag = find_tag(diag, "\\iclip");
|
||||
if (tag)
|
||||
inverse = true;
|
||||
else
|
||||
tag = find_tag(diag, "\\clip");
|
||||
|
||||
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;
|
||||
wxString scaleStr;
|
||||
res = get_value<wxString>(diag, "\\clip", 2, &scaleStr, &result);
|
||||
inverse = res == ALT_TAG_FOUND;
|
||||
if (!scaleStr.empty()) {
|
||||
long s;
|
||||
scaleStr.ToLong(&s);
|
||||
scale = s;
|
||||
if (tag) {
|
||||
scale = (*tag)[0]->Get<int>(scale);
|
||||
return (*tag)[1]->Get<wxString>("");
|
||||
}
|
||||
diag->ClearBlocks();
|
||||
return result;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/// @brief Set override
|
||||
/// @param tag
|
||||
/// @param value
|
||||
template<class FeatureType>
|
||||
void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxString value) {
|
||||
void VisualToolBase::SetSelectedOverride(wxString const& tag, wxString const& value) {
|
||||
for_each(c->selectionController->GetSelectedSet(),
|
||||
bind(&VisualToolBase::SetOverride, this, _1, tag, value));
|
||||
}
|
||||
|
||||
void VisualToolBase::SetOverride(AssDialogue* line, wxString const& tag, wxString const& value) {
|
||||
if (!line) return;
|
||||
|
||||
wxString removeTag;
|
||||
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 == "\\move") removeTag = "\\pos";
|
||||
else if (tag == "\\clip") removeTag = "\\iclip";
|
||||
|
@ -607,17 +578,14 @@ void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxStr
|
|||
|
||||
// Get block at start
|
||||
line->ParseASSTags();
|
||||
AssDialogueBlock *block = line->Blocks.at(0);
|
||||
AssDialogueBlock *block = line->Blocks.front();
|
||||
|
||||
// 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);
|
||||
|
||||
if (plain) {
|
||||
if (dynamic_cast<AssDialogueBlockPlain*>(block))
|
||||
line->Text = "{" + insert + "}" + line->Text;
|
||||
}
|
||||
else if (ovr) {
|
||||
else if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride*>(block)) {
|
||||
// Remove old of same
|
||||
for (size_t i = 0; i < ovr->Tags.size(); i++) {
|
||||
wxString name = ovr->Tags[i]->Name;
|
||||
|
@ -631,8 +599,6 @@ void VisualTool<FeatureType>::SetOverride(AssDialogue* line, wxString tag, wxStr
|
|||
|
||||
line->UpdateText();
|
||||
}
|
||||
|
||||
parent->SetFocus();
|
||||
}
|
||||
|
||||
// If only export worked
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -36,6 +23,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
@ -45,83 +33,158 @@
|
|||
#include <wx/button.h>
|
||||
#endif
|
||||
|
||||
#include "base_grid.h"
|
||||
#include <libaegisub/signal.h>
|
||||
|
||||
#include "gl_wrap.h"
|
||||
#include "selection_controller.h"
|
||||
#include "vector2d.h"
|
||||
|
||||
class AssDialogue;
|
||||
class SubtitlesGrid;
|
||||
class VideoDisplay;
|
||||
struct VideoState;
|
||||
class wxToolBar;
|
||||
namespace agi {
|
||||
struct Context;
|
||||
class OptionValue;
|
||||
}
|
||||
|
||||
/// First window id for visualsubtoolbar items
|
||||
#define VISUAL_SUB_TOOL_START 1300
|
||||
/// @class VisualToolBase
|
||||
/// @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
|
||||
#define VISUAL_SUB_TOOL_END (VISUAL_SUB_TOOL_START+100)
|
||||
void OnCommit(int type);
|
||||
void OnSeek(int new_frame);
|
||||
|
||||
class IVisualTool : public OpenGLWrapper {
|
||||
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();
|
||||
void OnMouseCaptureLost(wxMouseCaptureLostEvent &);
|
||||
|
||||
/// @brief Get the dialogue line currently in the edit box
|
||||
/// @return NULL if the line is not active on the current frame
|
||||
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;
|
||||
|
||||
std::set<feature_iterator, ltaddr> selFeatures; /// Currently selected visual features
|
||||
std::map<AssDialogue*, int> lineSelCount; /// Number of selected features for each line
|
||||
|
||||
bool selChanged; /// Has the selection already been changed in the current click?
|
||||
bool sel_changed; /// Has the selection already been changed in the current click?
|
||||
|
||||
/// @brief Called when a hold is begun
|
||||
/// @return Should the hold actually happen?
|
||||
virtual bool InitializeHold() { return false; }
|
||||
/// @brief Called on every mouse event during a hold
|
||||
virtual void UpdateHold() { }
|
||||
/// @brief Called at the end of a hold
|
||||
virtual void CommitHold() { }
|
||||
|
||||
/// @brief Called at the beginning of a drag
|
||||
/// @param feature The visual feature clicked on
|
||||
|
@ -130,67 +193,22 @@ private:
|
|||
/// @brief Called on every mouse event during a drag
|
||||
/// @param feature The current feature to process; not necessarily the one clicked on
|
||||
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
|
||||
virtual void Draw()=0;
|
||||
|
||||
protected:
|
||||
/// Read-only reference to the set of selected features for subclasses
|
||||
const std::set<feature_iterator, ltaddr> &selectedFeatures;
|
||||
std::set<feature_iterator, ltaddr> sel_features; ///< Currently selected visual features
|
||||
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
|
||||
std::list<FeatureType> features; /// List of features which are drawn and can be clicked on
|
||||
|
||||
int frameNumber; /// Current frame number
|
||||
VideoState const& video; /// Mouse and video information
|
||||
|
||||
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);
|
||||
/// Topmost feature under the mouse; generally only valid during a drag
|
||||
feature_iterator active_feature;
|
||||
/// List of features which are drawn and can be clicked on
|
||||
/// List is used here for the iterator invalidation properties
|
||||
std::list<FeatureType> features;
|
||||
|
||||
/// Draw all of the features in the list
|
||||
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
|
||||
/// @param i Index in the feature list
|
||||
|
@ -199,35 +217,15 @@ protected:
|
|||
|
||||
/// @brief Set the selection to a single feature, deselecting everything else
|
||||
/// @param i Index in the feature list
|
||||
void SetSelection(feature_iterator feat);
|
||||
|
||||
/// @brief Clear the selection
|
||||
void ClearSelection();
|
||||
|
||||
// SubtitleSelectionListener implementation
|
||||
void OnActiveLineChanged(AssDialogue *new_line);
|
||||
virtual void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) { }
|
||||
void SetSelection(feature_iterator feat, bool clear);
|
||||
|
||||
public:
|
||||
/// @brief Handler for all mouse events
|
||||
/// @param event Shockingly enough, the mouse 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
|
||||
/// @param parent The VideoDisplay to use for coordinate conversion
|
||||
/// @param video Video and mouse information passing blob
|
||||
VisualTool(VideoDisplay *parent, agi::Context *context, VideoState const& video);
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~VisualTool();
|
||||
VisualTool(VideoDisplay *parent, agi::Context *context);
|
||||
};
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -39,35 +26,30 @@
|
|||
#include <utility>
|
||||
#endif
|
||||
|
||||
#include "ass_dialogue.h"
|
||||
#include "ass_file.h"
|
||||
#include "utils.h"
|
||||
#include "video_display.h"
|
||||
#include "visual_tool_clip.h"
|
||||
|
||||
VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
||||
: VisualTool<ClipCorner>(parent, context, video)
|
||||
, curX1(0)
|
||||
, curY1(0)
|
||||
, curX2(video.w)
|
||||
, curY2(video.h)
|
||||
#include "utils.h"
|
||||
|
||||
VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<ClipCorner>(parent, context)
|
||||
, cur_1(0, 0)
|
||||
, cur_2(video_res)
|
||||
, inverse(false)
|
||||
{
|
||||
if (curDiag) {
|
||||
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
|
||||
}
|
||||
|
||||
Feature feat;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
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();
|
||||
feats[0] = &*(cur++);
|
||||
feats[1] = &*(cur++);
|
||||
feats[2] = &*(cur++);
|
||||
feats[3] = &*(cur++);
|
||||
|
||||
|
||||
// Attach each feature to the two features it shares edges with
|
||||
// Top-left
|
||||
int i = 0;
|
||||
feats[i]->horiz = feats[1];
|
||||
|
@ -87,129 +69,81 @@ VisualToolClip::VisualToolClip(VideoDisplay *parent, agi::Context *context, Vide
|
|||
// Bottom-right
|
||||
feats[i]->horiz = feats[2];
|
||||
feats[i]->vert = feats[1];
|
||||
i++;
|
||||
}
|
||||
|
||||
void VisualToolClip::Draw() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
|
||||
int dx1 = curX1;
|
||||
int dy1 = curY1;
|
||||
int dx2 = curX2;
|
||||
int dy2 = curY2;
|
||||
DrawAllFeatures();
|
||||
|
||||
// Draw rectangle
|
||||
SetLineColour(colour[3],1.0f,2);
|
||||
SetFillColour(colour[3],0.0f);
|
||||
DrawRectangle(dx1,dy1,dx2,dy2);
|
||||
gl.SetLineColour(colour[3], 1.0f, 2);
|
||||
gl.SetFillColour(colour[3], 0.0f);
|
||||
gl.DrawRectangle(cur_1, cur_2);
|
||||
|
||||
// Draw outside area
|
||||
SetLineColour(colour[3],0.0f);
|
||||
SetFillColour(wxColour(0,0,0),0.5f);
|
||||
gl.SetLineColour(colour[3], 0.0f);
|
||||
gl.SetFillColour(*wxBLACK, 0.5f);
|
||||
if (inverse) {
|
||||
DrawRectangle(dx1,dy1,dx2,dy2);
|
||||
gl.DrawRectangle(cur_1, cur_2);
|
||||
}
|
||||
else {
|
||||
DrawRectangle(0,0,video.w,dy1);
|
||||
DrawRectangle(0,dy2,video.w,video.h);
|
||||
DrawRectangle(0,dy1,dx1,dy2);
|
||||
DrawRectangle(dx2,dy1,video.w,dy2);
|
||||
Vector2D p1 = cur_1.Min(cur_2);
|
||||
Vector2D p2 = cur_1.Max(cur_2);
|
||||
gl.DrawRectangle(Vector2D(0, 0), Vector2D(video_res, p1));
|
||||
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() {
|
||||
startX = video.x;
|
||||
startY = video.y;
|
||||
curDiag->StripTag("\\clip");
|
||||
curDiag->StripTag("\\iclip");
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
curX1 = mid(0,curX1,video.w);
|
||||
curX2 = mid(0,curX2,video.w);
|
||||
curY1 = mid(0,curY1,video.h);
|
||||
curY2 = mid(0,curY2,video.h);
|
||||
Vector2D zero(0, 0);
|
||||
cur_1 = zero.Max(video_res.Min(drag_start));
|
||||
cur_2 = zero.Max(video_res.Min(mouse_pos));
|
||||
|
||||
SetFeaturePositions();
|
||||
CommitHold();
|
||||
}
|
||||
|
||||
void VisualToolClip::CommitHold() {
|
||||
int x1 = curX1;
|
||||
int x2 = curX2;
|
||||
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));
|
||||
SetOverride(active_line, inverse ? "\\iclip" : "\\clip",
|
||||
wxString::Format("(%s,%s)", ToScriptCoords(cur_1.Min(cur_2)).Str(), ToScriptCoords(cur_1.Max(cur_2)).Str()));
|
||||
}
|
||||
|
||||
bool VisualToolClip::InitializeDrag(feature_iterator) {
|
||||
curDiag->StripTag("\\clip");
|
||||
curDiag->StripTag("\\iclip");
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolClip::UpdateDrag(feature_iterator feature) {
|
||||
// Update brothers
|
||||
feature->horiz->y = feature->y;
|
||||
feature->vert->x = feature->x;
|
||||
// Update features which share an edge with the dragged one
|
||||
feature->horiz->pos = Vector2D(feature->horiz->pos, feature->pos);
|
||||
feature->vert->pos = Vector2D(feature->pos, feature->vert->pos);
|
||||
|
||||
// Get "cur" from features
|
||||
curX1 = feats[0]->x;
|
||||
curX2 = feats[3]->x;
|
||||
curY1 = feats[0]->y;
|
||||
curY2 = feats[3]->y;
|
||||
cur_1 = features.front().pos;
|
||||
cur_2 = features.back().pos;
|
||||
|
||||
// Make sure p1 < p2
|
||||
if (curX1 > curX2) std::swap(curX1,curX2);
|
||||
if (curY1 > curY2) std::swap(curY1,curY2);
|
||||
}
|
||||
|
||||
void VisualToolClip::CommitDrag(feature_iterator) {
|
||||
CommitHold();
|
||||
}
|
||||
|
||||
void VisualToolClip::SetFeaturePositions() {
|
||||
// Top-left
|
||||
int i = 0;
|
||||
feats[i]->x = curX1;
|
||||
feats[i]->y = curY1;
|
||||
i++;
|
||||
|
||||
// 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;
|
||||
feature_iterator it = features.begin();
|
||||
(it++)->pos = cur_1; // Top-left
|
||||
(it++)->pos = Vector2D(cur_2, cur_1); // Top-right
|
||||
(it++)->pos = Vector2D(cur_1, cur_2); // Bottom-left
|
||||
it->pos = cur_2; // Bottom-right
|
||||
}
|
||||
|
||||
void VisualToolClip::DoRefresh() {
|
||||
if (curDiag) {
|
||||
GetLineClip(curDiag,curX1,curY1,curX2,curY2,inverse);
|
||||
if (active_line) {
|
||||
GetLineClip(active_line, cur_1, cur_2, inverse);
|
||||
cur_1 = FromScriptCoords(cur_1);
|
||||
cur_2 = FromScriptCoords(cur_2);
|
||||
SetFeaturePositions();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -39,16 +26,10 @@
|
|||
|
||||
/// @class ClipCorner
|
||||
/// @brief VisualDraggableFeature with siblings
|
||||
class ClipCorner : public VisualDraggableFeature {
|
||||
public:
|
||||
ClipCorner* horiz; /// Other corner on this corner's horizontal line
|
||||
ClipCorner* vert; /// Other corner on this corner's vertical line
|
||||
/// @brief Constructor
|
||||
ClipCorner()
|
||||
: VisualDraggableFeature()
|
||||
, horiz(NULL)
|
||||
, vert(NULL)
|
||||
{ }
|
||||
struct ClipCorner : public VisualDraggableFeature {
|
||||
ClipCorner *horiz; /// Other corner on this corner's horizontal line
|
||||
ClipCorner *vert; /// Other corner on this corner's vertical line
|
||||
ClipCorner() : VisualDraggableFeature() , horiz(0) , vert(0) { }
|
||||
};
|
||||
|
||||
/// DOCME
|
||||
|
@ -57,11 +38,10 @@ public:
|
|||
///
|
||||
/// DOCME
|
||||
class VisualToolClip : public VisualTool<ClipCorner> {
|
||||
int startX,startY,curX1,curY1,curX2,curY2;
|
||||
Vector2D cur_1;
|
||||
Vector2D cur_2;
|
||||
|
||||
ClipCorner *feats[4];
|
||||
|
||||
bool inverse;
|
||||
bool inverse; ///< Is this currently in iclip mode?
|
||||
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
|
@ -72,9 +52,8 @@ class VisualToolClip : public VisualTool<ClipCorner> {
|
|||
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
void CommitDrag(feature_iterator feature);
|
||||
|
||||
void Draw();
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -35,88 +22,81 @@
|
|||
|
||||
#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"
|
||||
|
||||
VisualToolCross::VisualToolCross(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
||||
, glText(new OpenGLText)
|
||||
#include "gl_text.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#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() {
|
||||
if (!leftDClick) return true;
|
||||
if (!curDiag) return true;
|
||||
VisualToolCross::~VisualToolCross() {
|
||||
parent->SetCursor(wxNullCursor);
|
||||
}
|
||||
|
||||
int dx, dy;
|
||||
int vx = video.x;
|
||||
int vy = video.y;
|
||||
GetLinePosition(curDiag, dx, dy);
|
||||
parent->ToScriptCoords(&vx, &vy);
|
||||
parent->ToScriptCoords(&dx, &dy);
|
||||
dx -= vx;
|
||||
dy -= vy;
|
||||
void VisualToolCross::OnDoubleClick() {
|
||||
Vector2D d = ToScriptCoords(mouse_pos) - GetLinePosition(active_line);
|
||||
|
||||
Selection sel = c->selectionController->GetSelectedSet();
|
||||
for (Selection::const_iterator cur = sel.begin(); cur != sel.end(); ++cur) {
|
||||
int x1, y1;
|
||||
GetLinePosition(*cur, x1, y1);
|
||||
parent->ToScriptCoords(&x1, &y1);
|
||||
SetOverride(*cur, "\\pos", wxString::Format("(%i,%i)", x1 - dx, y1 - dy));
|
||||
for (Selection::const_iterator it = sel.begin(); it != sel.end(); ++it) {
|
||||
Vector2D p1, p2;
|
||||
int t1, t2;
|
||||
if (GetLineMove(*it, p1, p2, t1, t2)) {
|
||||
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"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void VisualToolCross::Draw() {
|
||||
if (!mouse_pos) return;
|
||||
|
||||
// Draw cross
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_COLOR_LOGIC_OP);
|
||||
glLogicOp(GL_INVERT);
|
||||
glLineWidth(1);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1.0f,1.0f,1.0f);
|
||||
glVertex2f(0, video.y);
|
||||
glVertex2f(video.w, video.y);
|
||||
glVertex2f(video.x, 0);
|
||||
glVertex2f(video.x, video.h);
|
||||
glEnd();
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
gl.SetInvert();
|
||||
gl.SetLineColour(*wxWHITE, 1.0, 1);
|
||||
float lines[] = {
|
||||
0.f, mouse_pos.Y(),
|
||||
video_res.X(), mouse_pos.Y(),
|
||||
mouse_pos.X(), 0.f,
|
||||
mouse_pos.X(), video_res.Y()
|
||||
};
|
||||
gl.DrawLines(2, lines, 4);
|
||||
gl.ClearInvert();
|
||||
|
||||
int tx,ty;
|
||||
if (!wxGetMouseState().ShiftDown()) {
|
||||
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);
|
||||
Vector2D t = ToScriptCoords(shift_down ? video_res - mouse_pos : mouse_pos);
|
||||
wxString mouse_text = t.Str();
|
||||
|
||||
int tw,th;
|
||||
glText->SetFont("Verdana", 12, true, false);
|
||||
glText->SetColour(wxColour(255, 255, 255), 1.f);
|
||||
glText->GetExtent(mouseText, tw, th);
|
||||
int tw, th;
|
||||
gl_text->SetFont("Verdana", 12, true, false);
|
||||
gl_text->SetColour(*wxWHITE, 1.f);
|
||||
gl_text->GetExtent(mouse_text, tw, th);
|
||||
|
||||
// Calculate draw position
|
||||
int dx = video.x;
|
||||
int dy = video.y;
|
||||
bool left = dx > video.w / 2;
|
||||
bool bottom = dy < video.h / 2;
|
||||
// Place the text in the corner of the cross closest to the center of the video
|
||||
int dx = mouse_pos.X();
|
||||
int dy = mouse_pos.Y();
|
||||
if (dx > video_res.X() / 2)
|
||||
dx -= tw + 4;
|
||||
else
|
||||
dx += 4;
|
||||
|
||||
// Text draw coords
|
||||
if (left) dx -= tw + 4;
|
||||
else dx += 4;
|
||||
if (bottom) dy += 3;
|
||||
else dy -= th + 3;
|
||||
if (dy < video_res.Y() / 2)
|
||||
dy += 3;
|
||||
else
|
||||
dy -= th + 3;
|
||||
|
||||
// Draw text
|
||||
glText->Print(mouseText, dx, dy);
|
||||
gl_text->Print(mouse_text, dx, dy);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -34,24 +21,21 @@
|
|||
/// @ingroup visual_ts
|
||||
///
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <tr1/memory>
|
||||
#endif
|
||||
#include <libaegisub/scoped_ptr.h>
|
||||
|
||||
#include "visual_feature.h"
|
||||
#include "visual_tool.h"
|
||||
|
||||
class OpenGLText;
|
||||
|
||||
/// DOCME
|
||||
/// @class VisualToolCross
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
/// @brief A crosshair which shows the current mouse position and on double-click
|
||||
/// shifts the selected lines to the clicked point
|
||||
class VisualToolCross : public VisualTool<VisualDraggableFeature> {
|
||||
bool Update();
|
||||
void OnDoubleClick();
|
||||
void Draw();
|
||||
std::tr1::shared_ptr<OpenGLText> glText;
|
||||
agi::scoped_ptr<OpenGLText> gl_text;
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -35,83 +22,79 @@
|
|||
|
||||
#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_file.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.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_START = DRAG_BIG_SQUARE;
|
||||
static const DraggableFeatureType DRAG_END = DRAG_BIG_CIRCLE;
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param _parent
|
||||
/// @param toolBar
|
||||
VisualToolDrag::VisualToolDrag(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar * toolBar)
|
||||
: VisualTool<VisualToolDragDraggableFeature>(parent, context, video)
|
||||
, toolBar(toolBar)
|
||||
, primary(NULL)
|
||||
, toggleMoveOnMove(true)
|
||||
VisualToolDrag::VisualToolDrag(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualToolDragDraggableFeature>(parent, context)
|
||||
, primary(0)
|
||||
, button_is_move(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);
|
||||
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() {
|
||||
// Check which bitmap to use
|
||||
bool toMove = true;
|
||||
if (curDiag) {
|
||||
int x1,y1,x2,y2,t1,t2;
|
||||
bool hasMove;
|
||||
GetLineMove(curDiag,hasMove,x1,y1,x2,y2,t1,t2);
|
||||
toMove = !hasMove;
|
||||
bool to_move = true;
|
||||
if (active_line) {
|
||||
Vector2D p1, p2;
|
||||
int t1, t2;
|
||||
to_move = !GetLineMove(active_line, p1, p2, t1, t2);
|
||||
}
|
||||
|
||||
// No change needed
|
||||
if (toMove == toggleMoveOnMove) return;
|
||||
if (to_move == button_is_move) return;
|
||||
|
||||
// Change bitmap
|
||||
if (toMove) {
|
||||
toolBar->SetToolNormalBitmap(BUTTON_TOGGLE_MOVE, GETIMAGE(visual_move_conv_move_24));
|
||||
}
|
||||
else {
|
||||
toolBar->SetToolNormalBitmap(BUTTON_TOGGLE_MOVE, GETIMAGE(visual_move_conv_pos_24));
|
||||
}
|
||||
toggleMoveOnMove = toMove;
|
||||
toolbar->SetToolNormalBitmap(toolbar->GetToolByPos(0)->GetId(),
|
||||
to_move ? GETIMAGE(visual_move_conv_move_24) : GETIMAGE(visual_move_conv_pos_24));
|
||||
button_is_move = to_move;
|
||||
}
|
||||
|
||||
/// @brief Toggle button pressed
|
||||
/// @param event
|
||||
void VisualToolDrag::OnSubTool(wxCommandEvent &) {
|
||||
// Toggle \move <-> \pos
|
||||
VideoContext *vc = c->videoController;
|
||||
for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
|
||||
AssDialogue *line = *cur;
|
||||
int x1,y1,x2,y2,t1,t2;
|
||||
bool hasMove;
|
||||
Vector2D p1, p2;
|
||||
int t1, t2;
|
||||
|
||||
GetLinePosition(line,x1,y1);
|
||||
GetLineMove(line,hasMove,x1,y1,x2,y2,t1,t2);
|
||||
parent->ToScriptCoords(&x1, &y1);
|
||||
parent->ToScriptCoords(&x2, &y2);
|
||||
bool has_move = GetLineMove(line, p1, p2, t1, t2);
|
||||
|
||||
if (hasMove) SetOverride(line, "\\pos",wxString::Format("(%i,%i)",x1,y1));
|
||||
else SetOverride(line, "\\move",wxString::Format("(%i,%i,%i,%i,%i,%i)",x1,y1,x1,y1,0,line->End.GetMS() - line->Start.GetMS()));
|
||||
if (has_move)
|
||||
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();
|
||||
Refresh();
|
||||
OnFileChanged();
|
||||
UpdateToggleButtons();
|
||||
}
|
||||
|
||||
|
@ -122,161 +105,142 @@ void VisualToolDrag::OnLineChanged() {
|
|||
void VisualToolDrag::OnFileChanged() {
|
||||
/// @todo it should be possible to preserve the selection in some cases
|
||||
features.clear();
|
||||
ClearSelection();
|
||||
primary = NULL;
|
||||
sel_features.clear();
|
||||
primary = 0;
|
||||
active_feature = features.end();
|
||||
|
||||
for (int i = c->subsGrid->GetRows() - 1; i >=0; i--) {
|
||||
AssDialogue *diag = c->subsGrid->GetDialogue(i);
|
||||
if (c->subsGrid->IsDisplayed(diag)) {
|
||||
MakeFeatures(diag);
|
||||
}
|
||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it);
|
||||
if (diag && IsDisplayed(diag))
|
||||
MakeFeatures(diag);
|
||||
}
|
||||
|
||||
UpdateToggleButtons();
|
||||
}
|
||||
|
||||
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 end = features.end();
|
||||
|
||||
for (int i = c->subsGrid->GetRows() - 1; i >=0; i--) {
|
||||
AssDialogue *diag = c->subsGrid->GetDialogue(i);
|
||||
if (c->subsGrid->IsDisplayed(diag)) {
|
||||
for (entryIter it = c->ass->Line.begin(); it != c->ass->Line.end(); ++it) {
|
||||
AssDialogue *diag = dynamic_cast<AssDialogue*>(*it);
|
||||
if (!diag) continue;
|
||||
|
||||
if (IsDisplayed(diag)) {
|
||||
// Features don't exist and should
|
||||
if (feat == end || feat->line != diag) {
|
||||
if (feat == end || feat->line != diag)
|
||||
MakeFeatures(diag, feat);
|
||||
}
|
||||
// Move past already existing features for the line
|
||||
else {
|
||||
else
|
||||
while (feat != end && feat->line == diag) ++feat;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remove all features for this line (if any)
|
||||
while (feat != end && feat->line == diag) {
|
||||
feat->line = NULL;
|
||||
feat->line = 0;
|
||||
RemoveSelection(feat);
|
||||
feat = features.erase(feat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
active_feature = features.end();
|
||||
}
|
||||
|
||||
void VisualToolDrag::OnSelectedSetChanged(const Selection &added, const Selection &removed) {
|
||||
c->selectionController->GetSelectedSet(selection);
|
||||
if (!externalChange) return;
|
||||
externalChange = false;
|
||||
c->subsGrid->BeginBatch();
|
||||
|
||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||
// Remove all deselected lines
|
||||
if (removed.find(cur->line) != removed.end()) {
|
||||
RemoveSelection(cur);
|
||||
}
|
||||
// And add all newly selected lines
|
||||
else if (added.find(cur->line) != added.end() && cur->type == DRAG_START) {
|
||||
AddSelection(cur);
|
||||
}
|
||||
for (feature_iterator it = features.begin(); it != features.end(); ++it) {
|
||||
if (removed.count(it->line))
|
||||
sel_features.erase(it);
|
||||
else if (added.count(it->line) && it->type == DRAG_START)
|
||||
sel_features.insert(it);
|
||||
}
|
||||
|
||||
c->subsGrid->EndBatch();
|
||||
externalChange = true;
|
||||
}
|
||||
|
||||
void VisualToolDrag::Draw() {
|
||||
DrawAllFeatures();
|
||||
|
||||
// Draw arrows
|
||||
// Draw connecting lines
|
||||
for (feature_iterator cur = features.begin(); cur != features.end(); ++cur) {
|
||||
if (cur->type == DRAG_START) continue;
|
||||
|
||||
feature_iterator p2 = cur;
|
||||
feature_iterator p1 = cur->parent;
|
||||
|
||||
// Has arrow?
|
||||
bool hasArrow = p2->type == DRAG_END;
|
||||
int arrowLen = hasArrow ? 10 : 0;
|
||||
// Move end marker has an arrow; origin doesn't
|
||||
bool has_arrow = p2->type == DRAG_END;
|
||||
int arrow_len = has_arrow ? 10 : 0;
|
||||
|
||||
// See if the distance between them is enough
|
||||
int dx = p2->x - p1->x;
|
||||
int dy = p2->y - p1->y;
|
||||
int dist = (int)sqrt(double(dx*dx + dy*dy));
|
||||
if (dist < 20+arrowLen) continue;
|
||||
// Don't show the connecting line if the features are very close
|
||||
Vector2D direction = p2->pos - p1->pos;
|
||||
if (direction.SquareLen() < (20 + arrow_len) * (20 + arrow_len)) continue;
|
||||
|
||||
// Get end points
|
||||
int x1 = p1->x + dx*10/dist;
|
||||
int x2 = p2->x - dx*(10+arrowLen)/dist;
|
||||
int y1 = p1->y + dy*10/dist;
|
||||
int y2 = p2->y - dy*(10+arrowLen)/dist;
|
||||
direction = direction.Unit();
|
||||
// Get the start and end points of the line
|
||||
Vector2D start = p1->pos + direction * 10;
|
||||
Vector2D end = p2->pos - direction * (10 + arrow_len);
|
||||
|
||||
// Draw arrow
|
||||
if (hasArrow) {
|
||||
// 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);
|
||||
if (has_arrow) {
|
||||
gl.SetLineColour(colour[3], 0.8f, 2);
|
||||
|
||||
// Arrow line
|
||||
SetLineColour(colour[3],0.8f,2);
|
||||
DrawLine(x1,y1,x2,y2);
|
||||
gl.DrawLine(start, end);
|
||||
|
||||
// Arrow head
|
||||
DrawLine(x2+sx,y2-sy,x2-sx,y2+sy);
|
||||
DrawLine(x2+sx,y2-sy,x2+dx*10/dist,y2+dy*10/dist);
|
||||
DrawLine(x2-sx,y2+sy,x2+dx*10/dist,y2+dy*10/dist);
|
||||
Vector2D t_half_base_w = Vector2D(-direction.Y(), direction.X()) * 4;
|
||||
gl.DrawTriangle(end + direction * arrow_len, end + t_half_base_w, end - t_half_base_w);
|
||||
}
|
||||
|
||||
// Draw dashed line
|
||||
else {
|
||||
SetLineColour(colour[3],0.5f,2);
|
||||
DrawDashedLine(x1,y1,x2,y2,6);
|
||||
gl.SetLineColour(colour[3], 0.5f, 2);
|
||||
gl.DrawDashedLine(start, end, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag) {
|
||||
MakeFeatures(diag, features.end());
|
||||
}
|
||||
|
||||
void VisualToolDrag::MakeFeatures(AssDialogue *diag, feature_iterator pos) {
|
||||
// Get position
|
||||
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);
|
||||
Vector2D p1 = FromScriptCoords(GetLinePosition(diag));
|
||||
|
||||
// Create \pos feature
|
||||
Feature feat;
|
||||
feat.x = x1;
|
||||
feat.y = y1;
|
||||
feat.pos = p1;
|
||||
feat.layer = 0;
|
||||
feat.type = DRAG_START;
|
||||
feat.time = t1;
|
||||
feat.time = 0;
|
||||
feat.line = diag;
|
||||
feat.parent = features.end();
|
||||
features.insert(pos, feat);
|
||||
feature_iterator cur = pos; --cur;
|
||||
feat.parent = cur;
|
||||
if (selection.find(diag) != selection.end()) {
|
||||
AddSelection(cur);
|
||||
}
|
||||
if (selection.count(diag))
|
||||
sel_features.insert(cur);
|
||||
|
||||
Vector2D p2;
|
||||
int t1, t2;
|
||||
|
||||
// Create move destination feature
|
||||
if (hasMove) {
|
||||
feat.x = x2;
|
||||
feat.y = y2;
|
||||
if (GetLineMove(diag, p1, p2, t1, t2)) {
|
||||
feat.pos = FromScriptCoords(p2);
|
||||
feat.layer = 1;
|
||||
feat.type = DRAG_END;
|
||||
feat.parent->time = t1;
|
||||
feat.time = t2;
|
||||
feat.line = diag;
|
||||
features.insert(pos, feat);
|
||||
feat.parent->parent = --pos; ++pos;
|
||||
}
|
||||
|
||||
// Create org feature
|
||||
if (torgx != x1 || torgy != y1) {
|
||||
feat.x = torgx;
|
||||
feat.y = torgy;
|
||||
if (Vector2D org = GetLineOrigin(diag)) {
|
||||
feat.pos = FromScriptCoords(org);
|
||||
feat.layer = -1;
|
||||
feat.type = DRAG_ORIGIN;
|
||||
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
|
||||
// selected features by the same amount
|
||||
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;
|
||||
|
||||
for (sel_iterator cur = selectedFeatures.begin(); cur != selectedFeatures.end(); ++cur) {
|
||||
if ((*cur)->type != DRAG_ORIGIN) {
|
||||
(*cur)->time += change;
|
||||
}
|
||||
for (sel_iterator cur = sel_features.begin(); cur != sel_features.end(); ++cur) {
|
||||
(*cur)->time += change;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolDrag::CommitDrag(feature_iterator feature) {
|
||||
void VisualToolDrag::UpdateDrag(feature_iterator feature) {
|
||||
if (feature->type == DRAG_ORIGIN) {
|
||||
int x = feature->x;
|
||||
int y = feature->y;
|
||||
parent->ToScriptCoords(&x, &y);
|
||||
SetOverride(feature->line, "\\org",wxString::Format("(%i,%i)",x,y));
|
||||
SetOverride(feature->line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
return;
|
||||
}
|
||||
|
||||
feature_iterator p = feature->parent;
|
||||
if (feature->type == DRAG_END) {
|
||||
std::swap(feature, p);
|
||||
}
|
||||
feature_iterator end_feature = feature->parent;
|
||||
if (feature->type == DRAG_END)
|
||||
std::swap(feature, end_feature);
|
||||
|
||||
int x1 = feature->x;
|
||||
int y1 = feature->y;
|
||||
parent->ToScriptCoords(&x1, &y1);
|
||||
|
||||
// Position
|
||||
if (feature->parent == features.end()) {
|
||||
SetOverride(feature->line, "\\pos", wxString::Format("(%i,%i)", x1, y1));
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
if (feature->parent == features.end())
|
||||
SetOverride(feature->line, "\\pos", ToScriptCoords(feature->pos).PStr());
|
||||
else
|
||||
SetOverride(feature->line, "\\move",
|
||||
wxString::Format("(%s,%s,%d,%d)",
|
||||
ToScriptCoords(feature->pos).Str(),
|
||||
ToScriptCoords(end_feature->pos).Str(),
|
||||
feature->time, end_feature->time));
|
||||
}
|
||||
bool VisualToolDrag::Update() {
|
||||
if (!leftDClick) return false;
|
||||
|
||||
int dx, dy;
|
||||
int vx = video.x;
|
||||
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;
|
||||
void VisualToolDrag::OnDoubleClick() {
|
||||
Vector2D d = ToScriptCoords(mouse_pos) - (primary ? ToScriptCoords(primary->pos) : GetLinePosition(active_line));
|
||||
|
||||
for (Selection::const_iterator cur = selection.begin(); cur != selection.end(); ++cur) {
|
||||
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, t1 = INT_MIN, t2 = INT_MIN, orgx, orgy;
|
||||
bool isMove;
|
||||
|
||||
GetLinePosition(*cur, x1, y1, orgx, orgy);
|
||||
GetLineMove(*cur, isMove, x1, y1, x2, y2, t1, t2);
|
||||
parent->ToScriptCoords(&x1, &y1);
|
||||
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));
|
||||
Selection sel = c->selectionController->GetSelectedSet();
|
||||
for (Selection::const_iterator it = sel.begin(); it != sel.end(); ++it) {
|
||||
Vector2D p1, p2;
|
||||
int t1, t2;
|
||||
if (GetLineMove(*it, p1, p2, t1, t2)) {
|
||||
if (t1 > 0 || t2 > 0)
|
||||
SetOverride(*it, "\\move", wxString::Format("(%s,%s,%d,%d)", (p1 + d).Str(), (p2 + d).Str(), t1, t2));
|
||||
else
|
||||
SetOverride(*cur, "\\move", wxString::Format("(%i,%i,%i,%i)", x1, y1, x2, y2));
|
||||
}
|
||||
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));
|
||||
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"));
|
||||
|
||||
OnFileChanged();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -34,11 +21,6 @@
|
|||
/// @ingroup visual_ts
|
||||
///
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/toolbar.h>
|
||||
#endif
|
||||
|
||||
#include "visual_feature.h"
|
||||
#include "visual_tool.h"
|
||||
|
||||
|
@ -51,27 +33,26 @@ public:
|
|||
VisualToolDragDraggableFeature() : VisualDraggableFeature(), time(0) { }
|
||||
};
|
||||
|
||||
class wxBitmapButton;
|
||||
class wxToolBar;
|
||||
|
||||
/// DOCME
|
||||
/// @class VisualToolDrag
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
/// @brief Moveable features for the positions of each visible line
|
||||
class VisualToolDrag : public VisualTool<VisualToolDragDraggableFeature> {
|
||||
/// The subtoolbar for the move/pos conversion button
|
||||
wxToolBar *toolBar;
|
||||
wxToolBar *toolbar;
|
||||
/// The feature last clicked on for the double-click handler
|
||||
/// 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
|
||||
Feature *primary;
|
||||
/// The last announced selection set
|
||||
Selection selection;
|
||||
int change;
|
||||
|
||||
/// 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
|
||||
bool toggleMoveOnMove;
|
||||
bool button_is_move;
|
||||
|
||||
/// @brief Create the features for a line
|
||||
/// @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);
|
||||
|
||||
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<>
|
||||
void OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed);
|
||||
|
||||
void OnFrameChanged();
|
||||
void OnFileChanged();
|
||||
void OnLineChanged();
|
||||
void OnCoordinateSystemsChanged() { OnFileChanged(); }
|
||||
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
void Draw();
|
||||
bool Update();
|
||||
public:
|
||||
VisualToolDrag(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *toolbar);
|
||||
void OnDoubleClick();
|
||||
|
||||
/// Set the pos/move button to the correct icon based on the active line
|
||||
void UpdateToggleButtons();
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -36,175 +23,152 @@
|
|||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#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"
|
||||
|
||||
VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
||||
VisualToolRotateXY::VisualToolRotateXY(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||
{
|
||||
features.resize(1);
|
||||
org = &features.back();
|
||||
org->type = DRAG_BIG_TRIANGLE;
|
||||
DoRefresh();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// Transform grid
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
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);
|
||||
gl.SetOrigin(org->pos);
|
||||
gl.SetRotation(angle_x, angle_y, angle_z);
|
||||
|
||||
// Draw grid
|
||||
glShadeModel(GL_SMOOTH);
|
||||
SetLineColour(colour[0],0.5f,2);
|
||||
SetModeLine();
|
||||
float r = colour[0].Red()/255.f;
|
||||
float g = colour[0].Green()/255.f;
|
||||
float b = colour[0].Blue()/255.f;
|
||||
glBegin(GL_LINES);
|
||||
for (int i=0;i<11;i++) {
|
||||
float a = 1.f - abs(i-5)*0.18f;
|
||||
int pos = 20*(i-5);
|
||||
glColor4f(r,g,b,0.f);
|
||||
glVertex2i(pos,120);
|
||||
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);
|
||||
gl.SetLineColour(colour[0], 0.5f, 2);
|
||||
gl.SetModeLine();
|
||||
float r = colour[0].Red() / 255.f;
|
||||
float g = colour[0].Green() / 255.f;
|
||||
float b = colour[0].Blue() / 255.f;
|
||||
|
||||
std::vector<float> colors(11 * 8 * 4);
|
||||
for (int i = 0; i < 88; ++i) {
|
||||
colors[i * 4 + 0] = r;
|
||||
colors[i * 4 + 1] = g;
|
||||
colors[i * 4 + 2] = b;
|
||||
colors[i * 4 + 3] = (i + 3) % 4 > 1 ? 0 : (1.f - abs(i / 8 - 5) * 0.18f);
|
||||
}
|
||||
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
|
||||
SetLineColour(colour[3],1.f,2);
|
||||
SetModeLine();
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(0.f,0.f,0.f);
|
||||
glVertex3f(50.f,0.f,0.f);
|
||||
glVertex3f(0.f,0.f,0.f);
|
||||
glVertex3f(0.f,50.f,0.f);
|
||||
glVertex3f(0.f,0.f,0.f);
|
||||
glVertex3f(0.f,0.f,50.f);
|
||||
glEnd();
|
||||
gl.SetLineColour(colour[3], 1.f, 2);
|
||||
float vectors[] = {
|
||||
0.f, 0.f, 0.f,
|
||||
50.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f,
|
||||
0.f, 50.f, 0.f,
|
||||
0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 50.f,
|
||||
};
|
||||
gl.DrawLines(3, vectors, 6);
|
||||
|
||||
// Draw arrow tops
|
||||
glBegin(GL_TRIANGLE_FAN);
|
||||
glVertex3f(60.f,0.f,0.f);
|
||||
glVertex3f(50.f,-3.f,-3.f);
|
||||
glVertex3f(50.f,3.f,-3.f);
|
||||
glVertex3f(50.f,3.f,3.f);
|
||||
glVertex3f(50.f,-3.f,3.f);
|
||||
glVertex3f(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();
|
||||
float arrows[] = {
|
||||
60.f, 0.f, 0.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, -3.f,
|
||||
|
||||
glPopMatrix();
|
||||
glShadeModel(GL_FLAT);
|
||||
0.f, 60.f, 0.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, -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() {
|
||||
startAngleX = (org->y-video.y)*2.f;
|
||||
startAngleY = (video.x-org->x)*2.f;
|
||||
origAngleX = curAngleX;
|
||||
origAngleY = curAngleY;
|
||||
orig_x = angle_x;
|
||||
orig_y = angle_y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolRotateXY::UpdateHold() {
|
||||
float screenAngleX = (org->y-video.y)*2.f;
|
||||
float screenAngleY = (video.x-org->x)*2.f;
|
||||
Vector2D delta = (mouse_pos - drag_start) * 2;
|
||||
if (shift_down)
|
||||
delta = delta.SingleAxis();
|
||||
|
||||
// Deltas
|
||||
float deltaX = screenAngleX - startAngleX;
|
||||
float deltaY = screenAngleY - startAngleY;
|
||||
if (shiftDown) {
|
||||
if (fabs(deltaX) >= fabs(deltaY)) deltaY = 0.f;
|
||||
else deltaX = 0.f;
|
||||
angle_x = orig_x - delta.Y();
|
||||
angle_y = orig_y + delta.X();
|
||||
|
||||
if (ctrl_down) {
|
||||
angle_x = floorf(angle_x / 30.f + .5f) * 30.f;
|
||||
angle_y = floorf(angle_y / 30.f + .5f) * 30.f;
|
||||
}
|
||||
|
||||
// Calculate
|
||||
curAngleX = fmodf(deltaX + origAngleX + 360.f, 360.f);
|
||||
curAngleY = fmodf(deltaY + origAngleY + 360.f, 360.f);
|
||||
angle_x = fmodf(angle_x + 360.f, 360.f);
|
||||
angle_y = fmodf(angle_y + 360.f, 360.f);
|
||||
|
||||
// Oh Snap
|
||||
if (ctrlDown) {
|
||||
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;
|
||||
}
|
||||
SetSelectedOverride("\\frx", wxString::Format("(%0.3g)", angle_x));
|
||||
SetSelectedOverride("\\fry", wxString::Format("(%0.3g)", angle_y));
|
||||
}
|
||||
|
||||
void VisualToolRotateXY::CommitHold() {
|
||||
Selection sel = c->selectionController->GetSelectedSet();
|
||||
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::UpdateDrag(feature_iterator feature) {
|
||||
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
}
|
||||
|
||||
void VisualToolRotateXY::DoRefresh() {
|
||||
if (!curDiag) return;
|
||||
int posx, posy;
|
||||
GetLinePosition(curDiag,posx,posy,org->x,org->y);
|
||||
GetLineRotation(curDiag,curAngleX,curAngleY,curAngleZ);
|
||||
if (!active_line) return;
|
||||
|
||||
if (!(org->pos = GetLineOrigin(active_line)))
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -41,20 +28,20 @@
|
|||
/// @class VisualToolRotateXY
|
||||
/// @brief DOCME
|
||||
class VisualToolRotateXY : public VisualTool<VisualDraggableFeature> {
|
||||
float curAngleX,startAngleX,origAngleX;
|
||||
float curAngleY,startAngleY,origAngleY;
|
||||
float curAngleZ;
|
||||
float angle_x; /// Current x rotation
|
||||
float angle_y; /// Current y rotation
|
||||
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;
|
||||
|
||||
void DoRefresh();
|
||||
void Draw();
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
void CommitHold();
|
||||
|
||||
void CommitDrag(feature_iterator feature);
|
||||
|
||||
void DoRefresh();
|
||||
|
||||
void Draw();
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -39,133 +26,110 @@
|
|||
#include <cmath>
|
||||
#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 "utils.h"
|
||||
|
||||
static const float deg2rad = 3.1415926536f / 180.f;
|
||||
static const float rad2deg = 180.f / 3.1415926536f;
|
||||
|
||||
VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
||||
VisualToolRotateZ::VisualToolRotateZ(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||
{
|
||||
features.resize(1);
|
||||
org = &features.back();
|
||||
org->type = DRAG_BIG_TRIANGLE;
|
||||
DoRefresh();
|
||||
}
|
||||
|
||||
void VisualToolRotateZ::Draw() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
|
||||
// Draw pivot
|
||||
DrawAllFeatures();
|
||||
|
||||
int radius = (int)sqrt(double((posx-org->x)*(posx-org->x)+(posy-org->y)*(posy-org->y)));
|
||||
int oRadius = radius;
|
||||
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);
|
||||
float radius = (pos - org->pos).Len();
|
||||
float oRadius = radius;
|
||||
if (radius < 50)
|
||||
radius = 50;
|
||||
|
||||
// Set up the projection
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
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);
|
||||
gl.SetOrigin(org->pos);
|
||||
gl.SetRotation(rotation_x, rotation_y, 0);
|
||||
gl.SetScale(scale);
|
||||
|
||||
// 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
|
||||
int markers = 6;
|
||||
float markStart = -90.f / markers;
|
||||
float markEnd = markStart+(180.f/markers);
|
||||
for (int i=0;i<markers;i++) {
|
||||
float angle = i*(360.f/markers);
|
||||
DrawRing(0,0,radius+30,radius+12,radius/radius,angle+markStart,angle+markEnd);
|
||||
float markEnd = markStart + (180.f / markers);
|
||||
for (int i = 0; i < markers; ++i) {
|
||||
float angle = i * (360.f / markers);
|
||||
gl.DrawRing(Vector2D(), radius+30, radius+12, 1.0, angle+markStart, angle+markEnd);
|
||||
}
|
||||
|
||||
// Draw the baseline
|
||||
SetLineColour(colour[3],1.f,2);
|
||||
DrawLine(deltax,deltay,-deltax,-deltay);
|
||||
// Draw the baseline through the origin showing current rotation
|
||||
Vector2D angle_vec(Vector2D::FromAngle(angle * deg2rad));
|
||||
gl.SetLineColour(colour[3], 1, 2);
|
||||
gl.DrawLine(angle_vec * -radius, angle_vec * radius);
|
||||
|
||||
// Draw the connection line
|
||||
if (org->x != posx || org->y != posy) {
|
||||
double angle = atan2(double(org->y-posy),double(posx-org->x)) + curAngle*deg2rad;
|
||||
int fx = int(cos(angle)*oRadius);
|
||||
int fy = -int(sin(angle)*oRadius);
|
||||
DrawLine(0,0,fx,fy);
|
||||
int mdx = int(cos(curAngle*deg2rad)*20);
|
||||
int mdy = int(-sin(curAngle*deg2rad)*20);
|
||||
DrawLine(fx-mdx,fy-mdy,fx+mdx,fy+mdy);
|
||||
if (org->pos != pos) {
|
||||
Vector2D rotated_pos = Vector2D::FromAngle(angle * deg2rad - (pos - org->pos).Angle()) * oRadius;
|
||||
|
||||
// Draw the line from origin to rotated position
|
||||
gl.DrawLine(Vector2D(), rotated_pos);
|
||||
|
||||
// Draw the line under the text
|
||||
gl.DrawLine(rotated_pos - angle_vec * 20, rotated_pos + angle_vec * 20);
|
||||
}
|
||||
|
||||
// Draw the rotation line
|
||||
SetLineColour(colour[0],1.f,1);
|
||||
SetFillColour(colour[1],0.3f);
|
||||
DrawCircle(deltax,deltay,4);
|
||||
// Draw the fake features on the ring
|
||||
gl.SetLineColour(colour[0], 1.f, 1);
|
||||
gl.SetFillColour(colour[1], 0.3f);
|
||||
gl.DrawCircle(angle_vec * radius, 4);
|
||||
gl.DrawCircle(angle_vec * -radius, 4);
|
||||
|
||||
glPopMatrix();
|
||||
// Clear the projection
|
||||
gl.ResetTransform();
|
||||
|
||||
// Draw line to mouse
|
||||
if (!dragging && curFeature == features.end() && video.x > INT_MIN && video.y > INT_MIN) {
|
||||
SetLineColour(colour[0]);
|
||||
DrawLine(org->x,org->y,video.x,video.y);
|
||||
// Draw line to mouse if it isn't over the origin feature
|
||||
if (mouse_pos && (mouse_pos - org->pos).SquareLen() > 100) {
|
||||
gl.SetLineColour(colour[0]);
|
||||
gl.DrawLine(org->pos, mouse_pos);
|
||||
}
|
||||
}
|
||||
|
||||
bool VisualToolRotateZ::InitializeHold() {
|
||||
startAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
|
||||
origAngle = curAngle;
|
||||
curDiag->StripTag("\\frz");
|
||||
curDiag->StripTag("\\fr");
|
||||
|
||||
orig_angle = angle + (org->pos - mouse_pos).Angle() * rad2deg;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolRotateZ::UpdateHold() {
|
||||
float screenAngle = atan2(double(org->y-video.y),double(video.x-org->x)) * rad2deg;
|
||||
curAngle = fmodf(screenAngle - startAngle + origAngle + 360.f, 360.f);
|
||||
angle = orig_angle - (org->pos - mouse_pos).Angle() * rad2deg;
|
||||
|
||||
// Oh Snap
|
||||
if (ctrlDown) {
|
||||
curAngle = floorf(curAngle/30.f+.5f)*30.f;
|
||||
if (curAngle > 359.f) curAngle = 0.f;
|
||||
}
|
||||
if (ctrl_down)
|
||||
angle = floorf(angle / 30.f + .5f) * 30.f;
|
||||
|
||||
angle = fmodf(angle + 360.f, 360.f);
|
||||
|
||||
SetSelectedOverride("\\frz", wxString::Format("(%0.3g)", angle));
|
||||
}
|
||||
|
||||
void VisualToolRotateZ::CommitHold() {
|
||||
Selection sel = c->selectionController->GetSelectedSet();
|
||||
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::UpdateDrag(feature_iterator feature) {
|
||||
SetOverride(active_line, "\\org", ToScriptCoords(feature->pos).PStr());
|
||||
}
|
||||
|
||||
void VisualToolRotateZ::DoRefresh() {
|
||||
if (!curDiag) return;
|
||||
GetLinePosition(curDiag, posx, posy, org->x, org->y);
|
||||
GetLineRotation(curDiag, rx, ry, curAngle);
|
||||
GetLineScale(curDiag, scaleX, scaleY);
|
||||
if (!active_line) return;
|
||||
|
||||
pos = FromScriptCoords(GetLinePosition(active_line));
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -37,29 +24,30 @@
|
|||
#include "visual_feature.h"
|
||||
#include "visual_tool.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class VisualToolRotateZ
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class VisualToolRotateZ : public VisualTool<VisualDraggableFeature> {
|
||||
float curAngle, startAngle, origAngle;
|
||||
Feature *org;
|
||||
int posx, posy;
|
||||
float rx, ry;
|
||||
float scaleX, scaleY;
|
||||
float angle; ///< Current Z rotation
|
||||
float orig_angle; ///< Z rotation at the beginning of the current hold
|
||||
Vector2D pos; ///< Position of the dialogue line
|
||||
Vector2D scale; ///< Current scale
|
||||
|
||||
float rotation_x; ///< Current X rotation
|
||||
float rotation_y; ///< Current Y rotation
|
||||
|
||||
Feature *org; ///< The origin feature
|
||||
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
void CommitHold();
|
||||
|
||||
void CommitDrag(feature_iterator feature);
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
|
||||
void DoRefresh();
|
||||
|
||||
void Draw();
|
||||
bool Update() { return true; }
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -36,126 +23,95 @@
|
|||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#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"
|
||||
|
||||
VisualToolScale::VisualToolScale(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar *)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context, video)
|
||||
, curScaleX(0.f)
|
||||
, origScaleX(0.f)
|
||||
, curScaleY(0.f)
|
||||
, origScaleY(0.f)
|
||||
, startX(0)
|
||||
, startY(0)
|
||||
#include "utils.h"
|
||||
|
||||
VisualToolScale::VisualToolScale(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualDraggableFeature>(parent, context)
|
||||
{
|
||||
DoRefresh();
|
||||
}
|
||||
|
||||
void VisualToolScale::Draw() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
|
||||
int len = 160;
|
||||
int dx = mid(len/2+10,posx,video.w-len/2-30);
|
||||
int dy = mid(len/2+10,posy,video.h-len/2-30);
|
||||
// The length in pixels of the 100% zoom
|
||||
static const int base_len = 160;
|
||||
// The width of the y scale guide/height of the x scale guide
|
||||
static const int guide_size = 10;
|
||||
|
||||
SetLineColour(colour[0]);
|
||||
SetFillColour(colour[1],0.3f);
|
||||
// Ensure that the scaling UI is comfortably visible on screen
|
||||
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
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
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
|
||||
int lenx = int(1.6 * curScaleX);
|
||||
int leny = int(1.6 * curScaleY);
|
||||
int drawX = len/2 + 10;
|
||||
int drawY = len/2 + 10;
|
||||
// Set the origin to the base point and apply the line's rotation
|
||||
gl.SetOrigin(base_point);
|
||||
gl.SetRotation(rx, ry, rz);
|
||||
|
||||
// Draw length markers
|
||||
SetLineColour(colour[3],1.f,2);
|
||||
DrawLine(-lenx/2,drawY+10,lenx/2,drawY+10);
|
||||
DrawLine(drawX+10,-leny/2,drawX+10,leny/2);
|
||||
SetLineColour(colour[0],1.f,1);
|
||||
SetFillColour(colour[1],0.3f);
|
||||
DrawCircle(lenx/2,drawY+10,4);
|
||||
DrawCircle(drawX+10,-leny/2,4);
|
||||
Vector2D scale_half_length = scale * base_len / 200;
|
||||
float minor_dim_offset = base_len / 2 + guide_size * 1.5f;
|
||||
|
||||
// Draw horizontal scale
|
||||
SetLineColour(colour[0],1.f,1);
|
||||
DrawRectangle(-len/2,drawY,len/2+1,drawY+5);
|
||||
SetLineColour(colour[0],1.f,2);
|
||||
DrawLine(-len/2+1,drawY+5,-len/2+1,drawY+15);
|
||||
DrawLine(len/2,drawY+5,len/2,drawY+15);
|
||||
// The ends of the current scale amount lines
|
||||
Vector2D x_p1(minor_dim_offset, -scale_half_length.Y());
|
||||
Vector2D x_p2(minor_dim_offset, scale_half_length.Y());
|
||||
Vector2D y_p1(-scale_half_length.X(), minor_dim_offset);
|
||||
Vector2D y_p2(scale_half_length.X(), minor_dim_offset);
|
||||
|
||||
// Draw vertical scale
|
||||
SetLineColour(colour[0],1.f,1);
|
||||
DrawRectangle(drawX,-len/2,drawX+5,len/2+1);
|
||||
SetLineColour(colour[0],1.f,2);
|
||||
DrawLine(drawX+5,-len/2+1,drawX+15,-len/2+1);
|
||||
DrawLine(drawX+5,len/2,drawX+15,len/2);
|
||||
// Current scale amount lines
|
||||
gl.SetLineColour(colour[3], 1.f, 2);
|
||||
gl.DrawLine(x_p1, x_p2);
|
||||
gl.DrawLine(y_p1, y_p2);
|
||||
|
||||
glPopMatrix();
|
||||
// Fake features at the end of the lines
|
||||
gl.SetLineColour(colour[0], 1.f, 1);
|
||||
gl.SetFillColour(colour[1], 0.3f);
|
||||
gl.DrawCircle(x_p1, 4);
|
||||
gl.DrawCircle(x_p2, 4);
|
||||
gl.DrawCircle(y_p1, 4);
|
||||
gl.DrawCircle(y_p2, 4);
|
||||
|
||||
// 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() {
|
||||
startX = video.x;
|
||||
startY = video.y;
|
||||
origScaleX = curScaleX;
|
||||
origScaleY = curScaleY;
|
||||
curDiag->StripTag("\\fscx");
|
||||
curDiag->StripTag("\\fscy");
|
||||
|
||||
initial_scale = scale;
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisualToolScale::UpdateHold() {
|
||||
// Deltas
|
||||
int deltaX = video.x - startX;
|
||||
int deltaY = startY - video.y;
|
||||
if (shiftDown) {
|
||||
if (abs(deltaX) >= abs(deltaY)) deltaY = 0;
|
||||
else deltaX = 0;
|
||||
}
|
||||
Vector2D delta = mouse_pos - drag_start;
|
||||
if (shift_down)
|
||||
delta = delta.SingleAxis();
|
||||
|
||||
// Calculate
|
||||
curScaleX = std::max(deltaX*1.25f + origScaleX, 0.f);
|
||||
curScaleY = std::max(deltaY*1.25f + origScaleY, 0.f);
|
||||
scale = Vector2D().Max(delta * 1.25f + initial_scale);
|
||||
if (ctrl_down)
|
||||
scale = scale.Round(25.f);
|
||||
|
||||
// Oh Snap
|
||||
if (ctrlDown) {
|
||||
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));
|
||||
}
|
||||
SetSelectedOverride("\\fscx", wxString::Format("(%0.3g)", scale.X()));
|
||||
SetSelectedOverride("\\fscy", wxString::Format("(%0.3g)", scale.Y()));
|
||||
}
|
||||
|
||||
void VisualToolScale::DoRefresh() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
|
||||
GetLineScale(curDiag, curScaleX, curScaleY);
|
||||
GetLinePosition(curDiag, posx, posy);
|
||||
GetLineRotation(curDiag, rx, ry, rz);
|
||||
GetLineScale(active_line, scale);
|
||||
GetLineRotation(active_line, rx, ry, rz);
|
||||
pos = FromScriptCoords(GetLinePosition(active_line));
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -41,20 +28,19 @@
|
|||
/// @class VisualToolScale
|
||||
/// @brief DOCME
|
||||
class VisualToolScale : public VisualTool<VisualDraggableFeature> {
|
||||
float curScaleX, origScaleX;
|
||||
float curScaleY, origScaleY;
|
||||
|
||||
int startX, startY;
|
||||
int posx, posy;
|
||||
float rx, ry, rz;
|
||||
Vector2D scale; ///< The current scale
|
||||
Vector2D initial_scale; ///< The scale at the beginning of the current hold
|
||||
Vector2D pos; ///< Position of the line
|
||||
|
||||
float rx; ///< X rotation
|
||||
float ry; ///< Y rotation
|
||||
float rz; ///< Z rotation
|
||||
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
void CommitHold();
|
||||
|
||||
void DoRefresh();
|
||||
void Draw();
|
||||
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
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -38,30 +25,18 @@
|
|||
#ifndef AGI_PRE
|
||||
#include <wx/toolbar.h>
|
||||
|
||||
#ifdef HAVE_APPLE_OPENGL_FRAMEWORK
|
||||
#include <OpenGL/glext.h>
|
||||
#else
|
||||
#include "gl/glext.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
/// Noop macro, this should never be defined in a header.
|
||||
#define APIENTRY
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ass_dialogue.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "utils.h"
|
||||
#include "video_display.h"
|
||||
|
||||
/// Button IDs
|
||||
enum {
|
||||
BUTTON_DRAG = VISUAL_SUB_TOOL_START,
|
||||
BUTTON_DRAG = 1300,
|
||||
BUTTON_LINE,
|
||||
BUTTON_BICUBIC,
|
||||
BUTTON_CONVERT,
|
||||
|
@ -72,34 +47,28 @@ enum {
|
|||
BUTTON_LAST // Leave this at the end and don't use it
|
||||
};
|
||||
|
||||
template<class C, class O, class M>
|
||||
static void for_each_iter(C &container, O obj, M method) {
|
||||
typename C::iterator end = container.end();
|
||||
for (typename C::iterator cur = container.begin(); cur != end; ++cur) {
|
||||
(obj ->* method)(cur);
|
||||
}
|
||||
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context)
|
||||
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, context)
|
||||
, spline(*this)
|
||||
{
|
||||
}
|
||||
|
||||
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, agi::Context *context, VideoState const& video, wxToolBar * toolBar)
|
||||
: VisualTool<VisualToolVectorClipDraggableFeature>(parent, context, video)
|
||||
, spline(*parent)
|
||||
, toolBar(toolBar)
|
||||
{
|
||||
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);
|
||||
void VisualToolVectorClip::SetToolbar(wxToolBar *toolBar) {
|
||||
this->toolBar = toolBar;
|
||||
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->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_REMOVE,_("Remove"),GETIMAGE(visual_vector_clip_remove_24),_("Removes a control point."),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_REMOVE, _("Remove"), GETIMAGE(visual_vector_clip_remove_24), _("Removes a control point."), wxITEM_CHECK);
|
||||
toolBar->AddSeparator();
|
||||
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->ToggleTool(BUTTON_DRAG,true);
|
||||
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->ToggleTool(BUTTON_DRAG, true);
|
||||
toolBar->Realize();
|
||||
toolBar->Show(true);
|
||||
|
||||
DoRefresh();
|
||||
toolBar->Bind(wxEVT_COMMAND_TOOL_CLICKED, &VisualToolVectorClip::OnSubTool, this);
|
||||
SetMode(features.empty());
|
||||
}
|
||||
|
||||
|
@ -107,35 +76,23 @@ void VisualToolVectorClip::OnSubTool(wxCommandEvent &event) {
|
|||
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
|
||||
// rather than one per group
|
||||
for (int i=BUTTON_DRAG;i<BUTTON_LAST;i++) {
|
||||
toolBar->ToggleTool(i,i == newMode + BUTTON_DRAG);
|
||||
}
|
||||
mode = newMode;
|
||||
}
|
||||
for (int i = BUTTON_DRAG; i < BUTTON_LAST; i++)
|
||||
toolBar->ToggleTool(i, i == new_mode + BUTTON_DRAG);
|
||||
|
||||
// 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++);
|
||||
}
|
||||
mode = new_mode;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool is_move(SplineCurve const& c) {
|
||||
return c.type == CURVE_POINT;
|
||||
return c.type == SplineCurve::POINT;
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::Draw() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
if (spline.empty()) return;
|
||||
|
||||
GL_EXT(PFNGLMULTIDRAWARRAYSPROC, glMultiDrawArrays);
|
||||
|
||||
// Parse vector
|
||||
std::vector<float> points;
|
||||
std::vector<int> start;
|
||||
|
@ -144,78 +101,33 @@ void VisualToolVectorClip::Draw() {
|
|||
spline.GetPointList(points, start, count);
|
||||
assert(!start.empty());
|
||||
assert(!count.empty());
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
|
||||
|
||||
// The following is nonzero winding-number PIP based on stencils
|
||||
gl.SetLineColour(colour[3], 1.f, 2);
|
||||
gl.SetFillColour(wxColour(0, 0, 0), 0.5f);
|
||||
|
||||
// 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());
|
||||
gl.DrawMultiPolygon(points, start, count, video_res, !inverse);
|
||||
|
||||
Vector2D pt;
|
||||
float t;
|
||||
Spline::iterator highCurve;
|
||||
spline.GetClosestParametricPoint(Vector2D(video.x, video.y), highCurve, t, pt);
|
||||
Spline::iterator highlighted_curve;
|
||||
spline.GetClosestParametricPoint(mouse_pos, highlighted_curve, t, pt);
|
||||
|
||||
// Draw highlighted line
|
||||
if ((mode == 3 || mode == 4) && curFeature == features.end() && points.size() > 2) {
|
||||
std::vector<float> highPoints;
|
||||
spline.GetPointList(highPoints, highCurve);
|
||||
if (!highPoints.empty()) {
|
||||
glVertexPointer(2, GL_FLOAT, 0, &highPoints[0]);
|
||||
SetLineColour(colour[2], 1.f, 2);
|
||||
SetModeLine();
|
||||
glDrawArrays(GL_LINE_STRIP, 0, highPoints.size() / 2);
|
||||
if ((mode == 3 || mode == 4) && active_feature == features.end() && points.size() > 2) {
|
||||
std::vector<float> highlighted_points;
|
||||
spline.GetPointList(highlighted_points, highlighted_curve);
|
||||
if (!highlighted_points.empty()) {
|
||||
gl.SetLineColour(colour[2], 1.f, 2);
|
||||
gl.DrawLineStrip(2, highlighted_points);
|
||||
}
|
||||
}
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
// Draw lines connecting the bicubic features
|
||||
SetLineColour(colour[3],0.9f,1);
|
||||
for (Spline::iterator cur=spline.begin();cur!=spline.end();cur++) {
|
||||
if (cur->type == CURVE_BICUBIC) {
|
||||
DrawDashedLine(cur->p1.x,cur->p1.y,cur->p2.x,cur->p2.y,6);
|
||||
DrawDashedLine(cur->p3.x,cur->p3.y,cur->p4.x,cur->p4.y,6);
|
||||
gl.SetLineColour(colour[3], 0.9f, 1);
|
||||
for (Spline::iterator cur = spline.begin(); cur != spline.end(); ++cur) {
|
||||
if (cur->type == SplineCurve::BICUBIC) {
|
||||
gl.DrawDashedLine(cur->p1, cur->p2, 6);
|
||||
gl.DrawDashedLine(cur->p3, cur->p4, 6);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,94 +135,84 @@ void VisualToolVectorClip::Draw() {
|
|||
|
||||
// Draw preview of inserted line
|
||||
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);
|
||||
SplineCurve *c1 = &spline.back();
|
||||
DrawDashedLine(video.x,video.y,c0->p1.x,c0->p1.y,6);
|
||||
DrawDashedLine(video.x,video.y,c1->EndPoint().x,c1->EndPoint().y,6);
|
||||
gl.DrawDashedLine(mouse_pos, c0->p1, 6);
|
||||
gl.DrawDashedLine(mouse_pos, c1->EndPoint(), 6);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
Feature feat;
|
||||
if (cur->type == CURVE_POINT) {
|
||||
feat.x = (int)cur->p1.x;
|
||||
feat.y = (int)cur->p1.y;
|
||||
feat.curve = cur;
|
||||
|
||||
if (cur->type == SplineCurve::POINT) {
|
||||
feat.pos = cur->p1;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.curve = cur;
|
||||
feat.point = 0;
|
||||
features.push_back(feat);
|
||||
}
|
||||
|
||||
else if (cur->type == CURVE_LINE) {
|
||||
feat.x = (int)cur->p2.x;
|
||||
feat.y = (int)cur->p2.y;
|
||||
else if (cur->type == SplineCurve::LINE) {
|
||||
feat.pos = cur->p2;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.curve = cur;
|
||||
feat.point = 1;
|
||||
features.push_back(feat);
|
||||
}
|
||||
|
||||
else if (cur->type == CURVE_BICUBIC) {
|
||||
else if (cur->type == SplineCurve::BICUBIC) {
|
||||
// Control points
|
||||
feat.x = (int)cur->p2.x;
|
||||
feat.y = (int)cur->p2.y;
|
||||
feat.curve = cur;
|
||||
feat.pos = cur->p2;
|
||||
feat.point = 1;
|
||||
feat.type = DRAG_SMALL_SQUARE;
|
||||
features.push_back(feat);
|
||||
|
||||
feat.x = (int)cur->p3.x;
|
||||
feat.y = (int)cur->p3.y;
|
||||
feat.pos = cur->p3;
|
||||
feat.point = 2;
|
||||
features.push_back(feat);
|
||||
|
||||
// End point
|
||||
feat.x = (int)cur->p4.x;
|
||||
feat.y = (int)cur->p4.y;
|
||||
feat.pos = cur->p4;
|
||||
feat.type = DRAG_SMALL_CIRCLE;
|
||||
feat.point = 3;
|
||||
features.push_back(feat);
|
||||
}
|
||||
features.push_back(feat);
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::MakeFeatures() {
|
||||
ClearSelection();
|
||||
sel_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() {
|
||||
SetOverride(curDiag, inverse ? "\\iclip" : "\\clip", "(" + spline.EncodeToASS() + ")");
|
||||
SetOverride(active_line, inverse ? "\\iclip" : "\\clip", "(" + spline.EncodeToASS() + ")");
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::UpdateDrag(feature_iterator feature) {
|
||||
spline.MovePoint(feature->curve,feature->point,Vector2D(feature->x,feature->y));
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::CommitDrag(feature_iterator) {
|
||||
spline.MovePoint(feature->curve, feature->point, feature->pos);
|
||||
Save();
|
||||
}
|
||||
|
||||
bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
||||
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
|
||||
feature->curve->type = CURVE_LINE;
|
||||
feature->curve->type = SplineCurve::LINE;
|
||||
feature->curve->p2 = feature->curve->p4;
|
||||
}
|
||||
else {
|
||||
Spline::iterator next = feature->curve;
|
||||
next++;
|
||||
if (next != spline.end()) {
|
||||
if (feature->curve->type == CURVE_POINT) {
|
||||
if (feature->curve->type == SplineCurve::POINT) {
|
||||
next->p1 = next->EndPoint();
|
||||
next->type = CURVE_POINT;
|
||||
next->type = SplineCurve::POINT;
|
||||
}
|
||||
else {
|
||||
next->p1 = feature->curve->p1;
|
||||
|
@ -319,7 +221,7 @@ bool VisualToolVectorClip::InitializeDrag(feature_iterator feature) {
|
|||
|
||||
spline.erase(feature->curve);
|
||||
}
|
||||
curFeature = features.end();
|
||||
active_feature = features.end();
|
||||
|
||||
Save();
|
||||
MakeFeatures();
|
||||
|
@ -333,21 +235,20 @@ bool VisualToolVectorClip::InitializeHold() {
|
|||
if (mode == 1 || mode == 2) {
|
||||
SplineCurve curve;
|
||||
|
||||
// Set start position
|
||||
if (!spline.empty()) {
|
||||
curve.p1 = spline.back().EndPoint();
|
||||
curve.type = mode == 1 ? CURVE_LINE : CURVE_BICUBIC;
|
||||
// New spline beginning at the clicked point
|
||||
if (spline.empty()) {
|
||||
curve.p1 = mouse_pos;
|
||||
curve.type = SplineCurve::POINT;
|
||||
}
|
||||
|
||||
// First point
|
||||
else {
|
||||
curve.p1 = Vector2D(video.x,video.y);
|
||||
curve.type = CURVE_POINT;
|
||||
// Continue from the spline in progress
|
||||
// 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);
|
||||
ClearSelection();
|
||||
sel_features.clear();
|
||||
MakeFeature(--spline.end());
|
||||
UpdateHold();
|
||||
return true;
|
||||
|
@ -359,93 +260,85 @@ bool VisualToolVectorClip::InitializeHold() {
|
|||
Vector2D pt;
|
||||
Spline::iterator curve;
|
||||
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 (curve != spline.end()) {
|
||||
if (curve->type == CURVE_LINE) {
|
||||
curve->type = CURVE_BICUBIC;
|
||||
if (curve->type == SplineCurve::LINE) {
|
||||
curve->type = SplineCurve::BICUBIC;
|
||||
curve->p4 = curve->p2;
|
||||
curve->p2 = curve->p1 * 0.75 + curve->p4 * 0.25;
|
||||
curve->p3 = curve->p1 * 0.25 + curve->p4 * 0.75;
|
||||
}
|
||||
|
||||
else if (curve->type == CURVE_BICUBIC) {
|
||||
curve->type = CURVE_LINE;
|
||||
else if (curve->type == SplineCurve::BICUBIC) {
|
||||
curve->type = SplineCurve::LINE;
|
||||
curve->p2 = curve->p4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert
|
||||
else {
|
||||
// Check if there is at least one curve to split
|
||||
if (spline.empty()) return false;
|
||||
|
||||
// Split the curve
|
||||
if (curve == spline.end()) {
|
||||
SplineCurve ct;
|
||||
ct.type = CURVE_LINE;
|
||||
ct.p1 = spline.back().EndPoint();
|
||||
ct.p2 = spline.front().p1;
|
||||
ct.p2 = ct.p1*(1-t) + ct.p2*t;
|
||||
SplineCurve ct(spline.back().EndPoint(), spline.front().p1);
|
||||
ct.p2 = ct.p1 * (1 - t) + ct.p2 * t;
|
||||
spline.push_back(ct);
|
||||
}
|
||||
else {
|
||||
SplineCurve c2;
|
||||
curve->Split(*curve,c2,t);
|
||||
curve->Split(*curve, c2, t);
|
||||
spline.insert(++curve, c2);
|
||||
}
|
||||
}
|
||||
|
||||
// Commit
|
||||
Save();
|
||||
MakeFeatures();
|
||||
Commit();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Freehand
|
||||
// Freehand spline draw
|
||||
if (mode == 6 || mode == 7) {
|
||||
ClearSelection();
|
||||
sel_features.clear();
|
||||
features.clear();
|
||||
active_feature = features.end();
|
||||
spline.clear();
|
||||
SplineCurve curve;
|
||||
curve.type = CURVE_POINT;
|
||||
curve.p1.x = video.x;
|
||||
curve.p1.y = video.y;
|
||||
spline.push_back(curve);
|
||||
spline.push_back(SplineCurve(mouse_pos));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @todo box selection?
|
||||
if (mode == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nothing to do for mode 5 (remove)
|
||||
return false;
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::UpdateHold() {
|
||||
// Insert line
|
||||
if (mode == 1) {
|
||||
spline.back().EndPoint() = Vector2D(video.x,video.y);
|
||||
features.back().x = video.x;
|
||||
features.back().y = video.y;
|
||||
spline.back().EndPoint() = mouse_pos;
|
||||
features.back().pos = mouse_pos;
|
||||
}
|
||||
|
||||
// Insert bicubic
|
||||
else if (mode == 2) {
|
||||
SplineCurve &curve = spline.back();
|
||||
curve.EndPoint() = Vector2D(video.x,video.y);
|
||||
curve.EndPoint() = mouse_pos;
|
||||
|
||||
// Control points
|
||||
if (spline.size() > 1) {
|
||||
std::list<SplineCurve>::reverse_iterator iter = spline.rbegin();
|
||||
iter++;
|
||||
SplineCurve &c0 = *iter;
|
||||
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;
|
||||
SplineCurve &c0 = spline.back();
|
||||
float len = (curve.p4 - curve.p1).Len();
|
||||
curve.p2 = (c0.type == SplineCurve::LINE ? c0.p2 - c0.p1 : c0.p4 - c0.p3).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;
|
||||
MakeFeatures();
|
||||
}
|
||||
|
@ -454,27 +347,19 @@ void VisualToolVectorClip::UpdateHold() {
|
|||
else if (mode == 6 || mode == 7) {
|
||||
// See if distance is enough
|
||||
Vector2D const& last = spline.back().EndPoint();
|
||||
int len = (int)Vector2D(last.x-video.x, last.y-video.y).Len();
|
||||
if (mode == 6 && len < 30) return;
|
||||
if (mode == 7 && len < 60) return;
|
||||
float len = (last - mouse_pos).SquareLen();
|
||||
if (mode == 6 && len < 900) return;
|
||||
if (mode == 7 && len < 3600) return;
|
||||
|
||||
// Generate curve and add it
|
||||
SplineCurve curve;
|
||||
curve.type = CURVE_LINE;
|
||||
curve.p1 = Vector2D(last.x,last.y);
|
||||
curve.p2 = Vector2D(video.x,video.y);
|
||||
spline.push_back(curve);
|
||||
spline.push_back(SplineCurve(last, mouse_pos));
|
||||
MakeFeature(--spline.end());
|
||||
}
|
||||
}
|
||||
|
||||
void VisualToolVectorClip::CommitHold() {
|
||||
if (mode == 3 || mode == 4) return;
|
||||
|
||||
// Smooth spline
|
||||
if (!holding && mode == 7) {
|
||||
if (!holding && mode == 7)
|
||||
spline.Smooth();
|
||||
}
|
||||
|
||||
Save();
|
||||
|
||||
|
@ -486,11 +371,11 @@ void VisualToolVectorClip::CommitHold() {
|
|||
}
|
||||
|
||||
void VisualToolVectorClip::DoRefresh() {
|
||||
if (!curDiag) return;
|
||||
if (!active_line) return;
|
||||
|
||||
wxString vect;
|
||||
int scale;
|
||||
vect = GetLineVectorClip(curDiag,scale,inverse);
|
||||
vect = GetLineVectorClip(active_line, scale, inverse);
|
||||
spline.DecodeFromASS(vect);
|
||||
|
||||
MakeFeatures();
|
||||
|
@ -498,6 +383,7 @@ void VisualToolVectorClip::DoRefresh() {
|
|||
}
|
||||
|
||||
void VisualToolVectorClip::SelectAll() {
|
||||
ClearSelection();
|
||||
for_each_iter(features, this, &VisualToolVectorClip::AddSelection);
|
||||
sel_features.clear();
|
||||
for (feature_iterator it = features.begin(); it != features.end(); ++it)
|
||||
sel_features.insert(it);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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.
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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/
|
||||
//
|
||||
|
@ -43,8 +30,7 @@ class wxToolBar;
|
|||
/// @class VisualToolVectorClipDraggableFeature
|
||||
/// @brief VisualDraggableFeature with information about a feature's location
|
||||
/// in the spline
|
||||
class VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
|
||||
public:
|
||||
struct VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
|
||||
/// Which curve in the spline this feature is a point on
|
||||
Spline::iterator curve;
|
||||
/// 0-3; indicates which part of the curve this point is
|
||||
|
@ -77,17 +63,15 @@ class VisualToolVectorClip : public VisualTool<VisualToolVectorClipDraggableFeat
|
|||
|
||||
bool InitializeHold();
|
||||
void UpdateHold();
|
||||
void CommitHold();
|
||||
|
||||
void UpdateDrag(feature_iterator feature);
|
||||
void CommitDrag(feature_iterator feature);
|
||||
bool InitializeDrag(feature_iterator feature);
|
||||
|
||||
void DoRefresh();
|
||||
void Draw();
|
||||
bool Update() { return mode >= 1 && mode <= 4; }
|
||||
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
|
||||
void OnSubTool(wxCommandEvent &event);
|
||||
|
|
Loading…
Reference in a new issue