diff options
author | Ira Rice <irarice@gmail.com> | 2009-03-17 20:18:41 -0600 |
---|---|---|
committer | Ira Rice <irarice@gmail.com> | 2009-03-17 20:18:41 -0600 |
commit | 72daf0bf49c0ff994aeff357f6e52140887bce30 (patch) | |
tree | 6965511cc5bbede09526c115d43fc1465f39f7de /src/resources/image.cpp | |
parent | a1eb62126bae54557e03682cac70c8331e359e01 (diff) | |
download | mana-72daf0bf49c0ff994aeff357f6e52140887bce30.tar.gz mana-72daf0bf49c0ff994aeff357f6e52140887bce30.tar.bz2 mana-72daf0bf49c0ff994aeff357f6e52140887bce30.tar.xz mana-72daf0bf49c0ff994aeff357f6e52140887bce30.zip |
Added an image merge feature loosely based on a merge function found in
the open source project Wormux. To improve SDL performance, the number
of layers that are pushed out to the hardware or software buffers should
be reduced, which is where this function comes into play, as it combines
two surfaces together so that the number of blit operations is reduced.
This function is currently not used, but will be used once a good way to
link each of the target systems is determined so that it only initiates
when SDL is enabled, as well as making sure that each hook that uses
this function is benefiting from it sufficiently. At the moment, it's
suspected that the particle engine will likely be the most likely to
benefit from this function, followed by tile drawing, then sprite drawing.
Signed-off-by: Ira Rice <irarice@gmail.com>
Diffstat (limited to 'src/resources/image.cpp')
-rw-r--r-- | src/resources/image.cpp | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 7a15b762..cff40197 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -26,6 +26,7 @@ #include "image.h" #include "../log.h" +#include "../position.h" #ifdef USE_OPENGL bool Image::mUseOpenGL = false; @@ -47,8 +48,7 @@ Image::Image(SDL_Surface *image): } #ifdef USE_OPENGL -Image::Image(GLuint glimage, int width, int height, - int texWidth, int texHeight): +Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight): mGLImage(glimage), mTexWidth(texWidth), mTexHeight(texHeight), @@ -316,6 +316,81 @@ void Image::setAlpha(float a) } } +Image* Image::merge(Image* image, const Position& pos) +{ + SDL_Surface* surface = new SDL_Surface(*(image->mImage)); + + Uint32 surface_pix, cur_pix; + Uint8 r, g, b, a, p_r, p_g, p_b, p_a; + double f_a, f_ca, f_pa; + SDL_PixelFormat *current_fmt = mImage->format; + SDL_PixelFormat *surface_fmt = surface->format; + int current_offset, surface_offset; + Position offset(0, 0); + + SDL_LockSurface(surface); + SDL_LockSurface(mImage); + // for each pixel lines of a source image + for (offset.x = (pos.x > 0 ? 0 : -pos.x); offset.x < image->getWidth() && + pos.x + offset.x < getWidth(); offset.x++) + { + for (offset.y = (pos.y > 0 ? 0 : -pos.y); offset.y < image->getHeight() + && pos.y + offset.y < getHeight(); offset.y++) + { + // Computing offset on both images + current_offset = (pos.y + offset.y) * getWidth() + pos.x + offset.x; + surface_offset = offset.y * surface->w + offset.x; + + // Retrieving a pixel to merge + surface_pix = ((Uint32*) surface->pixels)[surface_offset]; + cur_pix = ((Uint32*) mImage->pixels)[current_offset]; + + // Retreiving each channel of the pixel using pixel format + r = (Uint8)(((surface_pix & surface_fmt->Rmask) >> + surface_fmt->Rshift) << surface_fmt->Rloss); + g = (Uint8)(((surface_pix & surface_fmt->Gmask) >> + surface_fmt->Gshift) << surface_fmt->Gloss); + b = (Uint8)(((surface_pix & surface_fmt->Bmask) >> + surface_fmt->Bshift) << surface_fmt->Bloss); + a = (Uint8)(((surface_pix & surface_fmt->Amask) >> + surface_fmt->Ashift) << surface_fmt->Aloss); + + // Retreiving previous alpha value + p_a = (Uint8)(((cur_pix & current_fmt->Amask) >> + current_fmt->Ashift) << current_fmt->Aloss); + + // new pixel with no alpha or nothing on previous pixel + if (a == SDL_ALPHA_OPAQUE || (p_a == 0 && a > 0)) + ((Uint32 *)(surface->pixels))[current_offset] = + SDL_MapRGBA(current_fmt, r, g, b, a); + else if (a > 0) + { // alpha is lower => merge color with previous value + f_a = (double) a / 255.0; + f_ca = 1.0 - f_a; + f_pa = (double) p_a / 255.0; + p_r = (Uint8)(((cur_pix & current_fmt->Rmask) >> + current_fmt->Rshift) << current_fmt->Rloss); + p_g = (Uint8)(((cur_pix & current_fmt->Gmask) >> + current_fmt->Gshift) << current_fmt->Gloss); + p_b = (Uint8)(((cur_pix & current_fmt->Bmask) >> + current_fmt->Bshift) << current_fmt->Bloss); + r = (Uint8)((double) p_r * f_ca * f_pa + (double)r * f_a); + g = (Uint8)((double) p_g * f_ca * f_pa + (double)g * f_a); + b = (Uint8)((double) p_b * f_ca * f_pa + (double)b * f_a); + a = (a > p_a ? a : p_a); + ((Uint32 *)(surface->pixels))[current_offset] = + SDL_MapRGBA(current_fmt, r, g, b, a); + } + } + } + SDL_UnlockSurface(surface); + SDL_UnlockSurface(mImage); + + Image* newImage = new Image(surface); + + return newImage; +} + float Image::getAlpha() { return mAlpha; |