mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
Rotation and reflection should now work correctly;
Finished the symmetry editor git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@538 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -44,8 +44,7 @@ void filter_symbol(Image& symbol, const SymbolFilter& filter) {
|
||||
// HACK: wxGTK seems to fail sometimes if you ask it to allocate the alpha channel.
|
||||
// This manually allocates the memory and gives it to the image to handle.
|
||||
if (!alpha) {
|
||||
alpha = (Byte*) malloc (sizeof(Byte) * width * height);
|
||||
memset(alpha, 255, width * height);
|
||||
alpha = (Byte*) malloc(width * height);
|
||||
symbol.SetAlpha(alpha);
|
||||
}
|
||||
for (UInt y = 0 ; y < width ; ++y) {
|
||||
@@ -53,14 +52,18 @@ void filter_symbol(Image& symbol, const SymbolFilter& filter) {
|
||||
// Determine set
|
||||
// green -> border or outside
|
||||
// green+red=white -> border
|
||||
SymbolSet point = data[1] ? (data[0] ? SYMBOL_BORDER : SYMBOL_OUTSIDE) : SYMBOL_INSIDE;
|
||||
// Call filter
|
||||
AColor result = filter.color((double)x / width, (double)y / height, point);
|
||||
// Store color
|
||||
data[0] = result.Red();
|
||||
data[1] = result.Green();
|
||||
data[2] = result.Blue();
|
||||
alpha[0] = result.alpha;
|
||||
if (data[1] != data[2]) {
|
||||
// yellow/blue = editing hint, leave alone
|
||||
} else {
|
||||
SymbolSet point = data[1] ? (data[0] ? SYMBOL_BORDER : SYMBOL_OUTSIDE) : SYMBOL_INSIDE;
|
||||
// Call filter
|
||||
AColor result = filter.color((double)x / width, (double)y / height, point);
|
||||
// Store color
|
||||
data[0] = result.Red();
|
||||
data[1] = result.Green();
|
||||
data[2] = result.Blue();
|
||||
alpha[0] = result.alpha;
|
||||
}
|
||||
// next
|
||||
data += 3;
|
||||
alpha += 1;
|
||||
@@ -68,8 +71,8 @@ void filter_symbol(Image& symbol, const SymbolFilter& filter) {
|
||||
}
|
||||
}
|
||||
|
||||
Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double border_radius, int size) {
|
||||
Image i = render_symbol(symbol, border_radius, size);
|
||||
Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double border_radius, int size, bool edit_hints) {
|
||||
Image i = render_symbol(symbol, border_radius, size, edit_hints);
|
||||
filter_symbol(i, filter);
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class AColor : public Color {
|
||||
void filter_symbol(Image& symbol, const SymbolFilter& filter);
|
||||
|
||||
/// Render a Symbol to an Image and filter it
|
||||
Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double border_radius = 0.05, int size = 100);
|
||||
Image render_symbol(const SymbolP& symbol, const SymbolFilter& filter, double border_radius = 0.05, int size = 100, bool edit_hints = false);
|
||||
|
||||
/// Is a point inside a symbol?
|
||||
enum SymbolSet
|
||||
|
||||
+113
-81
@@ -14,7 +14,7 @@ DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Simple rendering
|
||||
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius, int size) {
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius, int size, bool editing_hints) {
|
||||
SymbolViewer viewer(symbol, size, border_radius);
|
||||
Bitmap bmp(size, size);
|
||||
wxMemoryDC dc;
|
||||
@@ -28,11 +28,12 @@ Image render_symbol(const SymbolP& symbol, double border_radius, int size) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Constructor
|
||||
|
||||
SymbolViewer::SymbolViewer(const SymbolP& symbol, double size, double border_radius)
|
||||
: border_radius(border_radius)
|
||||
SymbolViewer::SymbolViewer(const SymbolP& symbol, bool editing_hints, double size, double border_radius)
|
||||
: border_radius(border_radius), editing_hints(editing_hints)
|
||||
, rotation(0, RealRect(0,0,size,size), size)
|
||||
, multiply(size,0,0,size)
|
||||
, origin(0,0)
|
||||
, in_symmetry(0)
|
||||
{
|
||||
setSymbol(symbol);
|
||||
}
|
||||
@@ -42,7 +43,7 @@ void SymbolViewer::setZoom(double zoom) {
|
||||
multiply = Matrix2D(zoom,0, 0,zoom);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing
|
||||
// ----------------------------------------------------------------------------- : Drawing : Combining
|
||||
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
|
||||
@@ -52,7 +53,7 @@ MemoryDCP getTempDC(DC& dc) {
|
||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 1);
|
||||
MemoryDCP newDC(new wxMemoryDC);
|
||||
newDC->SelectObject(buffer);
|
||||
clearDC_black(*newDC);
|
||||
clearDC(*newDC, *wxBLACK_BRUSH);
|
||||
return newDC;
|
||||
}
|
||||
|
||||
@@ -66,6 +67,7 @@ void combineBuffers(DC& dc, DC* borders, DC* interior) {
|
||||
void SymbolViewer::draw(DC& dc) {
|
||||
bool paintedSomething = false;
|
||||
bool buffersFilled = false;
|
||||
in_symmetry = 0;
|
||||
// Temporary dcs
|
||||
MemoryDCP borderDC;
|
||||
MemoryDCP interiorDC;
|
||||
@@ -80,12 +82,15 @@ void SymbolViewer::draw(DC& dc) {
|
||||
}
|
||||
}
|
||||
// Draw all parts
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, true, borderDC, interiorDC);
|
||||
|
||||
combineSymbolPart(dc, *symbol, paintedSomething, buffersFilled, false, borderDC, interiorDC);
|
||||
// Output the final parts from the buffer
|
||||
if (buffersFilled) {
|
||||
combineBuffers(dc, borderDC.get(), interiorDC.get());
|
||||
}
|
||||
// Editing hints?
|
||||
if (editing_hints) {
|
||||
drawEditingHints(dc);
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
@@ -124,8 +129,10 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
|
||||
Matrix2D old_m = multiply;
|
||||
Vector2D old_o = origin;
|
||||
int copies = s->kind == SYMMETRY_REFLECTION ? s->copies / 2 * 2 : s->copies;
|
||||
if (copies > 1) ++in_symmetry;
|
||||
FOR_EACH_CONST_REVERSE(p, s->parts) {
|
||||
for (int i = 0 ; i < copies ; ++i) {
|
||||
for (int i = copies - 1 ; i >= 0 ; --i) {
|
||||
if (i == 0) --in_symmetry;
|
||||
if (s->clip) {
|
||||
// todo: clip
|
||||
}
|
||||
@@ -164,11 +171,14 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
|
||||
origin = old_o + (s->center - s->center * rot) * old_m;
|
||||
}
|
||||
// draw rotated copy
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap && i == 0, borderDC, interiorDC);
|
||||
combineSymbolPart(dc, *p, paintedSomething, buffersFilled, allow_overlap && i == copies - 1, borderDC, interiorDC);
|
||||
}
|
||||
}
|
||||
multiply = old_m;
|
||||
origin = old_o;
|
||||
if (editing_hints) {
|
||||
highlightPart(dc, *s, HIGHLIGHT_LESS);
|
||||
}
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
// Draw all parts, in reverse order (bottom to top)
|
||||
FOR_EACH_CONST_REVERSE(p, g->parts) {
|
||||
@@ -177,83 +187,14 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style) {
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
highlightPart(dc, *s);
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
highlightPart(dc, *g, style);
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style) {
|
||||
// create point list
|
||||
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), origin, multiply, points);
|
||||
}
|
||||
// draw
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else if (style == HIGHLIGHT_BORDER_DOT) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 1, wxDOT));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else {
|
||||
dc.SetLogicalFunction(wxOR);
|
||||
dc.SetBrush(Color(0,0,64));
|
||||
dc.SetPen (*wxTRANSPARENT_PEN);
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
if (shape.combine == SYMBOL_COMBINE_SUBTRACT || shape.combine == SYMBOL_COMBINE_BORDER) {
|
||||
dc.SetLogicalFunction(wxAND);
|
||||
dc.SetBrush(Color(191,191,255));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
dc.SetLogicalFunction(wxCOPY);
|
||||
}
|
||||
}
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) {
|
||||
// center
|
||||
RealPoint center = rotation.tr(sym.center);
|
||||
// draw 'spokes'
|
||||
double angle = atan2(sym.handle.y, sym.handle.x);
|
||||
dc.SetPen(wxPen(Color(255,200,0),3));
|
||||
for (int i = 0; i < sym.copies ; ++i) {
|
||||
double a = angle + (i + 0.5) * 2 * M_PI / sym.copies;
|
||||
Vector2D dir(cos(a), sin(a));
|
||||
Vector2D dir2 = rotation.tr(sym.center + 2 * dir);
|
||||
dc.DrawLine(center.x, center.y, dir2.x, dir2.y);
|
||||
}
|
||||
// draw center
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(Color(255,200,0));
|
||||
dc.DrawCircle(center.x, center.y, 5);
|
||||
// draw handle
|
||||
Vector2D dir2 = rotation.tr(sym.center + sym.handle);
|
||||
dc.SetPen(wxPen(Color(255,200,0),1,wxDOT));
|
||||
dc.DrawLine(center.x, center.y, dir2.x, dir2.y);
|
||||
}
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) {
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawRectangle(rotation.tr(RealRect(group.min_pos, RealSize(group.max_pos - group.min_pos))));
|
||||
}
|
||||
FOR_EACH_CONST(part, group.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC& interior, bool directB, bool directI) {
|
||||
// what color should the interior be?
|
||||
// use black when drawing to the screen
|
||||
Byte interiorCol = directI ? 0 : 255;
|
||||
if (editing_hints && in_symmetry) {
|
||||
interiorCol = directI ? 16 : 240;
|
||||
}
|
||||
// how to draw depends on combining mode
|
||||
switch(shape.combine) {
|
||||
case SYMBOL_COMBINE_OVERLAP:
|
||||
@@ -287,6 +228,10 @@ void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC&
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing : Basic
|
||||
|
||||
|
||||
void SymbolViewer::drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, Byte borderCol, Byte interiorCol, bool directB, bool clear) {
|
||||
// create point list
|
||||
vector<wxPoint> points;
|
||||
@@ -318,3 +263,90 @@ void SymbolViewer::drawSymbolShape(const SymbolShape& shape, DC* border, DC* int
|
||||
interior->DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Drawing : Highlighting
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style) {
|
||||
if (const SymbolShape* s = part.isSymbolShape()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
highlightPart(dc, *s, style);
|
||||
} else if (const SymbolGroup* g = part.isSymbolGroup()) {
|
||||
highlightPart(dc, *g, style);
|
||||
} else {
|
||||
throw InternalError(_("Invalid symbol part type"));
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style) {
|
||||
if (style == HIGHLIGHT_LESS) return;
|
||||
// create point list
|
||||
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), origin, multiply, points);
|
||||
}
|
||||
// draw
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else if (style == HIGHLIGHT_BORDER_DOT) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 1, wxDOT));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
} else {
|
||||
dc.SetLogicalFunction(wxOR);
|
||||
dc.SetBrush(Color(0,0,64));
|
||||
dc.SetPen (*wxTRANSPARENT_PEN);
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
if (shape.combine == SYMBOL_COMBINE_SUBTRACT || shape.combine == SYMBOL_COMBINE_BORDER) {
|
||||
dc.SetLogicalFunction(wxAND);
|
||||
dc.SetBrush(Color(191,191,255));
|
||||
dc.DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
dc.SetLogicalFunction(wxCOPY);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym, HighlightStyle style) {
|
||||
// highlight parts?
|
||||
FOR_EACH_CONST(part, sym.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
// Color?
|
||||
Color color = style & HIGHLIGHT_BORDER ? Color(255,100,0)
|
||||
: style & HIGHLIGHT_INTERIOR ? Color(255,200,0)
|
||||
: Color(200,170,0);
|
||||
// center
|
||||
RealPoint center = rotation.tr(sym.center);
|
||||
// draw 'spokes'
|
||||
double angle = atan2(sym.handle.y, sym.handle.x);
|
||||
dc.SetPen(wxPen(color, sym.kind == SYMMETRY_ROTATION ? 1 : 3));
|
||||
for (int i = 0; i < sym.copies ; ++i) {
|
||||
double a = angle + (i + 0.5) * 2 * M_PI / sym.copies;
|
||||
Vector2D dir(cos(a), sin(a));
|
||||
Vector2D dir2 = rotation.tr(sym.center + 2 * dir);
|
||||
dc.DrawLine(center.x, center.y, dir2.x, dir2.y);
|
||||
}
|
||||
// draw center
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(color);
|
||||
dc.DrawCircle(center.x, center.y, sym.kind == SYMMETRY_ROTATION ? 7 : 5);
|
||||
}
|
||||
|
||||
void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) {
|
||||
if (style == HIGHLIGHT_BORDER) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen (wxPen(Color(255,0,0), 2));
|
||||
dc.DrawRectangle(rotation.tr(RealRect(group.min_pos, RealSize(group.max_pos - group.min_pos))));
|
||||
}
|
||||
FOR_EACH_CONST(part, group.parts) {
|
||||
highlightPart(dc, *part, (HighlightStyle)(style | HIGHLIGHT_LESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SymbolViewer::drawEditingHints(DC& dc) {
|
||||
// TODO?
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// ----------------------------------------------------------------------------- : Simple rendering
|
||||
|
||||
/// Render a Symbol to an Image
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius = 0.05, int size = 100);
|
||||
Image render_symbol(const SymbolP& symbol, double border_radius = 0.05, int size = 100, bool editing_hints = false);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Symbol Viewer
|
||||
|
||||
@@ -32,11 +32,12 @@ enum HighlightStyle
|
||||
class SymbolViewer : public SymbolView {
|
||||
public:
|
||||
// --------------------------------------------------- : Data
|
||||
SymbolViewer(const SymbolP& symbol, double size = 500, double border_radius = 0.05);
|
||||
SymbolViewer(const SymbolP& symbol, bool editing_hints, double size = 500, double border_radius = 0.05);
|
||||
|
||||
// drawing
|
||||
double border_radius;
|
||||
|
||||
bool editing_hints;
|
||||
|
||||
// --------------------------------------------------- : Point translation
|
||||
|
||||
void setZoom(double zoom);
|
||||
@@ -50,15 +51,20 @@ class SymbolViewer : public SymbolView {
|
||||
/// Draw the symbol to a dc
|
||||
void draw(DC& dc);
|
||||
|
||||
void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolSymmetry& sym);
|
||||
void highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolSymmetry& sym, HighlightStyle style);
|
||||
void highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style);
|
||||
|
||||
void drawEditingHints(DC& dc);
|
||||
|
||||
void onAction(const Action&, bool) {}
|
||||
|
||||
|
||||
private:
|
||||
typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
||||
/// Inside a reflection?
|
||||
int in_symmetry;
|
||||
|
||||
/// Combine a symbol part with the dc
|
||||
void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, bool allow_overlap, MemoryDCP& borderDC, MemoryDCP& interiorDC);
|
||||
|
||||
Reference in New Issue
Block a user