diff --git a/src/data/field/symbol.cpp b/src/data/field/symbol.cpp index 07c39dbe..9b834b05 100644 --- a/src/data/field/symbol.cpp +++ b/src/data/field/symbol.cpp @@ -7,6 +7,7 @@ // ----------------------------------------------------------------------------- : Includes #include +#include // ----------------------------------------------------------------------------- : SymbolField @@ -35,7 +36,7 @@ SymbolStyle::Variation::Variation() IMPLEMENT_REFLECTION(SymbolStyle::Variation) { REFLECT(name); REFLECT(border_radius); - //REFLECT_NAMELESS(filter); + REFLECT_NAMELESS(filter); } // ----------------------------------------------------------------------------- : SymbolValue diff --git a/src/gfx/gfx.hpp b/src/gfx/gfx.hpp index dc6d3060..cc53b341 100644 --- a/src/gfx/gfx.hpp +++ b/src/gfx/gfx.hpp @@ -109,5 +109,8 @@ inline int bot(int x) { return max(0, x); } ///< bottom range check for color inline int top(int x) { return min(255, x); } ///< top range check for color values inline int col(int x) { return top(bot(x)); } ///< top and bottom range check for color values +/// Linear interpolation between colors +Color lerp(const Color& a, const Color& b, double t); + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/gui/control/gallery_list.cpp b/src/gui/control/gallery_list.cpp index 0278dd23..f4ae4ded 100644 --- a/src/gui/control/gallery_list.cpp +++ b/src/gui/control/gallery_list.cpp @@ -112,6 +112,7 @@ void GalleryList::onKeyDown(wxKeyEvent& ev) { } // Linear interpolation between colors +// MOVE ME, declared in gfx.hpp Color lerp(const Color& a, const Color& b, double t) { return Color(a.Red() + (b.Red() - a.Red() ) * t, a.Green() + (b.Green() - a.Green()) * t, diff --git a/src/gui/symbol/control.hpp b/src/gui/symbol/control.hpp index f792ee47..30ab7b59 100644 --- a/src/gui/symbol/control.hpp +++ b/src/gui/symbol/control.hpp @@ -11,7 +11,7 @@ #include #include -#include +#include class SymbolWindow; DECLARE_POINTER_TYPE(SymbolEditorBase); diff --git a/src/mse.vcproj b/src/mse.vcproj index 31a9f6cc..db61f41c 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -508,24 +508,6 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/render/symbol/filter.cpp b/src/render/symbol/filter.cpp new file mode 100644 index 00000000..77f39250 --- /dev/null +++ b/src/render/symbol/filter.cpp @@ -0,0 +1,135 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2006 Twan van Laarhoven | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include + +// ----------------------------------------------------------------------------- : Symbol filtering + +void filter_symbol(Image& symbol, const SymbolFilter& filter) { + if (!symbol.HasAlpha()) symbol.InitAlpha(); + Byte* data = symbol.GetData(); + Byte* alpha = symbol.GetAlpha(); + UInt width = symbol.GetWidth(), height = symbol.GetHeight(); + for (UInt y = 0 ; y < width ; ++y) { + for (UInt x = 0 ; x < height ; ++x) { + // 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[2] = result.Green(); + data[2] = result.Blue(); + alpha[0] = result.alpha; + // next + data += 3; + alpha += 1; + } + } +} + +// ----------------------------------------------------------------------------- : SymbolFilter + +IMPLEMENT_REFLECTION(SymbolFilter) { + if (!tag.reading()) { + String fill_type = fillType(); + REFLECT(fill_type); + } +} +template <> void GetMember::handle(const shared_ptr& f) { + handle(*f); +} + +template <> +shared_ptr read_new(Reader& reader) { + // there must be a fill type specified + String fill_type; + reader.handle(_("fill type"), fill_type); + if (fill_type == _("solid")) return new_shared(); + else if (fill_type == _("linear gradient")) return new_shared(); + else if (fill_type == _("radial gradient")) return new_shared(); + else { + throw ParseError(_("Unsupported fill type: '") + fill_type + _("'")); + } +} + +// ----------------------------------------------------------------------------- : SolidFillSymbolFilter + +String SolidFillSymbolFilter::fillType() const { return _("solid"); } + +AColor SolidFillSymbolFilter::color(double x, double y, SymbolSet point) const { + if (point == SYMBOL_INSIDE) return fill_color; + else if (point == SYMBOL_BORDER) return border_color; + else return AColor(0,0,0,0); +} + +IMPLEMENT_REFLECTION(SolidFillSymbolFilter) { + REFLECT_BASE(SymbolFilter); + REFLECT(fill_color); + REFLECT(border_color); +} + +// ----------------------------------------------------------------------------- : GradientSymbolFilter + +template +AColor GradientSymbolFilter::color(double x, double y, SymbolSet point, const T* t) const { + if (point == SYMBOL_INSIDE) return lerp(fill_color_1, fill_color_2, t->t(x,y)); + else if (point == SYMBOL_BORDER) return lerp(border_color_1, border_color_2, t->t(x,y)); + else return AColor(0,0,0,0); +} + +IMPLEMENT_REFLECTION(GradientSymbolFilter) { + REFLECT_BASE(SymbolFilter); + REFLECT(fill_color_1); + REFLECT(fill_color_2); + REFLECT(border_color_1); + REFLECT(border_color_2); +} + +// ----------------------------------------------------------------------------- : LinearGradientSymbolFilter + +String LinearGradientSymbolFilter::fillType() const { return _("linear gradient"); } + +LinearGradientSymbolFilter::LinearGradientSymbolFilter() + : center_x(0.5), center_y(0.5) + , end_x(1), end_y(1) +{} + +AColor LinearGradientSymbolFilter::color(double x, double y, SymbolSet point) const { + return GradientSymbolFilter::color(x,y,point,this); +} + +double LinearGradientSymbolFilter::t(double x, double y) const { + //return abs( int(x - center_x) * dirX + int(y - centerY) * dirY) * scale; + return 0; // todo +} + +IMPLEMENT_REFLECTION(LinearGradientSymbolFilter) { + REFLECT_BASE(GradientSymbolFilter); + REFLECT(center_x); REFLECT(center_y); + REFLECT(end_x); REFLECT(end_y); +} + +// ----------------------------------------------------------------------------- : RadialGradientSymbolFilter + +String RadialGradientSymbolFilter::fillType() const { return _("radial gradient"); } + +AColor RadialGradientSymbolFilter::color(double x, double y, SymbolSet point) const { + return GradientSymbolFilter::color(x,y,point,this); +} + +// TODO: move to some general util header +inline double sqr(double x) { return x * x; } + +double RadialGradientSymbolFilter::t(double x, double y) const { + return sqrt( (sqr(x - 0.5) + sqr(y - 0.5)) * 2); +} diff --git a/src/render/symbol/filter.hpp b/src/render/symbol/filter.hpp new file mode 100644 index 00000000..2079bd72 --- /dev/null +++ b/src/render/symbol/filter.hpp @@ -0,0 +1,111 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2006 Twan van Laarhoven | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +#ifndef HEADER_RENDER_SYMBOL_FILTER +#define HEADER_RENDER_SYMBOL_FILTER + +// ----------------------------------------------------------------------------- : Includes + +#include +#include + +class SymbolFilter; + +// ----------------------------------------------------------------------------- : Color + +/// Color with alpha channel +class AColor : public Color { + public: + int alpha; ///< The alpha value, in the range [0..255] + inline AColor(int r, int g, int b, int a = 255) : Color(r,g,b), alpha(a) {} + inline AColor(const Color& color, int a = 255) : Color(color), alpha(a) {} +}; + +// ----------------------------------------------------------------------------- : Symbol filtering + +/// Filter a symbol-image. +/** Filtering means that each pixel will be determined by the specified function. + * The result is stored in the symbol parameter. + */ +void filter_symbol(Image& symbol, const SymbolFilter& filter); + +/// Is a point inside a symbol? +enum SymbolSet +{ SYMBOL_INSIDE +, SYMBOL_BORDER +, SYMBOL_OUTSIDE +}; + +// ----------------------------------------------------------------------------- : SymbolFilter + +/// Base class for symbol filters +class SymbolFilter { + public: + virtual ~SymbolFilter() {} + /// What color should the symbol have at location (x, y)? + /** x,y are in the range [0...1) */ + virtual AColor color(double x, double y, SymbolSet point) const = 0; + /// Name of this fill type + virtual String fillType() const = 0; + + DECLARE_REFLECTION_VIRTUAL(); +}; + +template <> +shared_ptr read_new(Reader& reader); + +// ----------------------------------------------------------------------------- : SymbolFilter types + +/// Symbol filter that returns solid colors +class SolidFillSymbolFilter : public SymbolFilter { + public: + virtual AColor color(double x, double y, SymbolSet point) const; + virtual String fillType() const; + private: + Color fill_color, border_color; + DECLARE_REFLECTION(); +}; + +/// Symbol filter that returns some gradient +class GradientSymbolFilter : public SymbolFilter { + protected: + Color fill_color_1, border_color_1; + Color fill_color_2, border_color_2; + template + AColor color(double x, double y, SymbolSet point, const T* t) const; + + DECLARE_REFLECTION(); +}; + +/// Symbol filter that returns a linear gradient +class LinearGradientSymbolFilter : public GradientSymbolFilter { + public: + LinearGradientSymbolFilter(); + + virtual AColor color(double x, double y, SymbolSet point) const; + virtual String fillType() const; + + /// return time on the gradient, used by GradientSymbolFilter::color + inline double t(double x, double y) const; + + private: + double center_x, center_y; + double end_x, end_y; + DECLARE_REFLECTION(); +}; + +/// Symbol filter that returns a radial gradient +class RadialGradientSymbolFilter : public GradientSymbolFilter { + public: + virtual AColor color(double x, double y, SymbolSet point) const; + virtual String fillType() const; + + /// return time on the gradient, used by GradientSymbolFilter::color + inline double t(double x, double y) const; +}; + +// ----------------------------------------------------------------------------- : EOF +#endif diff --git a/src/render/symbol/viewer.cpp b/src/render/symbol/viewer.cpp index fcf3d86e..a884d3c8 100644 --- a/src/render/symbol/viewer.cpp +++ b/src/render/symbol/viewer.cpp @@ -6,14 +6,14 @@ // ----------------------------------------------------------------------------- : Includes -#include +#include DECLARE_TYPEOF_COLLECTION(SymbolPartP); // ----------------------------------------------------------------------------- : Constructor -SymbolViewer::SymbolViewer(const SymbolP& symbol, double borderRadius) - : borderRadius(borderRadius) +SymbolViewer::SymbolViewer(const SymbolP& symbol, double border_radius) + : border_radius(border_radius) , rotation(0, RealRect(0,0,500,500)) { setSymbol(symbol); @@ -176,7 +176,7 @@ void SymbolViewer::drawSymbolPart(const SymbolPart& part, DC* border, DC* interi // white/black border->SetBrush(Color(borderCol, borderCol, borderCol)); } - border->SetPen(wxPen(*wxWHITE, rotation.trS(borderRadius))); + border->SetPen(wxPen(*wxWHITE, rotation.trS(border_radius))); border->DrawPolygon((int)points.size(), &points[0]); } // draw interior @@ -186,38 +186,3 @@ void SymbolViewer::drawSymbolPart(const SymbolPart& part, DC* border, DC* interi interior->DrawPolygon((int)points.size(), &points[0]); } } - - -/* -void SymbolViewer::calcBezierPoint(const ControlPointP& p0, const ControlPointP& p1, Point*& p_out, UInt count) { - BezierCurve c(*p0, *p1); - // add start point - *p_out = toDisplay(*p0); - ++p_out; - // recursively calculate rest of curve - calcBezierOpt(c, *p0, *p1, 0.0f, 1.0f, p_out, count-1); -} - - -void SymbolViewer::calcBezierOpt(const BezierCurve& c, const Vector2D& p0, const Vector2D& p1, double t0, double t1, Point*& p_out, mutable UInt count) { - if (count <= 0) return; - double midtime = (t0+t1) * 0.5f; - Vector2D midpoint = c.pointAt(midtime); - Vector2D d0 = p0 - midpoint; - Vector2D d1 = midpoint - p1; - // Determine treshold for subdivision, greater angle -> subdivide - // greater size -> subdivide - double treshold = fabs( atan2(d0.x,d0.y) - atan2(d1.x,d1.y)) * (p0-p1).lengthSqr(); - bool subdivide = treshold >= .0001; - // subdivide left - calcBezierOpt(c, p0, midpoint, t0, midtime, p_out, count/2); - // add midpoint - if (subdivide) { - *p_out = toDisplay(midpoint); - ++p_out; - count -= 1; - } - // subdivide right - calcBezierOpt(c, midpoint, p1, midtime, t1, p_out, count/2); -} -*/ \ No newline at end of file diff --git a/src/render/symbol/viewer.hpp b/src/render/symbol/viewer.hpp index b5531fee..e5c796dd 100644 --- a/src/render/symbol/viewer.hpp +++ b/src/render/symbol/viewer.hpp @@ -14,6 +14,11 @@ #include #include +// ----------------------------------------------------------------------------- : Simple rendering + +/// Render a Symbol to an Image +Image render_symbol(const SymbolP& symbol, double border_radius = 0.05, int size = 100); + // ----------------------------------------------------------------------------- : Symbol Viewer enum HighlightStyle { @@ -25,10 +30,10 @@ enum HighlightStyle { class SymbolViewer : public SymbolView { public: // --------------------------------------------------- : Data - SymbolViewer(const SymbolP& symbol, double borderRadius = 0.05); + SymbolViewer(const SymbolP& symbol, double border_radius = 0.05); // drawing - double borderRadius; + double border_radius; // --------------------------------------------------- : Point translation diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index 62cdb160..4f5e2a66 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -55,6 +55,7 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) { ctx->setVariable(_("set"), new_intrusive1 >(&set)); ctx->setVariable(_("game"), toScript(set.game)); ctx->setVariable(_("stylesheet"), toScript(stylesheet)); + ctx->setVariable(_("card"), set.cards.empty() ? script_nil : toScript(set.cards.front())); // dummy value //ctx->setVariable(_("styling"), toScript(set->extraStyleData(style))); try { // perform init scripts