Add support for rendering vector clips with multiple 'm' commands.

Originally committed to SVN as r4463.
This commit is contained in:
Thomas Goyne 2010-06-08 06:09:19 +00:00
parent c7da8d9f61
commit f361d1a67b
8 changed files with 329 additions and 449 deletions

View File

@ -52,24 +52,6 @@
#include "options.h"
//////////////////////////
// Extension get function
#ifdef __WIN32__
/// @brief DOCME
/// @param str
/// @return
///
void* glGetProc(const char *str) { return wglGetProcAddress(str); }
#else
/// DOCME
#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
#endif
/// @brief Constructor
///
OpenGLWrapper::OpenGLWrapper() {

View File

@ -51,6 +51,19 @@ typedef GLuint GLhandleARB;
#include <wx/colour.h>
#endif
#ifdef __WIN32__
#define glGetProc(a) wglGetProcAddress(a)
#else
#define glGetProc(a) glXGetProcAddress((const GLubyte *)(a))
#endif
#define GL_EXT(type, name) \
static type name = reinterpret_cast<type>(glGetProc(#name)); \
if (!name) { \
name = & name ## Fallback; \
}
/// DOCME
/// @class OpenGLWrapper

View File

@ -40,11 +40,12 @@
#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) {
}
@ -54,23 +55,21 @@ wxString Spline::EncodeToASS() {
wxString result;
char lastCommand = 0;
// At least one element?
bool isFirst = true;
// Insert each element
for (std::list<SplineCurve>::iterator cur=curves.begin();cur!=curves.end();cur++) {
// Start of spline
if (isFirst) {
for (iterator cur=begin();cur!=end();cur++) {
// Each curve
switch (cur->type) {
case CURVE_POINT: {
if (lastCommand != 'm') {
result += L"m ";
lastCommand = 'm';
}
int x = cur->p1.x;
int y = cur->p1.y;
scale.ToScriptCoords(&x, &y);
result = wxString::Format(L"m %i %i ", x, y);
lastCommand = 'm';
isFirst = false;
result += wxString::Format(L"%i %i ", x, y);
break;
}
// Each curve
switch (cur->type) {
case CURVE_LINE: {
if (lastCommand != 'l') {
result += L"l ";
@ -109,14 +108,13 @@ wxString Spline::EncodeToASS() {
/// @param str
void Spline::DecodeFromASS(wxString str) {
// Clear current
curves.clear();
clear();
std::vector<int> stack;
// Prepare
char lastCommand = 'm';
int x = 0;
int y = 0;
bool coordsSet = false;
// Tokenize the string
wxStringTokenizer tkn(str,L" ");
@ -131,11 +129,13 @@ void Spline::DecodeFromASS(wxString str) {
// Move
if (stack.size() == 2 && lastCommand == 'm') {
x = stack[0];
y = stack[1];
scale.FromScriptCoords(&x, &y);
coordsSet = true;
scale.FromScriptCoords(&stack[0], &stack[1]);
SplineCurve curve;
x = curve.p1.x = stack[0];
y = curve.p1.y = stack[1];
curve.type = CURVE_POINT;
stack.clear();
push_back(curve);
}
// Line
@ -144,13 +144,11 @@ void Spline::DecodeFromASS(wxString str) {
SplineCurve curve;
curve.p1.x = x;
curve.p1.y = y;
curve.p2.x = stack[0];
curve.p2.y = stack[1];
x = curve.p2.x = stack[0];
y = curve.p2.y = stack[1];
curve.type = CURVE_LINE;
x = curve.p2.x;
y = curve.p2.y;
stack.clear();
AppendCurve(curve);
push_back(curve);
}
// Bicubic
@ -171,7 +169,7 @@ void Spline::DecodeFromASS(wxString str) {
x = curve.p4.x;
y = curve.p4.y;
stack.clear();
AppendCurve(curve);
push_back(curve);
}
// Close
@ -190,134 +188,69 @@ void Spline::DecodeFromASS(wxString str) {
else if (token == L"c") lastCommand = 'c';
}
}
// Got coordinates, but list is empty
if (curves.size() == 0 && coordsSet) {
SplineCurve curve;
curve.p1.x = x;
curve.p1.y = y;
curve.type = CURVE_POINT;
AppendCurve(curve);
}
}
/// @brief Insert a curve to the spline
/// @param curve
/// @param index
void Spline::InsertCurve(SplineCurve &curve,int index) {
if (index == -1) curves.push_back(curve);
else {
std::list<SplineCurve>::iterator cur;
int i=0;
for (cur=curves.begin();cur!=curves.end() && i < index;cur++,i++) ;
curves.insert(cur,curve);
}
}
/// @brief Get a specific curve
/// @param index
/// @return
SplineCurve *Spline::GetCurve(int index) {
int i=0;
for (std::list<SplineCurve>::iterator cur=curves.begin();cur!=curves.end() && i <= index;cur++,i++) {
if (i==index) return &(*cur);
}
return NULL;
}
/// @brief Moves a specific point in the spline
/// @param curveIndex
/// @param point
/// @param pos
void Spline::MovePoint(int curveIndex,int point,wxPoint pos) {
// Curves
int i = 0;
SplineCurve *c0 = NULL;
SplineCurve *c1 = NULL;
SplineCurve *c2 = NULL;
// Indices
int i0 = curveIndex-1;
int i1 = curveIndex;
int i2 = curveIndex+1;
// Get the curves
for (std::list<SplineCurve>::iterator cur = curves.begin();cur!=curves.end();cur++) {
if (i == i0) c0 = &(*cur);
if (i == i1) c1 = &(*cur);
if (i == i2) c2 = &(*cur);
i++;
}
void Spline::MovePoint(iterator curve,int point,Vector2D const& pos) {
iterator prev = curve;
if (curve != begin()) --prev;
iterator next = curve;
++next;
if (next != end() && next->type == CURVE_POINT) next = end();
// Modify
if (point == 0) {
c1->p1.x = pos.x;
c1->p1.y = pos.y;
if (c0) {
if (c0->type == CURVE_BICUBIC) {
c0->p4.x = pos.x;
c0->p4.y = pos.y;
}
else {
c0->p2.x = pos.x;
c0->p2.y = pos.y;
}
}
curve->p1 = pos;
if (curve != begin() && curve->type != CURVE_POINT) prev->EndPoint() = pos;
if (next != end() && curve->type == CURVE_POINT) next->p1 = pos;
}
else if (point == 1) {
c1->p2.x = pos.x;
c1->p2.y = pos.y;
if (c2 && c1->type != CURVE_BICUBIC) {
c2->p1.x = pos.x;
c2->p1.y = pos.y;
}
curve->p2 = pos;
if (next != end() && curve->type == CURVE_LINE) next->p1 = pos;
}
else if (point == 2) {
c1->p3.x = pos.x;
c1->p3.y = pos.y;
curve->p3 = pos;
}
else if (point == 3) {
c1->p4.x = pos.x;
c1->p4.y = pos.y;
if (c2 && c1->type == CURVE_BICUBIC) {
c2->p1.x = pos.x;
c2->p1.y = pos.y;
}
curve->p4 = pos;
if (next != end()) next->p1 = pos;
}
}
/// @brief Gets a list of points in the curve
/// @param points
/// @param pointCurve
void Spline::GetPointList(std::vector<float> &points,std::vector<int> &pointCurve) {
// Prepare
void Spline::GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count) {
points.clear();
points.reserve((curves.size() + 1) * 2);
pointCurve.reserve(curves.size() + 1);
pointCurve.clear();
Vector2D pt;
bool isFirst = true;
int curve = 0;
first.clear();
count.clear();
points.reserve((size() + 1) * 2);
int curCount = 0;
// Generate points for each curve
for (std::list<SplineCurve>::iterator cur = curves.begin();cur!=curves.end();cur++,curve++) {
// First point
if (isFirst) {
for (iterator cur = begin();cur!=end();cur++) {
switch (cur->type) {
case CURVE_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);
pointCurve.push_back(curve);
isFirst = false;
}
// Line
if (cur->type == CURVE_LINE) {
curCount = 1;
break;
case CURVE_LINE:
points.push_back(cur->p2.x);
points.push_back(cur->p2.y);
pointCurve.push_back(curve);
}
// Bicubic
else if (cur->type == CURVE_BICUBIC) {
curCount++;
break;
case CURVE_BICUBIC: {
// Get the control points
Vector2D p1 = cur->p1;
Vector2D p2 = cur->p2;
@ -335,16 +268,48 @@ void Spline::GetPointList(std::vector<float> &points,std::vector<int> &pointCurv
Vector2D p = cur->GetPoint(t);
points.push_back(p.x);
points.push_back(p.y);
pointCurve.push_back(curve);
}
curCount += steps;
break;
}
default: break;
}
}
// Insert a copy of the first point at the end
if (!points.empty()) {
points.push_back(points[0]);
points.push_back(points[1]);
pointCurve.push_back(curve);
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);
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);
}
break;
}
default: break;
}
}
@ -353,77 +318,64 @@ void Spline::GetPointList(std::vector<float> &points,std::vector<int> &pointCurv
/// @param curve
/// @param t
/// @param pt
void Spline::GetClosestParametricPoint(Vector2D reference,int &curve,float &t,Vector2D &pt) {
// Has at least one curve?
curve = -1;
t = 0.0f;
if (curves.size() == 0) return;
void Spline::GetClosestParametricPoint(Vector2D const& reference,iterator &curve,float &t,Vector2D &pt) {
curve = end();
t = 0.f;
if (empty()) return;
// Close the shape
SplineCurve pad;
pad.p1 = curves.back().GetEndPoint();
pad.p2 = curves.front().p1;
pad.p1 = back().EndPoint();
pad.p2 = front().p1;
pad.type = CURVE_LINE;
curves.push_back(pad);
push_back(pad);
// Prepare
float closest = 8000000.0f;
int i = 0;
for (std::list<SplineCurve>::iterator cur = curves.begin();cur!=curves.end();cur++,i++) {
float closest = std::numeric_limits<float>::infinity();
for (iterator cur = begin();cur!=end();cur++) {
float param = cur->GetClosestParam(reference);
Vector2D p1 = cur->GetPoint(param);
float dist = (p1-reference).Len();
float dist = (p1-reference).SquareLen();
if (dist < closest) {
closest = dist;
t = param;
curve = i;
curve = cur;
pt = p1;
}
}
if (&*curve == &back()) {
curve = end();
}
// Remove closing and return
curves.pop_back();
pop_back();
}
/// @brief Point closest to reference
/// @param reference
/// @return
Vector2D Spline::GetClosestPoint(Vector2D reference) {
int curve;
Vector2D Spline::GetClosestPoint(Vector2D const& reference) {
iterator curve;
float t;
Vector2D point;
GetClosestParametricPoint(reference,curve,t,point);
return point;
}
/// @brief Control point closest to reference
/// @param reference
/// @return
///
Vector2D Spline::GetClosestControlPoint(Vector2D reference) {
// TODO
return Vector2D(-1,-1);
}
/// @brief Smoothes the spline
/// @param smooth
void Spline::Smooth(float smooth) {
// See if there are enough curves
if (curves.size() < 3) return;
if (size() < 3) return;
// Smooth curve
SplineCurve *curve0 = NULL;
SplineCurve *curve1 = &curves.back();
SplineCurve *curve2 = NULL;
for (std::list<SplineCurve>::iterator cur=curves.begin();cur!=curves.end();) {
// Get curves
curve0 = curve1;
curve1 = &(*cur);
iterator curve1 = end();
--curve1;
for (iterator cur = begin(); cur != end();) {
iterator curve0 = curve1;
curve1 = cur;
cur++;
if (cur == curves.end()) curve2 = &curves.front();
else curve2 = &(*cur);
iterator curve2 = cur == end() ? begin() : cur;
// Smooth curve
curve1->Smooth(curve0->p1,curve2->p2,smooth);

View File

@ -45,36 +45,53 @@
class VideoDisplay;
/// DOCME
/// @class Spline
/// @brief DOCME
class Spline {
class Spline : private std::list<SplineCurve> {
private:
const VideoDisplay &scale;
public:
/// DOCME
std::list<SplineCurve> curves;
Spline(const VideoDisplay &scale);
wxString EncodeToASS();
void DecodeFromASS(wxString str);
/// @brief DOCME
/// @param curve
///
void AppendCurve(SplineCurve &curve) { InsertCurve(curve,-1); }
void InsertCurve(SplineCurve &curve,int index);
void MovePoint(int curveIndex,int point,wxPoint pos);
void MovePoint(iterator curve,int point,Vector2D const& pos);
void Smooth(float smooth=1.0f);
void GetPointList(std::vector<float> &points,std::vector<int> &pointCurve);
SplineCurve *GetCurve(int index);
void GetPointList(std::vector<float>& points, std::vector<int>& first, std::vector<int>& count);
void GetPointList(std::vector<float> &points, iterator curve);
void GetClosestParametricPoint(Vector2D reference,int &curve,float &t,Vector2D &point);
Vector2D GetClosestPoint(Vector2D reference);
Vector2D GetClosestControlPoint(Vector2D reference);
void GetClosestParametricPoint(Vector2D const& reference, iterator& curve, float &t, Vector2D &point);
Vector2D GetClosestPoint(Vector2D const& reference);
Vector2D GetClosestControlPoint(Vector2D const& reference);
// This list intentionally excludes things specific to std::list
using std::list<SplineCurve>::value_type;
using std::list<SplineCurve>::pointer;
using std::list<SplineCurve>::reference;
using std::list<SplineCurve>::const_reference;
using std::list<SplineCurve>::size_type;
using std::list<SplineCurve>::difference_type;
using std::list<SplineCurve>::iterator;
using std::list<SplineCurve>::const_iterator;
using std::list<SplineCurve>::reverse_iterator;
using std::list<SplineCurve>::const_reverse_iterator;
using std::list<SplineCurve>::begin;
using std::list<SplineCurve>::end;
using std::list<SplineCurve>::rbegin;
using std::list<SplineCurve>::rend;
using std::list<SplineCurve>::size;
using std::list<SplineCurve>::empty;
using std::list<SplineCurve>::front;
using std::list<SplineCurve>::back;
using std::list<SplineCurve>::push_front;
using std::list<SplineCurve>::push_back;
using std::list<SplineCurve>::pop_front;
using std::list<SplineCurve>::pop_back;
using std::list<SplineCurve>::insert;
using std::list<SplineCurve>::erase;
using std::list<SplineCurve>::clear;
};

View File

@ -34,7 +34,6 @@
/// @ingroup visual_ts
///
///////////
// Headers
#include "config.h"
@ -42,15 +41,12 @@
#include "spline_curve.h"
#include "utils.h"
/// @brief Curve constructor
///
SplineCurve::SplineCurve() {
type = CURVE_INVALID;
}
/// @brief Split a curve in two using the de Casteljau algorithm
/// @param c1
/// @param c2
@ -93,28 +89,26 @@ void SplineCurve::Split(SplineCurve &c1,SplineCurve &c2,float t) {
}
}
/// @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 P0,Vector2D P3,float smooth) {
void SplineCurve::Smooth(Vector2D const& P0,Vector2D const& P3,float smooth) {
// Validate
if (type != CURVE_LINE) return;
if (p1 == p2) return;
smooth = MID(0.0f,smooth,1.0f);
smooth = MID(0.f,smooth,1.f);
// Get points
Vector2D P1 = p1;
Vector2D P2 = p2;
// Calculate intermediate points
Vector2D c1 = (P0+P1)/2.0f;
Vector2D c2 = (P1+P2)/2.0f;
Vector2D c3 = (P2+P3)/2.0f;
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();
@ -130,43 +124,24 @@ void SplineCurve::Smooth(Vector2D P0,Vector2D P3,float smooth) {
type = CURVE_BICUBIC;
}
/// @brief Get a point
/// @param t
/// @return
///
Vector2D SplineCurve::GetPoint(float t) const {
// Point
if (type == CURVE_POINT) return p1;
// Line
else if (type == CURVE_LINE) {
return p1*(1.0f-t) + p2*t;
if (type == CURVE_LINE) {
return p1*(1.f-t) + p2*t;
}
// Bicubic
else if (type == CURVE_BICUBIC) {
float u = 1.0f-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;
}
else return Vector2D(0,0);
return Vector2D(0,0);
}
/// @brief Get start/end point
/// @return
///
Vector2D SplineCurve::GetStartPoint() const {
return p1;
}
/// @brief DOCME
/// @return
///
Vector2D SplineCurve::GetEndPoint() const {
Vector2D& SplineCurve::EndPoint() {
switch (type) {
case CURVE_POINT: return p1;
case CURVE_LINE: return p2;
@ -175,33 +150,26 @@ Vector2D SplineCurve::GetEndPoint() const {
}
}
/// @brief Get point closest to reference
/// @param ref
/// @return
///
Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const {
Vector2D SplineCurve::GetClosestPoint(Vector2D const& ref) const {
return GetPoint(GetClosestParam(ref));
}
/// @brief Get value of parameter closest to point
/// @param ref
/// @return
///
float SplineCurve::GetClosestParam(Vector2D ref) const {
// Line
float SplineCurve::GetClosestParam(Vector2D const& ref) const {
if (type == CURVE_LINE) {
return GetClosestSegmentPart(p1,p2,ref);
}
// Bicubic
if (type == CURVE_BICUBIC) {
int steps = 100;
float bestDist = 80000000.0f;
float bestT = 0.0f;
float bestDist = 80000000.f;
float bestT = 0.f;
for (int i=0;i<=steps;i++) {
float t = float(i)/float(steps);
float dist = (GetPoint(t)-ref).Len();
@ -212,19 +180,15 @@ float SplineCurve::GetClosestParam(Vector2D ref) const {
}
return bestT;
}
// Something else
return 0.0f;
return 0.f;
}
/// @brief Quick distance
/// @param ref
/// @return
///
float SplineCurve::GetQuickDistance(Vector2D ref) const {
// Bicubic
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);
@ -232,35 +196,29 @@ float SplineCurve::GetQuickDistance(Vector2D ref) const {
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));
return min(min(min(len1,len2),min(len3,len4)),min(len5,len6));
}
// Something else
else 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 pt1,Vector2D pt2,Vector2D pt3) const {
return MID(0.0f,(pt3-pt1).Dot(pt2-pt1)/(pt2-pt1).SquareLen(),1.0f);
float SplineCurve::GetClosestSegmentPart(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
return MID(0.f,(pt3-pt1).Dot(pt2-pt1)/(pt2-pt1).SquareLen(),1.f);
}
/// @brief Closest distance between p3 and segment p1-p2
/// @param pt1
/// @param pt2
/// @param pt3
///
float SplineCurve::GetClosestSegmentDistance(Vector2D pt1,Vector2D pt2,Vector2D pt3) const {
float SplineCurve::GetClosestSegmentDistance(Vector2D const& pt1,Vector2D const& pt2,Vector2D const& pt3) const {
float t = GetClosestSegmentPart(pt1,pt2,pt3);
return (pt1*(1.0f-t)+pt2*t-pt3).Len();
return (pt1*(1.f-t)+pt2*t-pt3).Len();
}

View File

@ -34,14 +34,10 @@
/// @ingroup visual_ts
///
///////////
// Headers
#include "vector2d.h"
/// DOCME
enum CurveType {
@ -58,8 +54,6 @@ enum CurveType {
CURVE_BICUBIC
};
/// DOCME
/// @class SplineCurve
/// @brief DOCME
@ -67,8 +61,8 @@ enum CurveType {
/// DOCME
class SplineCurve {
private:
float GetClosestSegmentPart(Vector2D p1,Vector2D p2,Vector2D p3) const;
float GetClosestSegmentDistance(Vector2D p1,Vector2D p2,Vector2D p3) const;
float GetClosestSegmentPart(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
float GetClosestSegmentDistance(Vector2D const& p1,Vector2D const& p2,Vector2D const& p3) const;
public:
@ -86,14 +80,11 @@ public:
SplineCurve();
void Split(SplineCurve &c1,SplineCurve &c2,float t=0.5);
void Smooth(Vector2D prev,Vector2D next,float smooth=1.0f);
void Smooth(Vector2D const& prev,Vector2D const& next,float smooth=1.0f);
Vector2D GetPoint(float t) const;
Vector2D GetStartPoint() const;
Vector2D GetEndPoint() const;
Vector2D GetClosestPoint(Vector2D ref) const;
float GetClosestParam(Vector2D ref) const;
float GetQuickDistance(Vector2D ref) const;
Vector2D& EndPoint();
Vector2D GetClosestPoint(Vector2D const& ref) const;
float GetClosestParam(Vector2D const& ref) const;
float GetQuickDistance(Vector2D const& ref) const;
};

View File

@ -35,6 +35,7 @@
#ifndef AGI_PRE
#include <wx/toolbar.h>
#include "gl/glext.h"
#endif
#include "config.h"
@ -44,35 +45,15 @@
#include "video_display.h"
#include "visual_tool_vector_clip.h"
///////
// IDs
enum {
/// DOCME
BUTTON_DRAG = VISUAL_SUB_TOOL_START,
/// DOCME
BUTTON_LINE,
/// DOCME
BUTTON_BICUBIC,
/// DOCME
BUTTON_CONVERT,
/// DOCME
BUTTON_INSERT,
/// DOCME
BUTTON_REMOVE,
/// DOCME
BUTTON_FREEHAND,
/// DOCME
BUTTON_FREEHAND_SMOOTH,
/// DOCME
BUTTON_LAST // Leave this at the end and don't use it
};
@ -107,25 +88,30 @@ VisualToolVectorClip::VisualToolVectorClip(VideoDisplay *parent, VideoState cons
if (features.size() == 0) SetMode(1);
}
/// @brief Sub-tool pressed
/// @param event
void VisualToolVectorClip::OnSubTool(wxCommandEvent &event) {
SetMode(event.GetId() - BUTTON_DRAG);
}
/// @brief Set mode
/// @param _mode
void VisualToolVectorClip::SetMode(int _mode) {
// Make sure clicked is checked and everything else isn't. (Yes, this is radio behavior, but the separators won't let me use it)
void VisualToolVectorClip::SetMode(int newMode) {
// 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 == _mode + BUTTON_DRAG);
toolBar->ToggleTool(i,i == newMode + BUTTON_DRAG);
}
mode = newMode;
}
// Substitute for glMultiDrawArrays for sub-1.4 OpenGL
static void APIENTRY glMultiDrawArraysFallback(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
for (int i = 0; i < primcount; ++i) {
glDrawArrays(mode, *first++, *count++);
}
mode = _mode;
}
/// @brief Draw
void VisualToolVectorClip::Draw() {
if (spline.curves.empty()) return;
if (spline.empty()) return;
GL_EXT(PFNGLMULTIDRAWARRAYSPROC, glMultiDrawArrays);
// Get line
AssDialogue *line = GetActiveDialogueLine();
@ -133,8 +119,12 @@ void VisualToolVectorClip::Draw() {
// Parse vector
std::vector<float> points;
std::vector<int> pointCurve;
spline.GetPointList(points,pointCurve);
std::vector<int> start;
std::vector<int> count;
spline.GetPointList(points, start, count);
assert(!start.empty());
assert(!count.empty());
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, &points[0]);
@ -156,12 +146,12 @@ void VisualToolVectorClip::Draw() {
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDrawArrays(GL_TRIANGLE_FAN, 0, points.size() / 2);
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);
glDrawArrays(GL_TRIANGLE_FAN, 0, points.size() / 2);
glMultiDrawArrays(GL_TRIANGLE_FAN, &start[0], &count[0], start.size());
glDisable(GL_CULL_FACE);
// Draw the actual rectangle
@ -176,29 +166,26 @@ void VisualToolVectorClip::Draw() {
DrawRectangle(0,0,video.w,video.h);
glDisable(GL_STENCIL_TEST);
// Get current position information for modes 3 and 4
Vector2D pt;
int highCurve = -1;
if (mode == 3 || mode == 4) {
float t;
spline.GetClosestParametricPoint(Vector2D(video.x,video.y),highCurve,t,pt);
}
// Draw lines
SetFillColour(colour[3],0.0f);
SetLineColour(colour[3],1.0f,2);
SetModeLine();
glDrawArrays(GL_LINE_STRIP, 0, points.size() / 2);
glMultiDrawArrays(GL_LINE_LOOP, &start[0], &count[0], start.size());
Vector2D pt;
float t;
Spline::iterator highCurve;
spline.GetClosestParametricPoint(Vector2D(video.x, video.y), highCurve, t, pt);
// Draw highlighted line
if (!curFeature && points.size() > 1 && highCurve > -1) {
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> high = std::equal_range(pointCurve.begin(), pointCurve.end(), highCurve);
if (high.first != high.second) {
if ((mode == 3 || mode == 4) && !curFeature && 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);
int first = std::distance(pointCurve.begin(), high.first);
int count = std::distance(high.first, high.second);
if (first > 0) first -= 1;
glDrawArrays(GL_LINE_STRIP, first, count);
SetModeLine();
glDrawArrays(GL_LINE_STRIP, 0, highPoints.size() / 2);
}
}
@ -206,23 +193,22 @@ void VisualToolVectorClip::Draw() {
// 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++) {
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);
}
}
// Draw features
DrawAllFeatures();
// Draw preview of inserted line
if (mode == 1 || mode == 2) {
if (spline.curves.size() && video.x > INT_MIN && video.y > INT_MIN) {
SplineCurve *c0 = &spline.curves.front();
SplineCurve *c1 = &spline.curves.back();
if (spline.size() && video.x > INT_MIN && video.y > INT_MIN) {
SplineCurve *c0 = &spline.front();
SplineCurve *c1 = &spline.back();
DrawDashedLine(video.x,video.y,c0->p1.x,c0->p1.y,6);
DrawDashedLine(video.x,video.y,c1->GetEndPoint().x,c1->GetEndPoint().y,6);
DrawDashedLine(video.x,video.y,c1->EndPoint().x,c1->EndPoint().y,6);
}
}
@ -235,31 +221,28 @@ void VisualToolVectorClip::PopulateFeatureList() {
ClearSelection(false);
features.clear();
// This is perhaps a bit conservative as there can be up to 3N+1 features
features.reserve(spline.curves.size());
features.reserve(spline.size());
VisualToolVectorClipDraggableFeature feat;
// Go through each curve
bool isFirst = true;
int i = 0;
int j = 0;
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();cur++,i++) {
// First point
if (isFirst) {
isFirst = false;
for (Spline::iterator cur=spline.begin();cur!=spline.end();cur++,i++) {
if (cur->type == CURVE_POINT) {
feat.x = (int)cur->p1.x;
feat.y = (int)cur->p1.y;
feat.type = DRAG_SMALL_CIRCLE;
feat.index = i;
feat.curve = cur;
feat.point = 0;
features.push_back(feat);
AddSelection(j++);
}
if (cur->type == CURVE_LINE) {
else if (cur->type == CURVE_LINE) {
feat.x = (int)cur->p2.x;
feat.y = (int)cur->p2.y;
feat.type = DRAG_SMALL_CIRCLE;
feat.index = i;
feat.curve = cur;
feat.point = 1;
features.push_back(feat);
AddSelection(j++);
@ -269,7 +252,7 @@ void VisualToolVectorClip::PopulateFeatureList() {
// Control points
feat.x = (int)cur->p2.x;
feat.y = (int)cur->p2.y;
feat.index = i;
feat.curve = cur;
feat.point = 1;
feat.type = DRAG_SMALL_SQUARE;
features.push_back(feat);
@ -295,7 +278,7 @@ void VisualToolVectorClip::PopulateFeatureList() {
/// @brief Update
/// @param feature
void VisualToolVectorClip::UpdateDrag(VisualToolVectorClipDraggableFeature* feature) {
spline.MovePoint(feature->index,feature->point,wxPoint(feature->x,feature->y));
spline.MovePoint(feature->curve,feature->point,Vector2D(feature->x,feature->y));
}
/// @brief Commit
@ -310,26 +293,27 @@ void VisualToolVectorClip::CommitDrag(VisualToolVectorClipDraggableFeature* feat
bool VisualToolVectorClip::InitializeDrag(VisualToolVectorClipDraggableFeature* feature) {
// Delete a control point
if (mode == 5) {
int i = 0;
for (std::list<SplineCurve>::iterator cur=spline.curves.begin();cur!=spline.curves.end();i++,cur++) {
if (i == feature->index) {
// Update next
if (i != 0 || feature->point != 0) {
std::list<SplineCurve>::iterator next = cur;
Spline::iterator next = feature->curve;
next++;
if (next != spline.curves.end()) next->p1 = cur->p1;
if (next != spline.end()) {
if (feature->curve->type == CURVE_POINT) {
next->p1 = next->EndPoint();
next->type = CURVE_POINT;
}
else {
next->p1 = feature->curve->p1;
}
}
// Erase and save changes
spline.curves.erase(cur);
spline.erase(feature->curve);
CommitDrag(feature);
PopulateFeatureList();
curFeature = NULL;
Commit(true);
return false;
}
}
}
return true;
}
@ -341,13 +325,10 @@ bool VisualToolVectorClip::InitializeHold() {
SplineCurve curve;
// Set start position
if (spline.curves.size()) {
curve.p1 = spline.curves.back().GetEndPoint();
if (!spline.empty()) {
curve.p1 = spline.back().EndPoint();
if (mode == 1) curve.type = CURVE_LINE;
else curve.type = CURVE_BICUBIC;
// Remove point if that's all there is
if (spline.curves.size()==1 && spline.curves.front().type == CURVE_POINT) spline.curves.clear();
}
// First point
@ -357,7 +338,7 @@ bool VisualToolVectorClip::InitializeHold() {
}
// Insert
spline.AppendCurve(curve);
spline.push_back(curve);
UpdateHold();
return true;
}
@ -366,26 +347,23 @@ bool VisualToolVectorClip::InitializeHold() {
if (mode == 3 || mode == 4) {
// Get closest point
Vector2D pt;
int curve;
Spline::iterator curve;
float t;
spline.GetClosestParametricPoint(Vector2D(video.x,video.y),curve,t,pt);
// Convert
if (mode == 3) {
SplineCurve *c1 = spline.GetCurve(curve);
if (!c1) {
}
else {
if (c1->type == CURVE_LINE) {
c1->type = CURVE_BICUBIC;
c1->p4 = c1->p2;
c1->p2 = c1->p1 * 0.75 + c1->p4 * 0.25;
c1->p3 = c1->p1 * 0.25 + c1->p4 * 0.75;
if (curve != spline.end()) {
if (curve->type == CURVE_LINE) {
curve->type = CURVE_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 (c1->type == CURVE_BICUBIC) {
c1->type = CURVE_LINE;
c1->p2 = c1->p4;
else if (curve->type == CURVE_BICUBIC) {
curve->type = CURVE_LINE;
curve->p2 = curve->p4;
}
}
}
@ -393,28 +371,28 @@ bool VisualToolVectorClip::InitializeHold() {
// Insert
else {
// Check if there is at least one curve to split
if (spline.curves.size() == 0) return false;
if (spline.empty()) return false;
// Split the curve
SplineCurve *c1 = spline.GetCurve(curve);
SplineCurve c2;
if (!c1) {
if (curve == spline.end()) {
SplineCurve ct;
ct.type = CURVE_LINE;
ct.p1 = spline.curves.back().GetEndPoint();
ct.p2 = spline.curves.front().p1;
ct.p1 = spline.back().EndPoint();
ct.p2 = spline.front().p1;
ct.p2 = ct.p1*(1-t) + ct.p2*t;
spline.AppendCurve(ct);
spline.push_back(ct);
}
else {
c1->Split(*c1,c2,t);
spline.InsertCurve(c2,curve+1);
SplineCurve c2;
curve->Split(*curve,c2,t);
spline.insert(++curve, c2);
}
}
// Commit
SetOverride(GetActiveDialogueLine(), inverse ? L"\\iclip" : L"\\clip", L"(" + spline.EncodeToASS() + L")");
Commit(true);
DoRefresh();
return false;
}
@ -422,30 +400,32 @@ bool VisualToolVectorClip::InitializeHold() {
if (mode == 6 || mode == 7) {
ClearSelection(false);
features.clear();
spline.curves.clear();
lastX = INT_MIN;
lastY = INT_MIN;
spline.clear();
SplineCurve curve;
curve.type = CURVE_POINT;
curve.p1.x = video.x;
curve.p1.y = video.y;
spline.push_back(curve);
return true;
}
return false;
}
/// @brief Update hold
/// @return
void VisualToolVectorClip::UpdateHold() {
// Insert line
if (mode == 1) {
spline.curves.back().p2 = Vector2D(video.x,video.y);
spline.back().p2 = Vector2D(video.x,video.y);
}
// Insert bicubic
if (mode == 2) {
SplineCurve &curve = spline.curves.back();
SplineCurve &curve = spline.back();
curve.p4 = Vector2D(video.x,video.y);
// Control points
if (spline.curves.size() > 1) {
std::list<SplineCurve>::reverse_iterator iter = spline.curves.rbegin();
if (spline.size() > 1) {
std::list<SplineCurve>::reverse_iterator iter = spline.rbegin();
iter++;
SplineCurve &c0 = *iter;
Vector2D prevVector;
@ -460,22 +440,18 @@ void VisualToolVectorClip::UpdateHold() {
// Freehand
if (mode == 6 || mode == 7) {
if (lastX != INT_MIN && lastY != INT_MIN) {
// See if distance is enough
Vector2D delta(lastX-video.x,lastY-video.y);
int len = (int)delta.Len();
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;
// Generate curve and add it
SplineCurve curve;
curve.type = CURVE_LINE;
curve.p1 = Vector2D(lastX,lastY);
curve.p1 = Vector2D(last.x,last.y);
curve.p2 = Vector2D(video.x,video.y);
spline.AppendCurve(curve);
}
lastX = video.x;
lastY = video.y;
spline.push_back(curve);
}
}
@ -510,4 +486,3 @@ void VisualToolVectorClip::DoRefresh() {
PopulateFeatureList();
}
}

View File

@ -46,13 +46,12 @@ class wxToolBar;
class VisualToolVectorClipDraggableFeature : public VisualDraggableFeature {
public:
/// Which curve in the spline this feature is a point on
int index;
Spline::iterator curve;
/// 0-3; indicates which part of the curve this point is
int point;
/// @brief Constructor
VisualToolVectorClipDraggableFeature()
: VisualDraggableFeature()
, index(0)
, point(0)
{ }
};
@ -62,24 +61,18 @@ public:
/// @brief DOCME
class VisualToolVectorClip : public VisualTool<VisualToolVectorClipDraggableFeature> {
private:
Spline spline; /// The current spline
/// DOCME
Spline spline;
/// DOCME
wxToolBar *toolBar;
wxToolBar *toolBar; /// The subtoolbar
/// DOCME
int mode;
/// DOCME
/// DOCME
int lastX,lastY;
/// DOCME
bool inverse;
/// @brief Set the mode
/// @param mode 0-7
void SetMode(int mode);
@ -90,7 +83,6 @@ private:
void UpdateHold();
void CommitHold();
void PopulateFeatureList();
void UpdateDrag(VisualToolVectorClipDraggableFeature* feature);
void CommitDrag(VisualToolVectorClipDraggableFeature* feature);