2007-07-05 06:32:46 +02:00
|
|
|
// Copyright (c) 2007, Rodrigo Braz Monteiro
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
|
|
// may be used to endorse or promote products derived from this software
|
|
|
|
// without specific prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// AEGISUB
|
|
|
|
//
|
|
|
|
// Website: http://aegisub.cellosoft.com
|
|
|
|
// Contact: mailto:zeratul@cellosoft.com
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
///////////
|
|
|
|
// Headers
|
|
|
|
#include "visual_tool_vector_clip.h"
|
|
|
|
#include "ass_dialogue.h"
|
|
|
|
|
|
|
|
|
2007-07-05 08:13:22 +02:00
|
|
|
///////
|
|
|
|
// IDs
|
|
|
|
enum {
|
|
|
|
BUTTON_DRAG = 1300,
|
|
|
|
BUTTON_LINE,
|
|
|
|
BUTTON_BICUBIC,
|
|
|
|
BUTTON_INSERT,
|
|
|
|
BUTTON_REMOVE,
|
|
|
|
BUTTON_CONVERT,
|
|
|
|
BUTTON_FREEHAND
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-07-05 06:32:46 +02:00
|
|
|
///////////////
|
|
|
|
// Constructor
|
2007-07-05 08:13:22 +02:00
|
|
|
VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent,wxSizer *toolbar,wxWindow *toolWindow)
|
2007-07-05 06:32:46 +02:00
|
|
|
: VisualTool(parent)
|
|
|
|
{
|
|
|
|
DoRefresh();
|
2007-07-05 08:13:22 +02:00
|
|
|
|
|
|
|
// Create toolbar
|
|
|
|
wxButton *drag = new wxBitmapButton(toolWindow,BUTTON_DRAG,wxBITMAP(visual_vector_clip_drag));
|
|
|
|
wxButton *line = new wxBitmapButton(toolWindow,BUTTON_LINE,wxBITMAP(visual_vector_clip_line));
|
|
|
|
wxButton *bicubic = new wxBitmapButton(toolWindow,BUTTON_BICUBIC,wxBITMAP(visual_vector_clip_bicubic));
|
|
|
|
wxButton *convert = new wxBitmapButton(toolWindow,BUTTON_CONVERT,wxBITMAP(visual_vector_clip_convert));
|
|
|
|
wxButton *insert = new wxBitmapButton(toolWindow,BUTTON_INSERT,wxBITMAP(visual_vector_clip_insert));
|
|
|
|
wxButton *remove = new wxBitmapButton(toolWindow,BUTTON_REMOVE,wxBITMAP(visual_vector_clip_remove));
|
|
|
|
wxButton *freehand = new wxBitmapButton(toolWindow,BUTTON_FREEHAND,wxBITMAP(visual_vector_clip_freehand));
|
|
|
|
drag->SetToolTip(_("Drag control points."));
|
|
|
|
line->SetToolTip(_("Appends a line."));
|
|
|
|
bicubic->SetToolTip(_("Appends a bezier bicubic curve."));
|
|
|
|
convert->SetToolTip(_("Converts a segment between line and bicubic."));
|
|
|
|
insert->SetToolTip(_("Inserts a control point."));
|
|
|
|
remove->SetToolTip(_("Removes a control point."));
|
|
|
|
freehand->SetToolTip(_("Draws a freehand shape."));
|
|
|
|
ConnectButton(drag);
|
|
|
|
ConnectButton(line);
|
|
|
|
ConnectButton(bicubic);
|
|
|
|
ConnectButton(convert);
|
|
|
|
ConnectButton(insert);
|
|
|
|
ConnectButton(remove);
|
|
|
|
ConnectButton(freehand);
|
|
|
|
toolbar->Add(drag,0,wxEXPAND);
|
|
|
|
toolbar->Add(line,0,wxEXPAND);
|
|
|
|
toolbar->Add(bicubic,0,wxEXPAND | wxRIGHT,5);
|
|
|
|
toolbar->Add(new wxStaticLine(toolWindow,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),0,wxEXPAND | wxRIGHT,5);
|
|
|
|
toolbar->Add(convert,0,wxEXPAND);
|
|
|
|
toolbar->Add(insert,0,wxEXPAND);
|
|
|
|
toolbar->Add(remove,0,wxEXPAND | wxRIGHT,5);
|
|
|
|
toolbar->Add(new wxStaticLine(toolWindow,-1,wxDefaultPosition,wxDefaultSize,wxLI_VERTICAL),0,wxEXPAND | wxRIGHT,5);
|
|
|
|
toolbar->Add(freehand,0,wxEXPAND);
|
|
|
|
toolbar->AddStretchSpacer(1);
|
|
|
|
|
2007-07-05 06:32:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////
|
|
|
|
// Update
|
|
|
|
void VisualToolVectorClip::Update() {
|
|
|
|
GetParent()->Render();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////
|
|
|
|
// Draw
|
|
|
|
void VisualToolVectorClip::Draw() {
|
|
|
|
// Get line
|
|
|
|
AssDialogue *line = GetActiveDialogueLine();
|
|
|
|
if (!line) return;
|
|
|
|
|
|
|
|
// Parse vector
|
2007-07-05 16:15:28 +02:00
|
|
|
std::vector<Vector2D> points;
|
2007-07-05 06:32:46 +02:00
|
|
|
spline.GetPointList(points);
|
|
|
|
|
|
|
|
// Draw lines
|
2007-07-05 06:56:56 +02:00
|
|
|
SetLineColour(colour[3],1.0f,2);
|
2007-07-05 06:32:46 +02:00
|
|
|
SetFillColour(colour[3],0.0f);
|
|
|
|
for (size_t i=0;i<points.size()-1;i++) {
|
|
|
|
DrawLine(points[i].x,points[i].y,points[i+1].x,points[i+1].y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw stencil mask
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
glColorMask(0,0,0,0);
|
|
|
|
glStencilFunc(GL_NEVER,1,1);
|
|
|
|
glStencilOp(GL_INVERT,GL_INVERT,GL_INVERT);
|
|
|
|
for (size_t i=1;i<points.size()-1;i++) {
|
|
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
glVertex2f(points[0].x,points[0].y);
|
|
|
|
glVertex2f(points[i].x,points[i].y);
|
|
|
|
glVertex2f(points[i+1].x,points[i+1].y);
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw "outside clip" mask
|
|
|
|
glColorMask(1,1,1,1);
|
|
|
|
glStencilFunc(GL_EQUAL, 0, 1);
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
2007-07-05 06:56:56 +02:00
|
|
|
SetLineColour(colour[3],0.0f);
|
2007-07-05 06:32:46 +02:00
|
|
|
SetFillColour(wxColour(0,0,0),0.5f);
|
|
|
|
DrawRectangle(0,0,sw,sh);
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
|
|
|
|
// Draw features
|
|
|
|
DrawAllFeatures();
|
|
|
|
|
|
|
|
// Draw lines connecting the bicubic features
|
|
|
|
SetLineColour(colour[3],0.9f,1);
|
|
|
|
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++) {
|
|
|
|
if (cur->type == CURVE_BICUBIC) {
|
2007-07-05 16:15:28 +02:00
|
|
|
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);
|
2007-07-05 06:32:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////
|
|
|
|
// Populate feature list
|
|
|
|
void VisualToolVectorClip::PopulateFeatureList() {
|
|
|
|
// Clear
|
|
|
|
features.clear();
|
|
|
|
VisualDraggableFeature feat;
|
|
|
|
|
|
|
|
// Go through each curve
|
|
|
|
bool isFirst = true;
|
|
|
|
int i = 0;
|
|
|
|
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++,i++) {
|
|
|
|
// First point
|
|
|
|
if (isFirst) {
|
|
|
|
isFirst = false;
|
2007-07-05 16:15:28 +02:00
|
|
|
feat.x = cur->p1.x;
|
|
|
|
feat.y = cur->p1.y;
|
2007-07-05 06:32:46 +02:00
|
|
|
feat.type = DRAG_SMALL_CIRCLE;
|
|
|
|
feat.value = i;
|
|
|
|
feat.value2 = 0;
|
|
|
|
features.push_back(feat);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Line
|
|
|
|
if (cur->type == CURVE_LINE) {
|
2007-07-05 16:15:28 +02:00
|
|
|
feat.x = cur->p2.x;
|
|
|
|
feat.y = cur->p2.y;
|
2007-07-05 06:32:46 +02:00
|
|
|
feat.type = DRAG_SMALL_CIRCLE;
|
|
|
|
feat.value = i;
|
|
|
|
feat.value2 = 1;
|
|
|
|
features.push_back(feat);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bicubic
|
|
|
|
if (cur->type == CURVE_BICUBIC) {
|
|
|
|
// Current size
|
|
|
|
int size = features.size();
|
|
|
|
|
|
|
|
// Control points
|
2007-07-05 16:15:28 +02:00
|
|
|
feat.x = cur->p2.x;
|
|
|
|
feat.y = cur->p2.y;
|
2007-07-05 06:32:46 +02:00
|
|
|
feat.value = i;
|
|
|
|
feat.value2 = 1;
|
|
|
|
feat.brother[0] = size-1;
|
|
|
|
feat.type = DRAG_SMALL_SQUARE;
|
|
|
|
features.push_back(feat);
|
2007-07-05 16:15:28 +02:00
|
|
|
feat.x = cur->p3.x;
|
|
|
|
feat.y = cur->p3.y;
|
2007-07-05 06:32:46 +02:00
|
|
|
feat.value2 = 2;
|
|
|
|
feat.brother[0] = size+2;
|
|
|
|
features.push_back(feat);
|
|
|
|
|
|
|
|
// End point
|
2007-07-05 16:15:28 +02:00
|
|
|
feat.x = cur->p4.x;
|
|
|
|
feat.y = cur->p4.y;
|
2007-07-05 06:32:46 +02:00
|
|
|
feat.type = DRAG_SMALL_CIRCLE;
|
|
|
|
feat.value2 = 3;
|
|
|
|
features.push_back(feat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////
|
|
|
|
// Update
|
|
|
|
void VisualToolVectorClip::UpdateDrag(VisualDraggableFeature &feature) {
|
|
|
|
spline.MovePoint(feature.value,feature.value2,wxPoint(feature.x,feature.y));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////
|
|
|
|
// Commit
|
|
|
|
void VisualToolVectorClip::CommitDrag(VisualDraggableFeature &feature) {
|
|
|
|
SetOverride(_T("\\clip"),_T("(") + spline.EncodeToASS() + _T(")"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////
|
|
|
|
// Refresh
|
|
|
|
void VisualToolVectorClip::DoRefresh() {
|
|
|
|
if (!dragging) {
|
|
|
|
// Get line
|
|
|
|
AssDialogue *line = GetActiveDialogueLine();
|
|
|
|
if (!line) return;
|
|
|
|
|
|
|
|
// Get clip vector
|
|
|
|
wxString vect;
|
|
|
|
int scale;
|
|
|
|
vect = GetLineVectorClip(line,scale);
|
|
|
|
if (vect.IsEmpty()) return;
|
|
|
|
spline.DecodeFromASS(vect);
|
|
|
|
PopulateFeatureList();
|
|
|
|
}
|
|
|
|
}
|