mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-11 05:07:00 -04:00
Added 'position hint' to packages, used to specify the order of the packages in a package list;
Added 'pack type', intended for playtesting (random boosters/starters); Added 'default(_image)' property to ImageStyle, and added the frame fillers for magic; Added blurring and bold printing (rather hacky) to the text rendering functions (used for "double click to add image" text); Added 'symmetric overlay' combine mode, which will look really nice for hybrids; Moved the watermark choices from the game to an include file in magic-watermarks; Working on a replacement for the image scripting system that plays nicer with the rest of the code. In particular, it will be possible to compare generated images quickly, so they can be updated continuously. This is a work in progress, currently there are two versions of everything. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@327 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -38,6 +38,7 @@ IMPLEMENT_REFLECTION_ENUM(ImageCombine) {
|
||||
VALUE_N("or", COMBINE_OR);
|
||||
VALUE_N("xor", COMBINE_XOR);
|
||||
VALUE_N("shadow", COMBINE_SHADOW);
|
||||
VALUE_N("symmetric overlay",COMBINE_SYMMETRIC_OVERLAY);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combining functions
|
||||
@@ -81,6 +82,7 @@ COMBINE_FUN(COMBINE_AND, a & b )
|
||||
COMBINE_FUN(COMBINE_OR, a | b )
|
||||
COMBINE_FUN(COMBINE_XOR, a ^ b )
|
||||
COMBINE_FUN(COMBINE_SHADOW, (b * a * a) / (255 * 255) )
|
||||
COMBINE_FUN(COMBINE_SYMMETRIC_OVERLAY, (Combine<COMBINE_OVERLAY>::f(a,b) + Combine<COMBINE_OVERLAY>::f(b,a)) / 2 )
|
||||
|
||||
// ----------------------------------------------------------------------------- : Combining
|
||||
|
||||
@@ -131,6 +133,7 @@ void combine_image(Image& a, const Image& b, ImageCombine combine) {
|
||||
DISPATCH(COMBINE_OR);
|
||||
DISPATCH(COMBINE_XOR);
|
||||
DISPATCH(COMBINE_SHADOW);
|
||||
DISPATCH(COMBINE_SYMMETRIC_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <gfx/generated_image.hpp>
|
||||
#include <util/io/package.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <data/symbol.hpp>
|
||||
#include <data/field/symbol.hpp>
|
||||
#include <render/symbol/filter.hpp>
|
||||
#include <gui/util.hpp> // load_resource_image
|
||||
|
||||
// ----------------------------------------------------------------------------- : GeneratedImage
|
||||
|
||||
ScriptType GeneratedImage::type() const { return SCRIPT_IMAGE; }
|
||||
String GeneratedImage::typeName() const { return _TYPE_("image"); }
|
||||
|
||||
// ----------------------------------------------------------------------------- : LinearBlendImage
|
||||
|
||||
Image LinearBlendImage::generate(const Options& opt) const {
|
||||
Image img = image1->generate(opt);
|
||||
linear_blend(img, image2->generate(opt), x1, y1, x2, y2);
|
||||
return img;
|
||||
}
|
||||
ImageCombine LinearBlendImage::combine() const {
|
||||
return image1->combine();
|
||||
}
|
||||
bool LinearBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const LinearBlendImage* that2 = dynamic_cast<const LinearBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& x1 == that2->x1 && y1 == that2->y1
|
||||
&& x2 == that2->x2 && y2 == that2->y2;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||
|
||||
Image MaskedBlendImage::generate(const Options& opt) const {
|
||||
Image img = light->generate(opt);
|
||||
mask_blend(img, dark->generate(opt), mask->generate(opt));
|
||||
return img;
|
||||
}
|
||||
ImageCombine MaskedBlendImage::combine() const {
|
||||
return light->combine();
|
||||
}
|
||||
bool MaskedBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const MaskedBlendImage* that2 = dynamic_cast<const MaskedBlendImage*>(&that);
|
||||
return that2 && *light == *that2->light
|
||||
&& *dark == *that2->dark
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||
|
||||
Image CombineBlendImage::generate(const Options& opt) const {
|
||||
Image img = image1->generate(opt);
|
||||
combine_image(img, image2->generate(opt), image_combine);
|
||||
return img;
|
||||
}
|
||||
ImageCombine CombineBlendImage::combine() const {
|
||||
return image1->combine();
|
||||
}
|
||||
bool CombineBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const CombineBlendImage* that2 = dynamic_cast<const CombineBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||
|
||||
Image SetMaskImage::generate(const Options& opt) const {
|
||||
Image img = image->generate(opt);
|
||||
set_alpha(img, mask->generate(opt));
|
||||
return img;
|
||||
}
|
||||
ImageCombine SetMaskImage::combine() const {
|
||||
return image->combine();
|
||||
}
|
||||
bool SetMaskImage::operator == (const GeneratedImage& that) const {
|
||||
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||
|
||||
Image SetCombineImage::generate(const Options& opt) const {
|
||||
return image->generate(opt);
|
||||
}
|
||||
ImageCombine SetCombineImage::combine() const {
|
||||
return image->combine();
|
||||
}
|
||||
bool SetCombineImage::operator == (const GeneratedImage& that) const {
|
||||
const SetCombineImage* that2 = dynamic_cast<const SetCombineImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackagedImage
|
||||
|
||||
Image PackagedImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
// open file from package
|
||||
if (!opt.package) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
||||
InputStreamP file = opt.package->openIn(filename);
|
||||
Image img;
|
||||
if (img.LoadFile(*file)) {
|
||||
if (img.HasMask()) img.InitAlpha(); // we can't handle masks
|
||||
return img;
|
||||
} else {
|
||||
throw ScriptError(_("Unable to load image '") + filename + _("' from '" + opt.package->name() + _("'")));
|
||||
}
|
||||
}
|
||||
bool PackagedImage::operator == (const GeneratedImage& that) const {
|
||||
const PackagedImage* that2 = dynamic_cast<const PackagedImage*>(&that);
|
||||
return that2 && filename == that2->filename;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : BuiltInImage
|
||||
|
||||
Image BuiltInImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
Image img = load_resource_image(name);
|
||||
if (!img.Ok()) {
|
||||
throw ScriptError(_("There is no build in image '") + name + _("'"));
|
||||
}
|
||||
return img;
|
||||
}
|
||||
bool BuiltInImage::operator == (const GeneratedImage& that) const {
|
||||
const BuiltInImage* that2 = dynamic_cast<const BuiltInImage*>(&that);
|
||||
return that2 && name == that2->name;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolToImage
|
||||
|
||||
Image SymbolToImage::generate(const Options& opt) const {
|
||||
// TODO : use opt.width and opt.height?
|
||||
if (!opt.symbol_package) throw ScriptError(_("Can only load images in a context where an image is expected"));
|
||||
SymbolP the_symbol;
|
||||
if (filename.empty()) {
|
||||
the_symbol = default_symbol();
|
||||
} else {
|
||||
the_symbol = opt.symbol_package->readFile<SymbolP>(filename);
|
||||
}
|
||||
return render_symbol(the_symbol, *variation->filter, variation->border_radius);
|
||||
}
|
||||
bool SymbolToImage::operator == (const GeneratedImage& that) const {
|
||||
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
|
||||
return that2 && filename == that2->filename
|
||||
&& age == that2->age
|
||||
&& variation == that2->variation;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
//+----------------------------------------------------------------------------+
|
||||
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||
//| Copyright: (C) 2001 - 2007 Twan van Laarhoven |
|
||||
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||
//+----------------------------------------------------------------------------+
|
||||
|
||||
#ifndef HEADER_GFX_GENERATED_IMAGE
|
||||
#define HEADER_GFX_GENERATED_IMAGE
|
||||
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/age.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <script/value.hpp>
|
||||
|
||||
DECLARE_INTRUSIVE_POINTER_TYPE(GeneratedImage);
|
||||
DECLARE_POINTER_TYPE(SymbolVariation);
|
||||
class Package;
|
||||
|
||||
// ----------------------------------------------------------------------------- : GeneratedImage
|
||||
|
||||
/// An image that is generated from a script.
|
||||
/** The actual generation is independend of the script execution
|
||||
*/
|
||||
class GeneratedImage : public ScriptValue {
|
||||
public:
|
||||
/// Options for generating the image
|
||||
struct Options {
|
||||
Options(int width = 0, int height = 0, Package* package = nullptr, Package* symbol_package = nullptr, PreserveAspect preserve_aspect = ASPECT_STRETCH, bool saturate = false)
|
||||
: width(width), height(height), preserve_aspect(preserve_aspect), saturate(saturate), package(package), symbol_package(symbol_package)
|
||||
{}
|
||||
|
||||
int width, height; ///< Width to force the image to, or 0 to keep the width of the input
|
||||
PreserveAspect preserve_aspect;
|
||||
bool saturate;
|
||||
Package* package; ///< Package to load images from
|
||||
Package* symbol_package; ///< Package to load symbols from
|
||||
};
|
||||
|
||||
/// Generate the image
|
||||
virtual Image generate(const Options&) const = 0;
|
||||
/// How must the image be combined with the background?
|
||||
virtual ImageCombine combine() const { return COMBINE_NORMAL; }
|
||||
/// Equality should mean that every pixel in the generated images is the same if the same options are used
|
||||
virtual bool operator == (const GeneratedImage& that) const = 0;
|
||||
inline bool operator != (const GeneratedImage& that) const { return !(*this == that); }
|
||||
|
||||
virtual ScriptType type() const;
|
||||
virtual String typeName() const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : LinearBlendImage
|
||||
|
||||
/// An image generator that linearly blends two other images
|
||||
class LinearBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline LinearBlendImage(const GeneratedImageP& image1, const GeneratedImageP& image2, double x1, double y1, double x2, double y2)
|
||||
: image1(image1), image2(image2), x1(x1), y1(y1), x2(x2), y2(y2)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image1, image2;
|
||||
double x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||
|
||||
/// An image generator that blends two other images using a third as a mask
|
||||
class MaskedBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline MaskedBlendImage(const GeneratedImageP& light, const GeneratedImageP& dark, const GeneratedImageP& mask)
|
||||
: light(light), dark(dark), mask(mask)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP light, dark, mask;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||
|
||||
/// An image generator that blends two other images using an ImageCombine function
|
||||
class CombineBlendImage : public GeneratedImage {
|
||||
public:
|
||||
inline CombineBlendImage(const GeneratedImageP& image1, const GeneratedImageP& image2, ImageCombine image_combine)
|
||||
: image1(image1), image2(image2), image_combine(image_combine)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image1, image2;
|
||||
ImageCombine image_combine;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||
|
||||
/// Change the alpha channel of an image
|
||||
class SetMaskImage : public GeneratedImage {
|
||||
public:
|
||||
inline SetMaskImage(const GeneratedImageP& image, const GeneratedImageP& mask)
|
||||
: image(image), mask(mask)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image, mask;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||
|
||||
/// Change the combine mode
|
||||
class SetCombineImage : public GeneratedImage {
|
||||
public:
|
||||
inline SetCombineImage(const GeneratedImageP& image, ImageCombine image_combine)
|
||||
: image(image), image_combine(image_combine)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual ImageCombine combine() const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
GeneratedImageP image;
|
||||
ImageCombine image_combine;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackagedImage
|
||||
|
||||
/// Load an image from a file in a package
|
||||
class PackagedImage : public GeneratedImage {
|
||||
public:
|
||||
inline PackagedImage(const String& filename)
|
||||
: filename(filename)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String filename;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : BuiltInImage
|
||||
|
||||
/// Return a built in image
|
||||
class BuiltInImage : public GeneratedImage {
|
||||
public:
|
||||
inline BuiltInImage(const String& name)
|
||||
: name(name)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String name;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : SymbolToImage
|
||||
|
||||
/// Use a symbol as an image
|
||||
class SymbolToImage : public GeneratedImage {
|
||||
public:
|
||||
inline SymbolToImage(const String& filename, Age age, const SymbolVariationP& variation)
|
||||
: filename(filename), age(age), variation(variation)
|
||||
{}
|
||||
virtual Image generate(const Options& opt) const;
|
||||
virtual bool operator == (const GeneratedImage& that) const;
|
||||
private:
|
||||
String filename;
|
||||
Age age; ///< Age the symbol was last updated
|
||||
SymbolVariationP variation;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
+2
-1
@@ -48,7 +48,7 @@ void sharp_resample_and_clip(const Image& img_in, Image& img_out, wxRect rect, i
|
||||
* rect = rectangle to draw in
|
||||
* (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
|
||||
*/
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text);
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius = 0, int repeat = 1);
|
||||
|
||||
// scaling factor to use when drawing resampled text
|
||||
extern const int text_scaling;
|
||||
@@ -107,6 +107,7 @@ enum ImageCombine
|
||||
, COMBINE_OR
|
||||
, COMBINE_XOR
|
||||
, COMBINE_SHADOW
|
||||
, COMBINE_SYMMETRIC_OVERLAY
|
||||
};
|
||||
|
||||
/// Combine image b onto image a using some combining function.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <util/error.hpp>
|
||||
#include <gui/util.hpp> // clearDC_black
|
||||
|
||||
void blur_image(const Image& img_in, Image& img_out);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Resampled text
|
||||
|
||||
// scaling factor to use when drawing resampled text
|
||||
@@ -69,13 +71,35 @@ void downsample_to_alpha(Image& img_in, Image& img_out) {
|
||||
}*/
|
||||
}
|
||||
|
||||
// simple blur
|
||||
int blur_alpha_pixel(Byte* in, int x, int y, int width, int height) {
|
||||
return (2 * ( in[0]) + // center
|
||||
(x == 0 ? in[0] : in[-1]) + // left
|
||||
(y == 0 ? in[0] : in[-width]) + // up
|
||||
(x == width - 1 ? in[0] : in[1]) + // right
|
||||
(y == height - 1 ? in[0] : in[width]) // down
|
||||
) / 6;
|
||||
}
|
||||
|
||||
// TODO: move me?
|
||||
void blur_image_alpha(Image& img) {
|
||||
int width = img.GetWidth(), height = img.GetHeight();
|
||||
Byte* data = img.GetAlpha();
|
||||
for (int y = 0 ; y < height ; ++y) {
|
||||
for (int x = 0 ; x < width ; ++x) {
|
||||
*data = blur_alpha_pixel(data, x, y, width, height);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw text by first drawing it using a larger font and then downsampling it
|
||||
// optionally rotated by an angle
|
||||
// (w2,h2) = size of text
|
||||
// (wc,hc) = the corner where drawing should begin, (0,0) for top-left, (1,1) for bottom-right
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text) {
|
||||
// enlarge slightly
|
||||
int w = static_cast<int>(rect.width) + 1, h = static_cast<int>(rect.height) + 1;
|
||||
void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle, const String& text, int blur_radius, int repeat) {
|
||||
// enlarge slightly; some fonts are larger then the GetTextExtent tells us (especially italic fonts)
|
||||
int w = static_cast<int>(rect.width) + 3 + 2 * blur_radius, h = static_cast<int>(rect.height) + 1 + 2 * blur_radius;
|
||||
// determine sub-pixel position
|
||||
int xi = static_cast<int>(rect.x), yi = static_cast<int>(rect.y);
|
||||
int xsub = static_cast<int>(text_scaling * (rect.x - xi)), ysub = static_cast<int>(text_scaling * (rect.y - yi));
|
||||
@@ -87,7 +111,7 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle
|
||||
// now draw the text
|
||||
mdc.SetFont(dc.GetFont());
|
||||
mdc.SetTextForeground(*wxWHITE);
|
||||
mdc.DrawRotatedText(text, wc * w * text_scaling + xsub, hc * h * text_scaling + ysub, angle);
|
||||
mdc.DrawRotatedText(text, (wc * w + blur_radius) * text_scaling + xsub, (hc * h + blur_radius) * text_scaling + ysub, angle);
|
||||
// get image
|
||||
mdc.SelectObject(wxNullBitmap);
|
||||
Image img_large = buffer.ConvertToImage();
|
||||
@@ -95,7 +119,14 @@ void draw_resampled_text(DC& dc, const RealRect& rect, int wc, int hc, int angle
|
||||
Image img_small(w, h, false);
|
||||
fill_image(img_small, dc.GetTextForeground());
|
||||
downsample_to_alpha(img_large, img_small);
|
||||
// blur
|
||||
for (int i = 0 ; i < blur_radius ; ++i) {
|
||||
blur_image_alpha(img_small);
|
||||
}
|
||||
// step 3. draw to dc
|
||||
dc.DrawBitmap(img_small, xi + static_cast<int>(wc * (rect.width - w)), yi + static_cast<int>(hc * (rect.height - h)));
|
||||
for (int i = 0 ; i < repeat ; ++i) {
|
||||
dc.DrawBitmap(img_small, xi + static_cast<int>(wc * (rect.width - w)) - blur_radius,
|
||||
yi + static_cast<int>(hc * (rect.height - h)) - blur_radius);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user