mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 21:06:59 -04:00
New class CachedScriptableMask: like CachedScriptableImage, only containing an AlphaMask instead of an Image/Bitmap.
Use CachedScriptableMask for all masks. TODO: This introduces some duplicate code in ValueViewers that could be fixed by moving mask to the Style base class. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1182 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
#include <render/value/choice.hpp>
|
||||
#include <render/card/viewer.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(wxPoint);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ChoiceValueViewer
|
||||
|
||||
IMPLEMENT_VALUE_VIEWER(Choice);
|
||||
@@ -20,11 +22,48 @@ bool ChoiceValueViewer::prepare(RotatedDC& dc) {
|
||||
return prepare_choice_viewer(dc, *this, style(), value().value());
|
||||
}
|
||||
void ChoiceValueViewer::draw(RotatedDC& dc) {
|
||||
drawFieldBorder(dc);
|
||||
int w = max(0,(int)dc.trX(style().width)), h = max(0,(int)dc.trY(style().height));
|
||||
const AlphaMask& alpha_mask = getMask(w,h);
|
||||
drawFieldBorder(dc, alpha_mask);
|
||||
if (style().render_style & RENDER_HIDDEN) return;
|
||||
draw_choice_viewer(dc, *this, style(), value().value());
|
||||
}
|
||||
|
||||
void ChoiceValueViewer::drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask) {
|
||||
if (!alpha_mask.isLoaded()) {
|
||||
ValueViewer::drawFieldBorder(dc);
|
||||
} else if (setFieldBorderPen(dc)) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
vector<wxPoint> points;
|
||||
alpha_mask.convexHull(points);
|
||||
if (points.size() < 3) return;
|
||||
FOR_EACH(p, points) p = dc.trPixelNoZoom(RealPoint(p.x,p.y));
|
||||
dc.getDC().DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChoiceValueViewer::containsPoint(const RealPoint& p) const {
|
||||
// check against mask
|
||||
return getMask(0,0).isOpaque(p, style().getSize());
|
||||
}
|
||||
|
||||
void ChoiceValueViewer::onStyleChange(int changes) {
|
||||
if (changes & CHANGE_MASK) style().image.clearCache();
|
||||
ValueViewer::onStyleChange(changes);
|
||||
}
|
||||
|
||||
const AlphaMask& ChoiceValueViewer::getMask(int w, int h) const {
|
||||
GeneratedImage::Options opts;
|
||||
opts.package = &viewer.getStylePackage();
|
||||
opts.local_package = &viewer.getLocalPackage();
|
||||
opts.angle = 0;
|
||||
opts.width = w;
|
||||
opts.height = h;
|
||||
return style().mask.get(opts);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Generic draw/prepare
|
||||
|
||||
bool prepare_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& style, const String& value) {
|
||||
if (style.render_style & RENDER_IMAGE) {
|
||||
style.initImage();
|
||||
@@ -38,7 +77,6 @@ bool prepare_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& styl
|
||||
// Generate image/bitmap (whichever is available)
|
||||
// don't worry, we cache the image
|
||||
ImageCombine combine = style.combine;
|
||||
style.loadMask(viewer.getStylePackage());
|
||||
Bitmap bitmap; Image image;
|
||||
RealSize size;
|
||||
img.generateCached(img_options, &style.mask, &combine, &bitmap, &image, &size);
|
||||
@@ -70,7 +108,6 @@ void draw_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& style,
|
||||
get_options(dc, viewer, style, img_options);
|
||||
// Generate image/bitmap
|
||||
ImageCombine combine = style.combine;
|
||||
style.loadMask(viewer.getStylePackage());
|
||||
Bitmap bitmap; Image image;
|
||||
RealSize size;
|
||||
img.generateCached(img_options, &style.mask, &combine, &bitmap, &image, &size);
|
||||
@@ -112,8 +149,3 @@ void get_options(Rotation& rot, ValueViewer& viewer, const ChoiceStyle& style, G
|
||||
opts.preserve_aspect = (style.alignment & ALIGN_STRETCH) ? ASPECT_STRETCH : ASPECT_FIT;
|
||||
}
|
||||
}
|
||||
|
||||
void ChoiceValueViewer::onStyleChange(int changes) {
|
||||
if (changes & CHANGE_MASK) style().image.clearCache();
|
||||
ValueViewer::onStyleChange(changes);
|
||||
}
|
||||
|
||||
@@ -23,10 +23,19 @@ class ChoiceValueViewer : public ValueViewer {
|
||||
virtual bool prepare(RotatedDC& dc);
|
||||
virtual void draw(RotatedDC& dc);
|
||||
virtual void onStyleChange(int);
|
||||
|
||||
virtual bool containsPoint(const RealPoint& p) const;
|
||||
|
||||
private:
|
||||
/// Draws a border around the field
|
||||
void drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask);
|
||||
/// Load the AlphaMask for this field
|
||||
const AlphaMask& getMask(int w, int h) const;
|
||||
};
|
||||
|
||||
bool prepare_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& style, const String& value);
|
||||
void draw_choice_viewer(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& style, const String& value);
|
||||
const AlphaMask& get_mask(RotatedDC& dc, ValueViewer& viewer, ChoiceStyle& style, int w, int h);
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
+36
-32
@@ -11,6 +11,7 @@
|
||||
#include <render/card/viewer.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(ColorField::ChoiceP);
|
||||
DECLARE_TYPEOF_COLLECTION(wxPoint);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ColorValueViewer
|
||||
|
||||
@@ -43,9 +44,10 @@ void ColorValueViewer::draw(RotatedDC& dc) {
|
||||
dc.DrawText(color_name, RealPoint(43, 3));
|
||||
} else {
|
||||
// is there a mask?
|
||||
loadMask(dc);
|
||||
if (alpha_mask) {
|
||||
dc.DrawImage(alpha_mask->colorImage(value().value()), RealPoint(0,0), style().combine);
|
||||
int w = max(0,(int)dc.trX(style().width)), h = max(0,(int)dc.trY(style().height));
|
||||
const AlphaMask& alpha_mask = getMask(w,h);
|
||||
if (alpha_mask.isLoaded()) {
|
||||
dc.DrawImage(alpha_mask.colorImage(value().value()), RealPoint(0,0), style().combine);
|
||||
} else {
|
||||
// do we need clipping?
|
||||
bool clip = style().left_width < style().width && style().right_width < style().width &&
|
||||
@@ -64,43 +66,45 @@ void ColorValueViewer::draw(RotatedDC& dc) {
|
||||
dc.DrawRoundedRectangle(style().getInternalRect(), style().radius);
|
||||
if (clip) dc.getDC().DestroyClippingRegion();
|
||||
}
|
||||
drawFieldBorder(dc, alpha_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorValueViewer::drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask) {
|
||||
if (!alpha_mask.isLoaded()) {
|
||||
ValueViewer::drawFieldBorder(dc);
|
||||
} else if (setFieldBorderPen(dc)) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
vector<wxPoint> points;
|
||||
alpha_mask.convexHull(points);
|
||||
if (points.size() < 3) return;
|
||||
FOR_EACH(p, points) p = dc.trPixelNoZoom(RealPoint(p.x,p.y));
|
||||
dc.getDC().DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorValueViewer::containsPoint(const RealPoint& p) const {
|
||||
// distance to each side
|
||||
double left = p.x, right = style().width - p.x - 1;
|
||||
double top = p.y, bottom = style().height - p.y - 1;
|
||||
if (left < 0 || right < 0 || top < 0 || bottom < 0) return false; // outside bounding box
|
||||
// check against mask
|
||||
if (!style().mask_filename().empty()) loadMask(getRotation());
|
||||
if (alpha_mask) {
|
||||
return !alpha_mask->isTransparent((int)left, (int)top);
|
||||
const AlphaMask& alpha_mask = getMask(0,0);
|
||||
if (alpha_mask.isLoaded()) {
|
||||
// check against mask
|
||||
return alpha_mask.isOpaque(p, style().getSize());
|
||||
} else {
|
||||
double left = p.x, right = style().width - p.x - 1;
|
||||
double top = p.y, bottom = style().height - p.y - 1;
|
||||
if (left < 0 || right < 0 || top < 0 || bottom < 0) return false; // outside bounding box
|
||||
// check against border
|
||||
if (left >= style().left_width && right >= style().right_width && // outside horizontal border
|
||||
top >= style().top_width && bottom >= style().bottom_width) { // outside vertical border
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return left < style().left_width || right < style().right_width // inside horizontal border
|
||||
|| top < style().top_width || bottom < style().bottom_width; // inside vertical border
|
||||
}
|
||||
}
|
||||
|
||||
void ColorValueViewer::onStyleChange(int changes) {
|
||||
if (changes & CHANGE_MASK) alpha_mask = AlphaMaskP();
|
||||
ValueViewer::onStyleChange(changes);
|
||||
}
|
||||
|
||||
void ColorValueViewer::loadMask(const Rotation& rot) const {
|
||||
if (style().mask_filename().empty()) return; // no mask
|
||||
int w = (int) rot.trX(rot.getWidth()), h = (int) rot.trY(rot.getHeight());
|
||||
if (alpha_mask && alpha_mask->hasSize(wxSize(w,h))) return; // mask loaded and right size
|
||||
// (re) load the mask
|
||||
Image image;
|
||||
InputStreamP image_file = getStylePackage().openIn(style().mask_filename);
|
||||
if (image.LoadFile(*image_file)) {
|
||||
Image resampled(w,h);
|
||||
resample(image, resampled);
|
||||
alpha_mask = new_intrusive1<AlphaMask>(resampled);
|
||||
}
|
||||
const AlphaMask& ColorValueViewer::getMask(int w, int h) const {
|
||||
GeneratedImage::Options opts;
|
||||
opts.package = &viewer.getStylePackage();
|
||||
opts.local_package = &viewer.getLocalPackage();
|
||||
opts.angle = 0;
|
||||
opts.width = w;
|
||||
opts.height = h;
|
||||
return style().mask.get(opts);
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ class ColorValueViewer : public ValueViewer {
|
||||
virtual void draw(RotatedDC& dc);
|
||||
virtual bool containsPoint(const RealPoint& p) const;
|
||||
|
||||
virtual void onStyleChange(int);
|
||||
|
||||
private:
|
||||
mutable AlphaMaskP alpha_mask;
|
||||
void loadMask(const Rotation& rot) const;
|
||||
/// Draws a border around the field
|
||||
void drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask);
|
||||
/// Load the AlphaMask for this field
|
||||
const AlphaMask& getMask(int w, int h) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+17
-26
@@ -22,6 +22,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
// reset?
|
||||
int w = max(0,(int)dc.trX(style().width)), h = max(0,(int)dc.trY(style().height));
|
||||
int a = dc.trAngle(0); //% TODO : Add getAngle()?
|
||||
const AlphaMask& alpha_mask = getMask(w,h);
|
||||
if (bitmap.Ok() && (a != angle || size.width != w || size.height != h)) {
|
||||
bitmap = Bitmap();
|
||||
}
|
||||
@@ -30,7 +31,6 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
angle = a;
|
||||
is_default = false;
|
||||
Image image;
|
||||
loadMask(dc);
|
||||
// load from file
|
||||
if (!value().filename.empty()) {
|
||||
try {
|
||||
@@ -48,7 +48,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
is_default = true;
|
||||
if (what & DRAW_EDITING) {
|
||||
bitmap = imagePlaceholder(dc, w, h, image, what & DRAW_EDITING);
|
||||
if (alpha_mask || a) {
|
||||
if (alpha_mask.isLoaded() || a) {
|
||||
image = bitmap.ConvertToImage(); // we need to convert back to an image
|
||||
} else {
|
||||
image = Image();
|
||||
@@ -59,7 +59,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
if (!image.Ok() && !bitmap.Ok() && style().width > 40) {
|
||||
// placeholder bitmap
|
||||
bitmap = imagePlaceholder(dc, w, h, wxNullImage, what & DRAW_EDITING);
|
||||
if (alpha_mask || a) {
|
||||
if (alpha_mask.isLoaded() || a) {
|
||||
// we need to convert back to an image
|
||||
image = bitmap.ConvertToImage();
|
||||
}
|
||||
@@ -67,27 +67,27 @@ void ImageValueViewer::draw(RotatedDC& dc) {
|
||||
// done
|
||||
if (image.Ok()) {
|
||||
// apply mask and rotate
|
||||
if (alpha_mask) alpha_mask->setAlpha(image);
|
||||
alpha_mask.setAlpha(image);
|
||||
size = RealSize(image);
|
||||
image = rotate_image(image, angle);
|
||||
bitmap = Bitmap(image);
|
||||
}
|
||||
}
|
||||
// border
|
||||
drawFieldBorder(dc);
|
||||
drawFieldBorder(dc, alpha_mask);
|
||||
// draw image, if any
|
||||
if (bitmap.Ok()) {
|
||||
dc.DrawPreRotatedBitmap(bitmap, dc.getInternalRect());
|
||||
}
|
||||
}
|
||||
|
||||
void ImageValueViewer::drawFieldBorder(RotatedDC& dc) {
|
||||
if (!alpha_mask) {
|
||||
void ImageValueViewer::drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask) {
|
||||
if (!alpha_mask.isLoaded()) {
|
||||
ValueViewer::drawFieldBorder(dc);
|
||||
} else if (setFieldBorderPen(dc)) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
vector<wxPoint> points;
|
||||
alpha_mask->convexHull(points);
|
||||
alpha_mask.convexHull(points);
|
||||
if (points.size() < 3) return;
|
||||
FOR_EACH(p, points) p = dc.trPixelNoZoom(RealPoint(p.x,p.y));
|
||||
dc.getDC().DrawPolygon((int)points.size(), &points[0]);
|
||||
@@ -95,14 +95,8 @@ void ImageValueViewer::drawFieldBorder(RotatedDC& dc) {
|
||||
}
|
||||
|
||||
bool ImageValueViewer::containsPoint(const RealPoint& p) const {
|
||||
if (!ValueViewer::containsPoint(p)) return false;
|
||||
// check against mask
|
||||
if (!style().mask_filename().empty()) {
|
||||
loadMask(getRotation());
|
||||
return !alpha_mask || !alpha_mask->isTransparent((int)p.x, (int)p.y);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return getMask(0,0).isOpaque(p, style().getSize());
|
||||
}
|
||||
|
||||
void ImageValueViewer::onValueChange() {
|
||||
@@ -114,20 +108,17 @@ void ImageValueViewer::onStyleChange(int changes) {
|
||||
((changes & CHANGE_DEFAULT) && is_default)) {
|
||||
bitmap = Bitmap();
|
||||
}
|
||||
if (changes & CHANGE_MASK) alpha_mask = AlphaMaskP();
|
||||
ValueViewer::onStyleChange(changes);
|
||||
}
|
||||
|
||||
void ImageValueViewer::loadMask(const Rotation& rot) const {
|
||||
if (style().mask_filename().empty()) return; // no mask
|
||||
int w = (int) rot.trX(style().width), h = (int) rot.trY(style().height);
|
||||
if (alpha_mask && alpha_mask->hasSize(wxSize(w,h))) return; // mask loaded and right size
|
||||
// (re) load the mask
|
||||
Image image;
|
||||
InputStreamP image_file = getStylePackage().openIn(style().mask_filename);
|
||||
if (image.LoadFile(*image_file)) {
|
||||
alpha_mask = new_intrusive1<AlphaMask>(resample(image,w,h));
|
||||
}
|
||||
const AlphaMask& ImageValueViewer::getMask(int w, int h) const {
|
||||
GeneratedImage::Options opts;
|
||||
opts.package = &viewer.getStylePackage();
|
||||
opts.local_package = &viewer.getLocalPackage();
|
||||
opts.angle = 0;
|
||||
opts.width = w;
|
||||
opts.height = h;
|
||||
return style().mask.get(opts);
|
||||
}
|
||||
|
||||
// is an image very light?
|
||||
|
||||
@@ -34,15 +34,15 @@ class ImageValueViewer : public ValueViewer {
|
||||
RealSize size; ///< Size of cached bitmap
|
||||
int angle; ///< Angle of cached bitmap
|
||||
int is_default; ///< Is the default placeholder image used?
|
||||
mutable AlphaMaskP alpha_mask;
|
||||
|
||||
void loadMask(const Rotation& rot) const;
|
||||
|
||||
/// Generate a placeholder image
|
||||
static Bitmap imagePlaceholder(const Rotation& rot, UInt w, UInt h, const Image& background, bool editing);
|
||||
|
||||
/// Draws a border around the field
|
||||
void drawFieldBorder(RotatedDC& dc);
|
||||
void drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask);
|
||||
|
||||
/// Load the AlphaMask for this field
|
||||
const AlphaMask& getMask(int w, int h) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <gui/util.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(String);
|
||||
DECLARE_TYPEOF_COLLECTION(wxPoint);
|
||||
|
||||
// ----------------------------------------------------------------------------- : MultipleChoiceValueViewer
|
||||
|
||||
@@ -24,7 +25,9 @@ bool MultipleChoiceValueViewer::prepare(RotatedDC& dc) {
|
||||
}
|
||||
|
||||
void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
|
||||
drawFieldBorder(dc);
|
||||
int w = max(0,(int)dc.trX(style().width)), h = max(0,(int)dc.trY(style().height));
|
||||
const AlphaMask& alpha_mask = getMask(w,h);
|
||||
drawFieldBorder(dc, alpha_mask);
|
||||
if (style().render_style & RENDER_HIDDEN) return;
|
||||
RealPoint pos = align_in_rect(style().alignment, RealSize(0,0), style().getInternalRect());
|
||||
// selected choices
|
||||
@@ -83,7 +86,35 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const
|
||||
pos = move_in_direction(style().direction, pos, size, style().spacing);
|
||||
}
|
||||
|
||||
void MultipleChoiceValueViewer::drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask) {
|
||||
if (!alpha_mask.isLoaded()) {
|
||||
ValueViewer::drawFieldBorder(dc);
|
||||
} else if (setFieldBorderPen(dc)) {
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
vector<wxPoint> points;
|
||||
alpha_mask.convexHull(points);
|
||||
if (points.size() < 3) return;
|
||||
FOR_EACH(p, points) p = dc.trPixelNoZoom(RealPoint(p.x,p.y));
|
||||
dc.getDC().DrawPolygon((int)points.size(), &points[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool MultipleChoiceValueViewer::containsPoint(const RealPoint& p) const {
|
||||
// check against mask
|
||||
return getMask(0,0).isOpaque(p, style().getSize());
|
||||
}
|
||||
|
||||
void MultipleChoiceValueViewer::onStyleChange(int changes) {
|
||||
if (changes & CHANGE_MASK) style().image.clearCache();
|
||||
ValueViewer::onStyleChange(changes);
|
||||
}
|
||||
|
||||
const AlphaMask& MultipleChoiceValueViewer::getMask(int w, int h) const {
|
||||
GeneratedImage::Options opts;
|
||||
opts.package = &viewer.getStylePackage();
|
||||
opts.local_package = &viewer.getLocalPackage();
|
||||
opts.angle = 0;
|
||||
opts.width = w;
|
||||
opts.height = h;
|
||||
return style().mask.get(opts);
|
||||
}
|
||||
|
||||
@@ -23,10 +23,15 @@ class MultipleChoiceValueViewer : public ValueViewer {
|
||||
virtual bool prepare(RotatedDC& dc);
|
||||
virtual void draw(RotatedDC& dc);
|
||||
virtual void onStyleChange(int);
|
||||
virtual bool containsPoint(const RealPoint& p) const;
|
||||
protected:
|
||||
double item_height; ///< Height of a single item, or 0 if non uniform
|
||||
private:
|
||||
void drawChoice(RotatedDC& dc, RealPoint& pos, const String& choice, bool active = true);
|
||||
/// Draws a border around the field
|
||||
void drawFieldBorder(RotatedDC& dc, const AlphaMask& alpha_mask);
|
||||
/// Load the AlphaMask for this field
|
||||
const AlphaMask& getMask(int w, int h) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
Reference in New Issue
Block a user