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:
twanvl
2008-08-30 21:51:38 +00:00
parent acb3493b59
commit a183ecc9a6
23 changed files with 306 additions and 159 deletions
+40 -8
View File
@@ -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);
}
+9
View File
@@ -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
View File
@@ -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);
}
+4 -4
View File
@@ -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
View File
@@ -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?
+4 -4
View File
@@ -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
+32 -1
View File
@@ -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);
}
+5
View File
@@ -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