Images are now cached as wxBitmap, not wxImage. This should improve performance.

Fixed some more corner cases of rotation+zoom.

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@630 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2007-08-25 21:24:28 +00:00
parent 741b987d54
commit 52ec7b38c0
38 changed files with 413 additions and 165 deletions
+61 -45
View File
@@ -15,30 +15,33 @@
bool ChoiceValueViewer::prepare(RotatedDC& dc) {
if (style().render_style & RENDER_IMAGE) {
style().initImage();
ScriptableImage& img = style().image;
CachedScriptableImage& img = style().image;
Context& ctx = viewer.getContext();
ctx.setVariable(_("input"), to_script(value().value()));
img.update(ctx);
//generate
if (img.isReady()) {
GeneratedImage::Options img_options(0,0, viewer.stylesheet.get(), &getSet());
if (nativeLook()) {
img_options.width = img_options.height = 16;
img_options.preserve_aspect = ASPECT_BORDER;
} else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size
// generate to determine the size
if (img.update(ctx) && img.isReady()) {
GeneratedImage::Options img_options;
getOptions(dc, img_options);
// Generate image/bitmap (whichever is available)
// don't worry, we cache the image
ImageCombine combine = style().combine;
style().loadMask(*viewer.stylesheet);
Bitmap bitmap; Image image;
img.generateCached(img_options, &style().mask, &combine, &bitmap, &image);
int w, h;
if (bitmap.Ok()) {
w = bitmap.GetWidth();
h = bitmap.GetHeight();
} else {
img_options.width = (int) dc.trX(style().width);
img_options.height = (int) dc.trY(style().height);
img_options.preserve_aspect = (style().alignment & ALIGN_STRETCH) ? ASPECT_STRETCH : ASPECT_FIT;
assert(image.Ok());
w = image.GetWidth();
h = image.GetHeight();
}
// don't worry we cache the image
Image image = img.generate(img_options, true);
if (sideways(img_options.angle)) swap(w,h);
// store content properties
if (style().content_width != image.GetWidth() ||
style().content_height != image.GetHeight()) {
style().content_width = image.GetWidth();
style().content_height = image.GetHeight();
if (style().content_width != w || style().content_height != h) {
style().content_width = w;
style().content_height = h;
return true;
}
}
@@ -53,33 +56,29 @@ void ChoiceValueViewer::draw(RotatedDC& dc) {
double margin = 0;
if (style().render_style & RENDER_IMAGE) {
// draw image
ScriptableImage& img = style().image;
CachedScriptableImage& img = style().image;
if (img.isReady()) {
GeneratedImage::Options img_options(0,0, viewer.stylesheet.get(), &getSet());
if (nativeLook()) {
img_options.width = img_options.height = 16;
img_options.preserve_aspect = ASPECT_BORDER;
} else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size
} else {
img_options.width = (int) dc.trX(style().width);
img_options.height = (int) dc.trY(style().height);
img_options.preserve_aspect = (style().alignment & ALIGN_STRETCH) ? ASPECT_STRETCH : ASPECT_FIT;
}
Image image = img.generate(img_options, true);
ImageCombine combine = img.combine();
// apply mask?
GeneratedImage::Options img_options;
getOptions(dc, img_options);
// Generate image/bitmap
ImageCombine combine = style().combine;
style().loadMask(*viewer.stylesheet);
if (style().mask.Ok()) {
set_alpha(image, style().mask);
Bitmap bitmap; Image image;
img.generateCached(img_options, &style().mask, &combine, &bitmap, &image);
if (bitmap.Ok()) {
// just draw it
dc.DrawPreRotatedBitmap(bitmap,
align_in_rect(style().alignment, dc.trInvNoNeg(RealSize(bitmap)), style().getRect())
);
margin = dc.trInv(RealSize(bitmap)).width + 1;
} else {
// use combine mode
dc.DrawPreRotatedImage(image,
align_in_rect(style().alignment, dc.trInvNoNeg(RealSize(image)), style().getRect()),
combine
);
margin = dc.trInv(RealSize(image)).width + 1;
}
// draw
dc.DrawImage(image,
align_in_rect(style().alignment, dc.trInvS(RealSize(image.GetWidth(), image.GetHeight())), style().getRect()),
combine == COMBINE_NORMAL ? style().combine : combine,
style().angle
);
margin = dc.trInvS(image.GetWidth()) + 1;
} else if (nativeLook()) {
// always have the margin
margin = 17;
@@ -99,6 +98,23 @@ void ChoiceValueViewer::draw(RotatedDC& dc) {
}
}
void ChoiceValueViewer::onStyleChange(bool already_prepared) {
if (!already_prepared) viewer.redraw(*this);
void ChoiceValueViewer::onStyleChange(int changes) {
if (changes & CHANGE_MASK) style().image.clearCache();
ValueViewer::onStyleChange(changes);
}
void ChoiceValueViewer::getOptions(Rotation& rot, GeneratedImage::Options& opts) {
opts.package = viewer.stylesheet.get();
opts.local_package = &getSet();
opts.angle = rot.trAngle(style().angle);
if (nativeLook()) {
opts.width = opts.height = 16;
opts.preserve_aspect = ASPECT_BORDER;
} else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size
} else {
opts.width = (int) rot.trX(style().width);
opts.height = (int) rot.trY(style().height);
opts.preserve_aspect = (style().alignment & ALIGN_STRETCH) ? ASPECT_STRETCH : ASPECT_FIT;
}
}
+3 -1
View File
@@ -22,7 +22,9 @@ class ChoiceValueViewer : public ValueViewer {
virtual bool prepare(RotatedDC& dc);
virtual void draw(RotatedDC& dc);
virtual void onStyleChange(bool);
virtual void onStyleChange(int);
private:
void getOptions(Rotation& rot, GeneratedImage::Options& opts);
};
// ----------------------------------------------------------------------------- : EOF
+3 -3
View File
@@ -86,9 +86,9 @@ bool ColorValueViewer::containsPoint(const RealPoint& p) const {
}
}
void ColorValueViewer::onStyleChange(bool already_prepared) {
alpha_mask = AlphaMaskP();
if (!already_prepared) viewer.redraw(*this);
void ColorValueViewer::onStyleChange(int changes) {
if (changes & CHANGE_MASK) alpha_mask = AlphaMaskP();
ValueViewer::onStyleChange(changes);
}
void ColorValueViewer::loadMask(const Rotation& rot) const {
+1 -1
View File
@@ -25,7 +25,7 @@ class ColorValueViewer : public ValueViewer {
virtual void draw(RotatedDC& dc);
virtual bool containsPoint(const RealPoint& p) const;
virtual void onStyleChange(bool);
virtual void onStyleChange(int);
private:
mutable AlphaMaskP alpha_mask;
+62 -16
View File
@@ -16,22 +16,64 @@
void ImageValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc);
// reset?
int w = (int)dc.trX(style().width), h = (int)dc.trY(style().height);
int a = dc.trAngle(style().angle);
if (bitmap.Ok() && (a != angle || bitmap.GetWidth() != w || bitmap.GetHeight() != h)) {
bitmap = Bitmap();
}
// try to load image
if (!bitmap.Ok() && !value().filename.empty()) {
try {
InputStreamP image_file = getSet().openIn(value().filename);
Image image;
if (image.LoadFile(*image_file)) {
image.Rescale((int)dc.trX(style().width), (int)dc.trY(style().height));
// apply mask to image
loadMask(dc);
if (alpha_mask) alpha_mask->setAlpha(image);
bitmap = Bitmap(image);
if (!bitmap.Ok()) {
angle = a;
is_default = false;
Image image;
loadMask(dc);
// load from file
if (!value().filename.empty()) {
try {
InputStreamP image_file = getSet().openIn(value().filename);
if (image.LoadFile(*image_file)) {
image.Rescale(w, h);
}
} catch (Error e) {
handle_error(e, false, false); // don't handle now, we are in onPaint
}
} catch (Error e) {
handle_error(e, false, false); // don't handle now, we are in onPaint
}
// nice placeholder
if (!image.Ok() && style().default_image.isReady()) {
image = style().default_image.generate(GeneratedImage::Options(w, h, viewer.stylesheet.get(), &getSet()));
is_default = true;
if (viewer.drawEditing()) {
bitmap = imagePlaceholder(dc, w, h, image, viewer.drawEditing());
if (alpha_mask || a) {
image = bitmap.ConvertToImage(); // we need to convert back to an image
} else {
image = Image();
}
}
}
// checkerboard placeholder
if (!image.Ok() && !bitmap.Ok() && style().width > 40) {
// placeholder bitmap
bitmap = imagePlaceholder(dc, w, h, wxNullImage, viewer.drawEditing());
if (alpha_mask || a) {
// we need to convert back to an image
image = bitmap.ConvertToImage();
}
}
// done
if (image.Ok()) {
// apply mask and rotate
if (alpha_mask) alpha_mask->setAlpha(image);
image = rotate_image(image, angle);
bitmap = Bitmap(image);
}
}
// draw image, if any
if (bitmap.Ok()) {
dc.DrawPreRotatedBitmap(bitmap, style().getPos());
}
/*
// if there is no image, generate a placeholder
if (!bitmap.Ok()) {
UInt w = (UInt)dc.trX(style().width), h = (UInt)dc.trY(style().height);
@@ -56,6 +98,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
if (bitmap.Ok()) {
dc.DrawBitmap(bitmap, style().getPos());
}
*/
}
bool ImageValueViewer::containsPoint(const RealPoint& p) const {
@@ -77,10 +120,13 @@ void ImageValueViewer::onValueChange() {
bitmap = Bitmap();
}
void ImageValueViewer::onStyleChange(bool already_prepared) {
bitmap = Bitmap();
alpha_mask = AlphaMaskP(); // TODO: only reload whatever has changed
if (!already_prepared) viewer.redraw(*this);
void ImageValueViewer::onStyleChange(int changes) {
if ((changes & CHANGE_MASK) ||
((changes & CHANGE_DEFAULT) && is_default)) {
bitmap = Bitmap();
}
if (changes & CHANGE_MASK) alpha_mask = AlphaMaskP();
ValueViewer::onStyleChange(changes);
}
void ImageValueViewer::loadMask(const Rotation& rot) const {
+4 -2
View File
@@ -27,10 +27,12 @@ class ImageValueViewer : public ValueViewer {
virtual bool containsPoint(const RealPoint& p) const;
virtual void onValueChange();
virtual void onStyleChange(bool);
virtual void onStyleChange(int);
private:
Bitmap bitmap;
Bitmap bitmap; ///< 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;
+40 -26
View File
@@ -44,36 +44,32 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
if (style().render_style & RENDER_IMAGE) {
// draw image
style().initImage();
ScriptableImage& img = style().image;
CachedScriptableImage& img = style().image;
Context& ctx = viewer.getContext();
ctx.setVariable(_("input"), to_script(value().value()));
img.update(ctx);
if (img.isReady()) {
GeneratedImage::Options img_options(0,0, viewer.stylesheet.get(), &getSet());
if (nativeLook()) {
img_options.width = img_options.height = 16;
img_options.preserve_aspect = ASPECT_BORDER;
} else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size
} else {
img_options.width = (int) dc.trX(style().width);
img_options.height = (int) dc.trY(style().height);
img_options.preserve_aspect = style().alignment == ALIGN_STRETCH ? ASPECT_STRETCH : ASPECT_FIT;
}
Image image = img.generate(img_options, true);
ImageCombine combine = img.combine();
// apply mask?
GeneratedImage::Options img_options;
getOptions(dc, img_options);
// Generate image/bitmap
ImageCombine combine = style().combine;
style().loadMask(*viewer.stylesheet);
if (style().mask.Ok()) {
set_alpha(image, style().mask);
Bitmap bitmap; Image image;
img.generateCached(img_options, &style().mask, &combine, &bitmap, &image);
if (bitmap.Ok()) {
// just draw it
dc.DrawPreRotatedBitmap(bitmap,
align_in_rect(style().alignment, dc.trInvNoNeg(RealSize(bitmap)), style().getRect())
);
margin = dc.trInv(RealSize(bitmap)).width + 1;
} else {
// use combine mode
dc.DrawPreRotatedImage(image,
align_in_rect(style().alignment, dc.trInvNoNeg(RealSize(image)), style().getRect()),
combine
);
margin = dc.trInv(RealSize(image)).width + 1;
}
// draw
dc.DrawImage(image,
align_in_rect(style().alignment, RealSize(image.GetWidth(), image.GetHeight()), style().getRect()),
combine == COMBINE_NORMAL ? style().combine : combine,
style().angle
);
margin = dc.trInvS(image.GetWidth()) + 1;
}
}
if (style().render_style & RENDER_TEXT) {
@@ -96,10 +92,11 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const
if (style().render_style & RENDER_IMAGE) {
map<String,ScriptableImage>::iterator it = style().choice_images.find(cannocial_name_form(choice));
if (it != style().choice_images.end() && it->second.isReady()) {
Image image = it->second.generate(GeneratedImage::Options(0,0, viewer.stylesheet.get(),&getSet()), true);
// TODO: scaling, caching
Image image = it->second.generate(GeneratedImage::Options(0,0, viewer.stylesheet.get(),&getSet()));
ImageCombine combine = it->second.combine();
// TODO : alignment?
dc.DrawImage(image, pos + RealSize(size.width, 0), combine == COMBINE_NORMAL ? style().combine : combine);
dc.DrawImage(image, pos + RealSize(size.width, 0), combine == COMBINE_DEFAULT ? style().combine : combine);
size = add_horizontal(size, dc.trInv(RealSize(image.GetWidth() + 1, image.GetHeight())));
}
}
@@ -114,3 +111,20 @@ void MultipleChoiceValueViewer::drawChoice(RotatedDC& dc, RealPoint& pos, const
// next position
pos = move_in_direction(style().direction, pos, size, style().spacing);
}
// COPY from ChoiceValueViewer
void MultipleChoiceValueViewer::getOptions(Rotation& rot, GeneratedImage::Options& opts) {
opts.package = viewer.stylesheet.get();
opts.local_package = &getSet();
opts.angle = rot.trAngle(style().angle);
if (nativeLook()) {
opts.width = opts.height = 16;
opts.preserve_aspect = ASPECT_BORDER;
} else if(style().render_style & RENDER_TEXT) {
// also drawing text, use original size
} else {
opts.width = (int) rot.trX(style().width);
opts.height = (int) rot.trY(style().height);
opts.preserve_aspect = (style().alignment & ALIGN_STRETCH) ? ASPECT_STRETCH : ASPECT_FIT;
}
}
+1
View File
@@ -25,6 +25,7 @@ class MultipleChoiceValueViewer : public ValueViewer {
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);
void getOptions(Rotation& rot, GeneratedImage::Options& opts);
};
// ----------------------------------------------------------------------------- : EOF
+2 -2
View File
@@ -42,9 +42,9 @@ void TextValueViewer::onValueChange() {
v.reset(false);
}
void TextValueViewer::onStyleChange(bool already_prepared) {
void TextValueViewer::onStyleChange(int changes) {
v.reset(true);
if (!already_prepared) viewer.redraw(*this);
ValueViewer::onStyleChange(changes);
}
void TextValueViewer::onAction(const Action&, bool undone) {
+1 -1
View File
@@ -24,7 +24,7 @@ class TextValueViewer : public ValueViewer {
virtual bool prepare(RotatedDC& dc);
virtual void draw(RotatedDC& dc);
virtual void onValueChange();
virtual void onStyleChange(bool);
virtual void onStyleChange(int);
virtual void onAction(const Action&, bool undone);
protected:
+7
View File
@@ -26,6 +26,7 @@ Set& ValueViewer::getSet() const { return *viewer.getSet(); }
void ValueViewer::setValue(const ValueP& value) {
assert(value->fieldP == styleP->fieldP); // matching field
if (valueP == value) return;
valueP = value;
onValueChange();
}
@@ -55,6 +56,12 @@ bool ValueViewer::isCurrent() const {
return viewer.focusedViewer() == this;
}
void ValueViewer::onStyleChange(int changes) {
if (!(changes & CHANGE_ALREADY_PREPARED)) {
viewer.redraw(*this);
}
}
// ----------------------------------------------------------------------------- : Type dispatch
#define IMPLEMENT_MAKE_VIEWER(Type) \
+2 -2
View File
@@ -57,8 +57,8 @@ class ValueViewer : public StyleListener {
*/
virtual void onValueChange() {}
/// Called when a (scripted) property of the associated style has changed
/** If alread_prepared, should make sure the viewer stays in a state similair to that after prepare() */
virtual void onStyleChange(bool already_prepared) {}
/** Default: redraws the viewer if needed */
virtual void onStyleChange(int changes);
/// Called when an action is performed on the associated value
virtual void onAction(const Action&, bool undone) { onValueChange(); }