mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Implemented rotation and reflection
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@536 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -78,14 +78,17 @@ menu:
|
||||
store symbol: S&tore Ctrl+Enter
|
||||
close symbol editor:Close Alt+F4
|
||||
|
||||
duplicate: Duplicate Ctrl+D
|
||||
duplicate: &Duplicate Ctrl+D
|
||||
group: &Group Ctrl+G
|
||||
ungroup: &Ungroup Ctrl+U
|
||||
|
||||
tool: &Tool
|
||||
select: &Select F5
|
||||
rotate: &Rotate F6
|
||||
points: &Points F7
|
||||
basic shapes: &Basic Shapes F8
|
||||
paint: P&aint F9
|
||||
symmetry: S&ymmetry F9
|
||||
paint: P&aint F10
|
||||
|
||||
############################################################## Menu help texts
|
||||
help:
|
||||
@@ -179,6 +182,8 @@ help:
|
||||
close symbol editor:Closes the symbol editor
|
||||
|
||||
duplicate: Duplicates the selected shapes
|
||||
group: Group the selected shapes together
|
||||
ungroup: Break up the selected group
|
||||
|
||||
grid: Show gridlines
|
||||
snap: Snap shapes and points to gridlines
|
||||
@@ -188,6 +193,7 @@ help:
|
||||
rotate: Rotate and shear shapes
|
||||
points: Edit control points for a shape in the symbol
|
||||
basic shapes: Draw basic shapes, such as rectangles and circles
|
||||
symmetry: Add symmetries to the symbol
|
||||
paint: Paint on the shape using a paintbrush
|
||||
|
||||
select editor:
|
||||
@@ -247,6 +253,7 @@ tool:
|
||||
rotate: Rotate
|
||||
points: Points
|
||||
basic shapes: Basic Shapes
|
||||
symmetry: Symmetry
|
||||
paint: Paint
|
||||
|
||||
merge: Merge
|
||||
@@ -261,6 +268,9 @@ tool:
|
||||
polygon: Polygon
|
||||
star: Star
|
||||
|
||||
rotation: Rotation
|
||||
reflection: Reflection
|
||||
|
||||
line segment: Line
|
||||
curve segment: Curve
|
||||
free point: Free
|
||||
@@ -314,7 +324,8 @@ tooltip:
|
||||
rotate: Rotate (F6)
|
||||
points: Points (F7)
|
||||
basic shapes: Basic Shapes (F8)
|
||||
paint: Paint on Shape (F9)
|
||||
symmetry: Symmetry (F9)
|
||||
paint: Paint on Shape (F10)
|
||||
|
||||
merge: Merge with shapes below
|
||||
subtract: Subtract from shapes below
|
||||
@@ -328,6 +339,9 @@ tooltip:
|
||||
polygon: Polygon
|
||||
star: Star
|
||||
|
||||
rotation: Rotational symmetry (wheel)
|
||||
reflection: Reflectional symmetry (mirror)
|
||||
|
||||
line segment: To straigt line
|
||||
curve segment: To curve
|
||||
free point: Unlock point
|
||||
@@ -513,6 +527,8 @@ action:
|
||||
reorder parts: Reorder
|
||||
change combine mode:Change combine mode
|
||||
change shape name: Change shape name
|
||||
group parts: Group
|
||||
ungroup parts: Ungroup
|
||||
|
||||
# Symbol Part Actions
|
||||
convert to line: Convert to line
|
||||
@@ -608,6 +624,10 @@ type:
|
||||
polygon: polygon
|
||||
star: star
|
||||
|
||||
rotation: rotation
|
||||
reflection: reflection
|
||||
group: group
|
||||
|
||||
point: point
|
||||
points: points
|
||||
handle: handle
|
||||
|
||||
@@ -62,13 +62,12 @@ void SymbolPartMoveAction::movePart(SymbolPart& part) {
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center -= moved;
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,13 +107,12 @@ void SymbolPartMatrixAction::transform(SymbolPart& part, const Matrix2D& m) {
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center = (s->center - center) * m + center;
|
||||
s->handle = s->handle * m;
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transform(*p, m);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,13 +282,12 @@ void SymbolPartScaleAction::transformPart(SymbolPart& part) {
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
transform(s->center);
|
||||
s->handle.mul(new_size.div(old_size));
|
||||
} else if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
g->calculateBoundsNonRec();
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -59,7 +59,7 @@ void deCasteljau(const Vector2D& a1, Vector2D& a21, Vector2D& a34, const Vector2
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing
|
||||
|
||||
void curve_subdivide(const BezierCurve& c, const Vector2D& p0, const Vector2D& p1, double t0, double t1, const Rotation& rot, vector<wxPoint>& out, UInt level) {
|
||||
void curve_subdivide(const BezierCurve& c, const Vector2D& p0, const Vector2D& p1, double t0, double t1, const Vector2D& origin, const Matrix2D& m, vector<wxPoint>& out, UInt level) {
|
||||
if (level <= 0) return;
|
||||
double midtime = (t0+t1) * 0.5f;
|
||||
Vector2D midpoint = c.pointAt(midtime);
|
||||
@@ -70,23 +70,23 @@ void curve_subdivide(const BezierCurve& c, const Vector2D& p0, const Vector2D& p
|
||||
double treshold = fabs( atan2(d0.x,d0.y) - atan2(d1.x,d1.y)) * (p0-p1).lengthSqr();
|
||||
bool subdivide = treshold >= .0001;
|
||||
// subdivide left
|
||||
curve_subdivide(c, p0, midpoint, t0, midtime, rot, out, level - 1);
|
||||
curve_subdivide(c, p0, midpoint, t0, midtime, origin, m, out, level - 1);
|
||||
// add midpoint
|
||||
if (subdivide) {
|
||||
out.push_back(rot.tr(midpoint));
|
||||
out.push_back(origin + midpoint * m);
|
||||
}
|
||||
// subdivide right
|
||||
curve_subdivide(c, midpoint, p1, midtime, t1, rot, out, level - 1);
|
||||
curve_subdivide(c, midpoint, p1, midtime, t1, origin, m, out, level - 1);
|
||||
}
|
||||
|
||||
void segment_subdivide(const ControlPoint& p0, const ControlPoint& p1, const Rotation& rot, vector<wxPoint>& out) {
|
||||
void segment_subdivide(const ControlPoint& p0, const ControlPoint& p1, const Vector2D& origin, const Matrix2D& m, vector<wxPoint>& out) {
|
||||
assert(p0.segment_after == p1.segment_before);
|
||||
// always the start
|
||||
out.push_back(rot.tr(p0.pos));
|
||||
out.push_back(origin + p0.pos * m);
|
||||
if (p0.segment_after == SEGMENT_CURVE) {
|
||||
// need more points?
|
||||
BezierCurve curve(p0,p1);
|
||||
curve_subdivide(curve, p0.pos, p1.pos, 0, 1, rot, out, 5);
|
||||
curve_subdivide(curve, p0.pos, p1.pos, 0, 1, origin, m, out, 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/rotation.hpp>
|
||||
#include <util/vector2d.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Evaluation
|
||||
@@ -65,9 +65,9 @@ void deCasteljau(const Vector2D& a1, Vector2D& a21, Vector2D& a34, const Vector2
|
||||
|
||||
/// Devide a segment into a number of straight lines for display purposes
|
||||
/** Adds the resulting corner points of those lines to out, the last point is not added.
|
||||
* All points are converted to display coordinates using rot.tr
|
||||
* All points are converted to display coordinates by multiplying with m and adding origin
|
||||
*/
|
||||
void segment_subdivide(const ControlPoint& p0, const ControlPoint& p1, const Rotation& rot, vector<wxPoint>& out);
|
||||
void segment_subdivide(const ControlPoint& p0, const ControlPoint& p1, const Vector2D& origin, const Matrix2D& m, vector<wxPoint>& out);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Bounds
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ void SymbolControl::onChar(wxKeyEvent& ev) {
|
||||
|
||||
void SymbolControl::onSize(wxSizeEvent& ev) {
|
||||
wxSize s = GetClientSize();
|
||||
rotation.setZoom(min(s.GetWidth(), s.GetHeight()));
|
||||
setZoom(min(s.GetWidth(), s.GetHeight()));
|
||||
Refresh(false);
|
||||
}
|
||||
void SymbolControl::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
@@ -248,6 +248,9 @@ void SymbolControl::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
// can only edit points when a shape is available
|
||||
ev.Enable(selected_parts.getAShape());
|
||||
}
|
||||
if (ev.GetId() == ID_MODE_SYMMETRY) {
|
||||
ev.Enable(!selected_parts.empty());
|
||||
}
|
||||
break;
|
||||
case ID_MODE_PAINT:
|
||||
ev.Enable(false); // TODO
|
||||
|
||||
@@ -24,10 +24,11 @@ void SymbolPartsSelection::clear() {
|
||||
}
|
||||
|
||||
bool SymbolPartsSelection::select(const SymbolPartP& part, SelectMode mode) {
|
||||
assert(part);
|
||||
// make sure part is not the decendent of a part that is already selected
|
||||
if (mode != SELECT_OVERRIDE) {
|
||||
FOR_EACH(s, selection) {
|
||||
if (isAncestor(s.get(), part.get())) return false;
|
||||
if (s != part && s->isAncestor(*part)) return false;
|
||||
}
|
||||
}
|
||||
// select
|
||||
@@ -70,15 +71,6 @@ void SymbolPartsSelection::clearChildren(SymbolPart* part) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SymbolPartsSelection::isAncestor(SymbolPart* ancestor, SymbolPart* part) {
|
||||
if (SymbolGroup* g = ancestor->isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
if (part == p.get()) return true;
|
||||
if (isAncestor(p.get(), part)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Position based
|
||||
|
||||
@@ -116,7 +108,7 @@ bool SymbolPartsSelection::selectRect(const Vector2D& a, const Vector2D& b, cons
|
||||
}
|
||||
bool SymbolPartsSelection::selectRect(const SymbolGroup& parent, const Vector2D& a, const Vector2D& b, const Vector2D& c) {
|
||||
bool changes = false;
|
||||
FOR_EACH_CONST(p, root->parts) {
|
||||
FOR_EACH_CONST(p, parent.parts) {
|
||||
bool in_ab = (p->min_pos.x >= min(a.x, b.x) && p->min_pos.y >= min(a.y, b.y) && p->max_pos.x <= max(a.x, b.x) && p->max_pos.y <= max(a.y, b.y));
|
||||
bool in_bc = (p->min_pos.x >= min(a.x, c.x) && p->min_pos.y >= min(a.y, c.y) && p->max_pos.x <= max(a.x, c.x) && p->max_pos.y <= max(a.y, c.y));
|
||||
if (in_ab != in_bc) {
|
||||
|
||||
@@ -73,8 +73,6 @@ class SymbolPartsSelection {
|
||||
|
||||
/// Make sure not both a parent and its child/decendant are selected
|
||||
void clearChildren (SymbolPart* part);
|
||||
/// Is a part another's ancestor?
|
||||
static bool isAncestor(SymbolPart* ancestor, SymbolPart* part);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
/// Editor for adding symmetries
|
||||
class SymbolSymmetryEditor : public SymbolEditorBase {
|
||||
public:
|
||||
/** The symmetry parameter is optional, if it is not set, then only new ones can be created */
|
||||
//%SymbolSymmetryEditor(SymbolControl* control, SymbolSymmetryP symmetry);
|
||||
SymbolSymmetryEditor(SymbolControl* control);
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
@@ -29,7 +29,7 @@ SymbolWindow::SymbolWindow(Window* parent) {
|
||||
|
||||
SymbolWindow::SymbolWindow(Window* parent, const String& filename) {
|
||||
// open file
|
||||
Reader reader(filename);
|
||||
Reader reader(new_shared1<wxFileInputStream>(filename), filename);
|
||||
SymbolP symbol;
|
||||
reader.handle_greedy(symbol);
|
||||
init(parent, symbol);
|
||||
|
||||
@@ -15,12 +15,12 @@ DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||
// ----------------------------------------------------------------------------- : Simple rendering
|
||||
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius, int size) {
|
||||
SymbolViewer viewer(symbol, border_radius);
|
||||
SymbolViewer viewer(symbol, size, border_radius);
|
||||
Bitmap bmp(size, size);
|
||||
wxMemoryDC dc;
|
||||
dc.SelectObject(bmp);
|
||||
clearDC(dc, Color(0,128,0));
|
||||
viewer.rotation.setZoom(size);
|
||||
viewer.setZoom(size);
|
||||
viewer.draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
return bmp.ConvertToImage();
|
||||
@@ -28,13 +28,20 @@ Image render_symbol(const SymbolP& symbol, double border_radius, int size) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Constructor
|
||||
|
||||
SymbolViewer::SymbolViewer(const SymbolP& symbol, double border_radius)
|
||||
SymbolViewer::SymbolViewer(const SymbolP& symbol, double size, double border_radius)
|
||||
: border_radius(border_radius)
|
||||
, rotation(0, RealRect(0,0,500,500), 500)
|
||||
, rotation(0, RealRect(0,0,size,size), size)
|
||||
, multiply(size,0,0,size)
|
||||
, origin(0,0)
|
||||
{
|
||||
setSymbol(symbol);
|
||||
}
|
||||
|
||||
void SymbolViewer::setZoom(double zoom) {
|
||||
rotation.setZoom(zoom);
|
||||
multiply = Matrix2D(zoom,0, 0,zoom);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing
|
||||
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
@@ -73,16 +80,16 @@ void SymbolViewer::draw(DC& dc) {
|
||||
}
|
||||
}
|
||||
// Draw all parts
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, borderDC, interiorDC);
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, true, borderDC, interiorDC);
|
||||
|
||||
// Output the final parts from the buffer
|
||||
if (buffersFilled) {
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
}
|
||||
}
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, MemoryDCP& borderDC, MemoryDCP& interiorDC) {
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC) {
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled) {
|
||||
if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled && allow_overlap) {
|
||||
// We will be overlapping some previous parts, write them to the screen
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
// Clear the buffers
|
||||
@@ -111,14 +118,61 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
|
||||
combineSymbolShape(*s, *borderDC, *interiorDC, false, false);
|
||||
buffersFilled = true;
|
||||
}
|
||||
// Paint symmetric versions of this part
|
||||
// TODO
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
// symmetry, already handled above
|
||||
// Draw all parts, in reverse order (bottom to top), also draw rotated copies
|
||||
double b = 2 * atan2(s->handle.y, s->handle.x);
|
||||
Matrix2D old_m = multiply;
|
||||
Vector2D old_o = origin;
|
||||
int copies = s->kind == SYMMETRY_REFLECTION ? s->copies / 2 * 2 : s->copies;
|
||||
FOR_EACH_CONST_REVERSE(p, s->parts) {
|
||||
for (int i = 0 ; i < copies ; ++i) {
|
||||
if (s->clip) {
|
||||
// todo: clip
|
||||
}
|
||||
double a = i * 2 * M_PI / copies;
|
||||
if (s->kind == SYMMETRY_ROTATION || i % 2 == 0) {
|
||||
// set matrix
|
||||
// Calling:
|
||||
// - p the input point
|
||||
// - p' the output point
|
||||
// - rot our rotation matrix
|
||||
// - d out origin
|
||||
// - o the current origin (old_o)
|
||||
// - m the current matrix (old_m)
|
||||
// We want:
|
||||
// p' = ((p - d) * rot + d) * m + o
|
||||
// = (p * rot - d * rot + d) * m + o
|
||||
// = p * rot * m + (d - d * rot) * m + o
|
||||
Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
multiply.mx = rot.mx * old_m;
|
||||
multiply.my = rot.my * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
} else {
|
||||
// reflection
|
||||
// Calling angle = b
|
||||
// Matrix2D ref(cos(b),sin(b), sin(b),-cos(b));
|
||||
// Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||
//
|
||||
// ref * rot
|
||||
// /cos b sin b\ /cos a -sin a\
|
||||
// = \sin b -cos b/ \sin a cos a/
|
||||
// = /cos(a+b) sin(a+b)\
|
||||
// \sin(a+b) -cos(a+b)/
|
||||
Matrix2D rot(cos(a+b),sin(a+b), sin(a+b),-cos(a+b));
|
||||
multiply.mx = rot.mx * old_m;
|
||||
multiply.my = rot.my * old_m;
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
}
|
||||
// draw rotated copy
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap && i == 0, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
multiply = old_m;
|
||||
origin = old_o;
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
// Draw all parts, in reverse order (bottom to top)
|
||||
FOR_EACH_CONST_REVERSE(p, g->parts) {
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, borderDC, interiorDC);
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,7 +193,7 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyl
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), rotation, points);
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
@@ -238,7 +292,7 @@ void SymbolViewer::drawSymbolShape(const SymbolShape& shape, DC* border, DC* int
|
||||
vector<wxPoint> points;
|
||||
size_t size = shape.points.size();
|
||||
for(size_t i = 0 ; i < size ; ++i) {
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), rotation, points);
|
||||
segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), origin, multiply, points);
|
||||
}
|
||||
// draw border
|
||||
if (border && border_radius > 0) {
|
||||
|
||||
@@ -32,14 +32,18 @@ enum HighlightStyle
|
||||
class SymbolViewer : public SymbolView {
|
||||
public:
|
||||
// --------------------------------------------------- : Data
|
||||
SymbolViewer(const SymbolP& symbol, double border_radius = 0.05);
|
||||
SymbolViewer(const SymbolP& symbol, double size = 500, double border_radius = 0.05);
|
||||
|
||||
// drawing
|
||||
double border_radius;
|
||||
|
||||
// --------------------------------------------------- : Point translation
|
||||
|
||||
void setZoom(double zoom);
|
||||
|
||||
Rotation rotation; ///< Object that handles rotation, scaling and translation
|
||||
Matrix2D multiply; ///< Scaling/rotation of actual parts
|
||||
Vector2D origin; ///< Origin of parts
|
||||
|
||||
// --------------------------------------------------- : Drawing
|
||||
|
||||
@@ -57,7 +61,7 @@ class SymbolViewer : public SymbolView {
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
|
||||
/// Combine a symbol part with the dc
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, MemoryDCP& borderDC, MemoryDCP& interiorDC);
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC);
|
||||
|
||||
/// Combines a symbol part with what is currently drawn, the border and interior are drawn separatly
|
||||
/** directB/directI are true if the border/interior is the screen dc, false if it
|
||||
|
||||
Reference in New Issue
Block a user