mirror of https://github.com/odrling/Aegisub
407 lines
12 KiB
C++
407 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2007, ai-chan
|
|
* 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 ASSDraw3 Team 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 AI-CHAN ``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 AI-CHAN 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.
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: engine.hpp
|
|
// Purpose: header file for ASSDraw drawing engine
|
|
// Author: ai-chan
|
|
// Created: 08/26/06
|
|
// Copyright: (c) ai-chan
|
|
// Licence: 3-clause BSD
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
|
|
#include "_common.hpp"
|
|
|
|
// we use these 2 standard libraries
|
|
#include <math.h>
|
|
#include <list>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
// agg support
|
|
#include "wxAGG/AGGWindow.h"
|
|
#include "agg_color_rgba.h"
|
|
#include "agg_rasterizer_scanline_aa.h"
|
|
#include "agg_scanline_p.h"
|
|
#include "agg_renderer_base.h"
|
|
#include "agg_renderer_primitives.h"
|
|
#include "agg_renderer_scanline.h"
|
|
#include "agg_path_storage.h"
|
|
#include "agg_curves.h"
|
|
#include "agg_conv_curve.h"
|
|
#include "agg_conv_contour.h"
|
|
#include "agg_conv_stroke.h"
|
|
#include "agg_conv_bcspline.h"
|
|
#include "agg_math.h"
|
|
|
|
#define DEFAULT_SCALE 10
|
|
|
|
// this header file declare the following classes
|
|
class DrawEngine;
|
|
class Point;
|
|
class PointSystem;
|
|
class DrawCmd;
|
|
|
|
typedef std::list<DrawCmd*> DrawCmdList;
|
|
typedef std::list<Point*> PointList;
|
|
typedef std::set<Point*> PointSet;
|
|
|
|
// Command type
|
|
enum CMDTYPE
|
|
{
|
|
M = 0,
|
|
N = 1,
|
|
L = 2,
|
|
B = 3,
|
|
S = 4,
|
|
P = 5,
|
|
C = 6
|
|
};
|
|
|
|
// Point type
|
|
enum POINTTYPE
|
|
{
|
|
MP, // main point
|
|
CP // control point
|
|
};
|
|
|
|
// A PointSystem is a centralized entity holding the parameters:
|
|
// scale, originx and originy, all of which are needed by Point
|
|
class PointSystem
|
|
{
|
|
public:
|
|
double scale, originx, originy;
|
|
|
|
PointSystem ( double sc = 1.0, double origx = 0.0, double origy = 0.0 )
|
|
{ Set( sc, origx, origy ); }
|
|
|
|
// set scale, originx and originy;
|
|
void Set( double sc, double origx, double origy )
|
|
{ scale = sc, originx = origx, originy = origy; }
|
|
|
|
wxRealPoint ToWxRealPoint ( double x, double y )
|
|
{ return wxRealPoint( originx + x * scale, originy + y * scale ); }
|
|
|
|
// given drawing command coordinates returns the wxPoint on the GUI
|
|
wxPoint ToWxPoint ( double x, double y )
|
|
{ return wxPoint( (int) (originx + x * scale), (int) (originy + y * scale) ); }
|
|
|
|
// given wxPoint on the GUI returns the nearest drawing command coords
|
|
void FromWxPoint ( int wxpx, int wxpy, int &x, int &y )
|
|
{
|
|
x = int( floor( ((double) wxpx - originx) / scale + 0.5 ) );
|
|
y = int( floor( ((double) wxpy - originy) / scale + 0.5 ) );
|
|
}
|
|
|
|
// given wxPoint on the GUI returns the nearest drawing command coords
|
|
void FromWxPoint ( wxPoint wxp, int &x, int &y )
|
|
{
|
|
FromWxPoint( wxp.x, wxp.y, x, y );
|
|
}
|
|
};
|
|
|
|
// The point class
|
|
// note: this actually refers to the x,y-coordinate in drawing commands,
|
|
// not the coordinate in the GUI
|
|
class Point
|
|
{
|
|
public:
|
|
POINTTYPE type;
|
|
PointSystem *pointsys;
|
|
|
|
// drawing commands that depend on this point
|
|
DrawCmd* cmd_main;
|
|
DrawCmd* cmd_next;
|
|
bool isselected;
|
|
unsigned num;
|
|
|
|
// constructor
|
|
//Point ( ) { cmd_main = NULL; cmd_next = NULL; }
|
|
|
|
// constructor
|
|
Point ( int _x, int _y, PointSystem* ps, POINTTYPE t, DrawCmd* cmd, unsigned n = 0 );
|
|
|
|
// getters
|
|
int x() { return x_; }
|
|
|
|
int y() { return y_; }
|
|
|
|
//set x and y
|
|
void setXY( int _x, int _y);
|
|
|
|
// simply returns true if px and py are the coordinate values
|
|
bool IsAt( int px, int py );
|
|
|
|
// convert this point to wxPoint using scale and originx, originy
|
|
wxPoint ToWxPoint () { return ToWxPoint(true); }
|
|
|
|
// convert this point to wxPoint using scale;
|
|
// also use originx and originy if useorigin = true
|
|
wxPoint ToWxPoint (bool useorigin);
|
|
|
|
// check if wxpoint is nearby this point
|
|
bool CheckWxPoint ( wxPoint wxpoint );
|
|
|
|
private:
|
|
int x_, y_;
|
|
|
|
};
|
|
|
|
// The base class for all draw commands
|
|
class DrawCmd
|
|
{
|
|
public:
|
|
CMDTYPE type;
|
|
|
|
// main point (almost every command has one)
|
|
// for B and S it's the last (destination) point
|
|
Point* m_point;
|
|
|
|
// other points than the main point
|
|
// subclasses must populate this list even if they define
|
|
// new variables for other points
|
|
PointList controlpoints;
|
|
|
|
// Linked list feature
|
|
DrawCmd *prev;
|
|
|
|
// Must set to true if the next command should NOT utilize this command
|
|
// for the drawing
|
|
bool dobreak;
|
|
|
|
// Set to true if invisible m_point (not drawn)
|
|
bool invisible;
|
|
|
|
// true if this DrawCmd has been initialized with Init(), false otherwise
|
|
// (initialized means that the control points have been generated)
|
|
bool initialized;
|
|
|
|
// -----------------------------------------------------------
|
|
// Constructor(s)
|
|
DrawCmd ( int x, int y, PointSystem *ps, DrawCmd *pv );
|
|
|
|
// Destructor
|
|
virtual ~DrawCmd ();
|
|
|
|
// Init the draw command (for example to generate the control points)
|
|
virtual void Init(unsigned n = 0) { initialized = true; }
|
|
|
|
virtual wxString ToString() { return wxT(""); }
|
|
|
|
};
|
|
|
|
class ASSDrawEngine: public GUI::AGGWindow
|
|
{
|
|
public:
|
|
ASSDrawEngine( wxWindow *parent, int extraflags = 0 );
|
|
|
|
// destructor
|
|
~ASSDrawEngine();
|
|
|
|
virtual void SetDrawCmdSet(wxString set) { drawcmdset = set; }
|
|
|
|
virtual void ResetEngine();
|
|
virtual void ResetEngine(bool addM);
|
|
virtual void RefreshDisplay();
|
|
|
|
void FitToViewPoint(int hmargin, int vmargin);
|
|
void SetFitToViewPointOnNextPaint(int hmargin = -1, int vmargin = -1);
|
|
|
|
PointSystem* _PointSystem() { return pointsys; }
|
|
|
|
// ASS draw commands; returns the number of parsed commands
|
|
virtual int ParseASS ( wxString str );
|
|
// generate ASS draw commands
|
|
virtual wxString GenerateASS ( );
|
|
|
|
// drawing
|
|
virtual void OnPaint(wxPaintEvent &event);
|
|
|
|
// -------------------- adding new commands ----------------------------
|
|
|
|
// create draw command of type 'type' and m_point (x, y), append to the
|
|
// list and return it
|
|
virtual DrawCmd* AppendCmd ( CMDTYPE type, int x, int y );
|
|
|
|
// append draw command
|
|
virtual DrawCmd* AppendCmd ( DrawCmd* cmd );
|
|
|
|
// create draw command of type 'type' and m_point (x, y), insert to the
|
|
// list after the _cmd and return it
|
|
virtual DrawCmd* InsertCmd ( CMDTYPE type, int x, int y, DrawCmd* _cmd );
|
|
|
|
// insert draw command cmd after _cmd
|
|
virtual void InsertCmd ( DrawCmd* cmd, DrawCmd* _cmd );
|
|
|
|
// Create new DrawCmd
|
|
DrawCmd* NewCmd ( CMDTYPE type, int x, int y );
|
|
|
|
// -------------------- read/modify commands ---------------------------
|
|
|
|
// returns the iterator for the list
|
|
virtual DrawCmdList::iterator Iterator ( );
|
|
|
|
// returns the 'end' iterator for the list
|
|
virtual DrawCmdList::iterator IteratorEnd ( );
|
|
|
|
// returns the last command in the list
|
|
virtual DrawCmd* LastCmd ();
|
|
|
|
// returns the total number of commands in the list
|
|
//virtual int CmdCount () { return cmds.size(); }
|
|
|
|
// move all points by relative amount of x, y coordinates
|
|
virtual void MovePoints ( int x, int y );
|
|
|
|
// transform all points using the calculation:
|
|
// | (m11) (m12) | x | (x - mx) | + | nx |
|
|
// | (m21) (m22) | | (y - my) | | ny |
|
|
virtual void Transform( float m11, float m12, float m21, float m22,
|
|
float mx, float my, float nx, float ny );
|
|
|
|
// returns some DrawCmd if its m_point = (x, y)
|
|
virtual DrawCmd* PointAt ( int x, int y );
|
|
|
|
// returns some DrawCmd if one of its control point = (x, y)
|
|
// also set &point to refer to that control point
|
|
virtual DrawCmd* ControlAt ( int x, int y, Point* &point );
|
|
|
|
// attempts to delete a commmand, returns true|false if successful|fail
|
|
virtual bool DeleteCommand ( DrawCmd* cmd );
|
|
|
|
agg::rgba rgba_shape;
|
|
PixelFormat::AGGType::color_type color_bg;
|
|
|
|
protected:
|
|
/// The AGG base renderer
|
|
typedef agg::renderer_base<PixelFormat::AGGType> RendererBase;
|
|
/// The AGG primitives renderer
|
|
typedef agg::renderer_primitives<RendererBase> RendererPrimitives;
|
|
/// The AGG solid renderer
|
|
typedef agg::renderer_scanline_aa_solid<RendererBase> RendererSolid;
|
|
|
|
enum DRAWCMDMODE {
|
|
NORMAL,
|
|
CTRL_LN,
|
|
HILITE
|
|
};
|
|
|
|
DrawCmdList cmds;
|
|
wxString drawcmdset;
|
|
|
|
PointSystem* pointsys;
|
|
|
|
// for FitToViewPoint feature
|
|
bool setfitviewpoint;
|
|
int fitviewpoint_vmargin, fitviewpoint_hmargin;
|
|
|
|
// AGG
|
|
agg::rasterizer_scanline_aa<> rasterizer; ///< Scanline rasterizer
|
|
agg::scanline_p8 scanline; ///< Scanline container
|
|
void render_scanlines_aa_solid(RendererBase& rbase, agg::rgba rbga, bool affectboundaries = true);
|
|
void render_scanlines(RendererSolid& rsolid, bool affectboundaries = true);
|
|
int rendered_min_x, rendered_min_y, rendered_max_x, rendered_max_y; //bounding coord of rendered shapes
|
|
void update_rendered_bound_coords(bool rendered_fresh = false);
|
|
|
|
typedef agg::conv_transform<agg::path_storage> trans_path;
|
|
agg::path_storage m_path, b_path;
|
|
trans_path *rm_path, *rb_path;
|
|
agg::conv_curve<trans_path> *rm_curve;
|
|
|
|
void draw();
|
|
virtual void ConstructPathsAndCurves(agg::trans_affine& mtx, trans_path*& _rm_path, trans_path*& _rb_path, agg::conv_curve<trans_path>*& _rm_curve);
|
|
virtual void DoDraw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx );
|
|
virtual void Draw_Clear( RendererBase& rbase );
|
|
virtual void Draw_Draw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx, agg::rgba color );
|
|
bool refresh_called;
|
|
|
|
// set stuff to connect two drawing commands cmd1 and cmd2 such that
|
|
// cmd1 comes right before cmd2
|
|
virtual void ConnectSubsequentCmds (DrawCmd* cmd1, DrawCmd* cmd2);
|
|
|
|
virtual void AddDrawCmdToAGGPathStorage(DrawCmd* cmd, agg::path_storage& path, DRAWCMDMODE mode = NORMAL);
|
|
|
|
virtual std::vector< bool > PrepareC1ContData();
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
namespace agg
|
|
{
|
|
class simple_polygon_vertex_source
|
|
{
|
|
public:
|
|
simple_polygon_vertex_source(const double* polygon, unsigned np,
|
|
bool roundoff = false,
|
|
bool close = true) :
|
|
m_polygon(polygon),
|
|
m_num_points(np),
|
|
m_vertex(0),
|
|
m_roundoff(roundoff),
|
|
m_close(close)
|
|
{
|
|
}
|
|
|
|
void close(bool f) { m_close = f; }
|
|
bool close() const { return m_close; }
|
|
|
|
void rewind(unsigned)
|
|
{
|
|
m_vertex = 0;
|
|
}
|
|
|
|
unsigned vertex(double* x, double* y)
|
|
{
|
|
if(m_vertex > m_num_points) return path_cmd_stop;
|
|
if(m_vertex == m_num_points)
|
|
{
|
|
++m_vertex;
|
|
return path_cmd_end_poly | (m_close ? path_flags_close : 0);
|
|
}
|
|
*x = m_polygon[m_vertex * 2];
|
|
*y = m_polygon[m_vertex * 2 + 1];
|
|
if(m_roundoff)
|
|
{
|
|
*x = floor(*x) + 0.5;
|
|
*y = floor(*y) + 0.5;
|
|
}
|
|
++m_vertex;
|
|
return (m_vertex == 1) ? path_cmd_move_to : path_cmd_line_to;
|
|
}
|
|
|
|
private:
|
|
const double* m_polygon;
|
|
unsigned m_num_points;
|
|
unsigned m_vertex;
|
|
bool m_roundoff;
|
|
bool m_close;
|
|
};
|
|
};
|
|
|
|
typedef agg::simple_polygon_vertex_source aggpolygon;
|