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
+97 -14
View File
@@ -41,14 +41,7 @@ GeneratedImageP image_from_script(const ScriptValueP& value) {
// ----------------------------------------------------------------------------- : ScriptableImage
Image ScriptableImage::generate(const GeneratedImage::Options& options, bool cache) const {
if (cached.Ok() && (cached.GetWidth() == options.width && cached.GetHeight() == options.height
|| (options.preserve_aspect == ASPECT_FIT && // only one dimension has to fit
(cached.GetWidth() == options.width || cached.GetHeight() == options.height)
))) {
// cached, so we are done
return cached;
}
Image ScriptableImage::generate(const GeneratedImage::Options& options) const {
// generate
Image image;
if (isReady()) {
@@ -64,14 +57,11 @@ Image ScriptableImage::generate(const GeneratedImage::Options& options, bool cac
i.SetAlpha(0,0,0);
image = i;
}
image = conform_image(image, options);
// cache? and return
if (cache) cached = image;
return image;
return conform_image(image, options);
}
ImageCombine ScriptableImage::combine() const {
if (!isReady()) return COMBINE_NORMAL;
if (!isReady()) return COMBINE_DEFAULT;
return value->combine();
}
@@ -80,7 +70,6 @@ bool ScriptableImage::update(Context& ctx) {
GeneratedImageP new_value = image_from_script(script.invoke(ctx));
if (!new_value || !value || *new_value != *value) {
value = new_value;
cached = Image();
return true;
} else {
return false;
@@ -118,3 +107,97 @@ template <> void Writer::handle(const ScriptableImage& s) {
template <> void GetDefaultMember::handle(const ScriptableImage& s) {
handle(s.script.unparsed);
}
// ----------------------------------------------------------------------------- : CachedScriptableImage
void CachedScriptableImage::generateCached(const GeneratedImage::Options& options,
Image* mask,
ImageCombine* combine, wxBitmap* bitmap, wxImage* image) {
// ready?
if (!isReady()) {
// error, return blank image
Image i(1,1);
i.InitAlpha();
i.SetAlpha(0,0,0);
*image = i;
return;
}
// find combine mode
ImageCombine combine_i = value->combine();
if (combine_i != COMBINE_DEFAULT) *combine = combine_i;
// desired size
int ow = options.width, oh = options.height;
if (sideways(options.angle)) swap(ow,oh);
// image or bitmap?
if (*combine <= COMBINE_NORMAL) {
// bitmap
if (cached_b.Ok() && options.angle == cached_angle) {
bool w_ok = cached_b.GetWidth() == ow,
h_ok = cached_b.GetHeight() == oh;
if ((w_ok && h_ok) || (options.preserve_aspect == ASPECT_FIT && (w_ok || h_ok))) { // only one dimension has to fit when fitting
// cached, we are done
*bitmap = cached_b;
return;
}
}
} else {
// image
if (cached_i.Ok()) {
bool w_ok = cached_i.GetWidth() == options.width,
h_ok = cached_i.GetHeight() == options.height;
if ((w_ok && h_ok) || (options.preserve_aspect == ASPECT_FIT && (w_ok || h_ok))) { // only one dimension has to fit when fitting
if (options.angle != cached_angle) {
// rotate cached image
cached_i = rotate_image(cached_i, options.angle - cached_angle + 360);
cached_angle = options.angle;
}
*image = cached_i;
return;
}
}
}
// generate
cached_i = generate(options);
cached_angle = options.angle;
if (mask && mask->Ok()) {
// apply mask
if (mask->GetWidth() == cached_i.GetWidth() && mask->GetHeight() == cached_i.GetHeight()) {
set_alpha(cached_i, *mask);
} else {
Image mask_scaled(cached_i.GetWidth(),cached_i.GetHeight(), false);
resample(mask,mask_scaled);
set_alpha(cached_i, mask_scaled);
}
}
if (*combine <= COMBINE_NORMAL) {
*bitmap = cached_b = Bitmap(cached_i);
cached_i = Image();
} else {
*image = cached_i;
}
}
bool CachedScriptableImage::update(Context& ctx) {
bool change = ScriptableImage::update(ctx);
if (change) {
clearCache();
}
return change;
}
void CachedScriptableImage::clearCache() {
cached_i = Image();
cached_b = Bitmap();
}
template <> void Reader::handle(CachedScriptableImage& s) {
handle((ScriptableImage&)s);
}
template <> void Writer::handle(const CachedScriptableImage& s) {
handle((const ScriptableImage&)s);
}
template <> void GetDefaultMember::handle(const CachedScriptableImage& s) {
handle((const ScriptableImage&)s);
}
+35 -4
View File
@@ -20,7 +20,6 @@
/// An image that can also be scripted
/** Differs from Scriptable<Image> in that:
* - A script is always used
* - Age is checked, chached images are used if possible
* - The image can be scaled
*/
class ScriptableImage {
@@ -37,7 +36,7 @@ class ScriptableImage {
inline bool isSet() const { return script || value; }
/// Generate an image.
Image generate(const GeneratedImage::Options& options, bool cache = false) const;
Image generate(const GeneratedImage::Options& options) const;
/// How should images be combined with the background?
ImageCombine combine() const;
@@ -56,10 +55,9 @@ class ScriptableImage {
/// Get access to the script, always returns a valid script
ScriptP getScriptP();
private:
protected:
OptionalScript script; ///< The script, not really optional
GeneratedImageP value; ///< The image generator
mutable Image cached; ///< The cached actual image
DECLARE_REFLECTION();
};
@@ -70,5 +68,38 @@ inline ScriptValueP to_script(const ScriptableImage&) { return script_nil; }
/// Convert a script value to a GeneratedImageP
GeneratedImageP image_from_script(const ScriptValueP& value);
// ----------------------------------------------------------------------------- : CachedScriptableImage
/// A version of ScriptableImage that does caching
class CachedScriptableImage : public ScriptableImage {
public:
inline CachedScriptableImage() {}
inline CachedScriptableImage(const String& script) : ScriptableImage(script) {}
inline CachedScriptableImage(const GeneratedImageP& gen) : ScriptableImage(gen) {}
/// Generate an image, using caching if possible.
/** *combine should be set to the combine value of the style.
* It will be overwritten if the image specifies a non-default combine.
* After this call, either:
* - combine <= COMBINE_NORMAL && bitmap->Ok()
* - or combine > COMBINE_NORMAL && image->Ok()
* Optionally, an alpha mask is applied to the image.
*/
void generateCached(const GeneratedImage::Options& img_options,
Image* mask,
ImageCombine* combine, wxBitmap* bitmap, wxImage* image);
/// Update the script, returns true if the value has changed
bool update(Context& ctx);
/// Clears the cache
void clearCache();
private:
Image cached_i; ///< The cached image
Bitmap cached_b; ///< *or* the cached bitmap
int cached_angle;
};
// ----------------------------------------------------------------------------- : EOF
#endif
+2 -2
View File
@@ -224,9 +224,9 @@ void SetScriptManager::updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>&
FOR_EACH_CONST(s, styles) {
if (only_content_dependent && !s->content_dependent) continue;
try {
if (s->update(ctx)) {
if (int change = s->update(ctx)) {
// style has changed, tell listeners
s->tellListeners(only_content_dependent);
s->tellListeners(change | (only_content_dependent ? CHANGE_ALREADY_PREPARED : 0) );
}
} catch (const ScriptError& e) {
// NOTE: don't handle errors now, we are likely in an onPaint handler