diff --git a/libxbrzscale.cpp b/libxbrzscale.cpp index 5623e73..b495ff2 100644 --- a/libxbrzscale.cpp +++ b/libxbrzscale.cpp @@ -18,23 +18,39 @@ #include "libxbrzscale.h" +#include +#include + +#ifndef XBRZLIB_RELATIVEPATHSDL #include #include #include #include -#include +#else +#include "SDL_endian.h" +#include "SDL_error.h" +#include "SDL_pixels.h" +#include "SDL_surface.h" +#endif #include "xbrz/xbrz.h" -//#include -//#include -//#include "SDL.h" -//#include "SDL_image.h" -//#include "xbrz/xbrz.h" - bool libxbrzscale::bEnableOutput=false; -Uint32 libxbrzscale::SDL_GetPixel(SDL_Surface *surface, int x, int y) +bool libxbrzscale::bDbgMsg=false; + +bool libxbrzscale::bUseCache=false; + +bool libxbrzscale::bFreeInputSurfaceAfterScale=true; +bool libxbrzscale::bFreeOutputSurfaceAfterScale=true; + +#ifdef XBRZLIB_NOINLINEGETSETPIX //this may be required to let some compillers linking actually work w/o error: "undefined reference to" these +#define XBRZLIB_GSPINLINE +#else +#define XBRZLIB_GSPINLINE inline +#endif + +XBRZLIB_GSPINLINE Uint32 libxbrzscale::SDL_GetPixel(SDL_Surface *surface, int x, int y) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to retrieve */ @@ -61,7 +77,7 @@ Uint32 libxbrzscale::SDL_GetPixel(SDL_Surface *surface, int x, int y) } } -void libxbrzscale::SDL_PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) +XBRZLIB_GSPINLINE void libxbrzscale::SDL_PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ @@ -96,6 +112,7 @@ void libxbrzscale::SDL_PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel SDL_Surface* libxbrzscale::createARGBSurface(int w, int h) { + if(bDbgMsg)printf("Creating SDL RGB surface w=%d h=%d\n",w,h); return SDL_CreateRGBSurface(0, w, h, 32, 0xff0000U, 0xff00U, 0xffU, 0xff000000U); } @@ -134,8 +151,37 @@ void displayImage(SDL_Surface* surface, const char* message) { } */ -uint32_t* libxbrzscale::surfaceToUint32(SDL_Surface* img){ - uint32_t *data = new uint32_t[img->w * img->h]; + +unsigned long lUInt32ImgCacheSizeIN=0; +unsigned long lUInt32ImgCacheSizeOUT=0; +uint32_t* pUInt32ImgCacheIN=NULL; +uint32_t* pUInt32ImgCacheOUT=NULL; +void DeleteCache(bool bIn){ + if(bIn){ + delete [] pUInt32ImgCacheIN; + pUInt32ImgCacheIN=NULL; + lUInt32ImgCacheSizeIN=0; + }else{ + delete [] pUInt32ImgCacheOUT; + pUInt32ImgCacheOUT=NULL; + lUInt32ImgCacheSizeOUT=0; + } +} +uint32_t* GetImgUint32Cache(bool bIn, unsigned long lSize){ //as that memory deletion wont happen promptly, it may consume too much memory too fast unnecessarily becoming a bottle neck on performance + if(lSize > (bIn?lUInt32ImgCacheSizeIN:lUInt32ImgCacheSizeOUT)){ + if(libxbrzscale::isDbgMsg())std::cerr<<"libxBRZ: increasing "<<(bIn?"IN":"OUT")<<" image cache to "<w * img->h); int x, y, offset=0; Uint8 r, g, b, a; @@ -180,29 +226,51 @@ void libxbrzscale::uint32toSurface(uint32_t* ui32src, SDL_Surface* dst_img){ } SDL_Surface* libxbrzscale::scale(SDL_Surface* src_img, int scale){ + return libxbrzscale::scale(NULL, src_img, scale); +} +/** + * dst_img if not null may be re-used, and is also returned + */ +SDL_Surface* libxbrzscale::scale(SDL_Surface* dst_imgCache, SDL_Surface* src_img, int scale){ + if(scale<2 || scale>6){ + fprintf(stderr, "invalid stretch value min=2, max=6, requested=%d\n", scale); + return NULL; + } + int src_width = src_img->w; int src_height = src_img->h; int dst_width = src_width * scale; int dst_height = src_height * scale; - uint32_t *in_data = surfaceToUint32(src_img); - SDL_FreeSurface(src_img); + uint32_t *in_data = surfaceToUint32(true, src_img); + if(bFreeInputSurfaceAfterScale && src_img!=NULL && src_img->refcount>0){ + SDL_FreeSurface(src_img); //previous INPUT surface + src_img=NULL; //just to prevent future troubles here, but pointless outside here + } if(bEnableOutput)printf("Scaling image...\n"); - uint32_t* dest = new uint32_t[dst_width * dst_height]; + uint32_t* dest = GetImgUint32Cache(false, dst_width * dst_height); xbrz::scale(scale, in_data, dest, src_width, src_height, xbrz::ColorFormat::ARGB); - delete [] in_data; + if(!bUseCache){DeleteCache(true);in_data=NULL;} if(bEnableOutput)printf("Saving image...\n"); - SDL_Surface* dst_img = createARGBSurface(dst_width, dst_height); - if (!dst_img) { - delete [] dest; - if(bEnableOutput)fprintf(stderr, "Failed to create SDL surface: %s\n", SDL_GetError()); + + if(dst_imgCache==NULL || dst_imgCache->w!=dst_width || dst_imgCache->h!=dst_height || dst_imgCache->refcount==0){ + if(bFreeOutputSurfaceAfterScale && dst_imgCache!=NULL && dst_imgCache->refcount>0){ + SDL_FreeSurface(dst_imgCache); //previous OUTPUT surface + } + + dst_imgCache = createARGBSurface(dst_width, dst_height); + } + + if (!dst_imgCache) { + if(!bUseCache){DeleteCache(false);dest=NULL;} + fprintf(stderr, "Failed to create SDL surface: %s\n", SDL_GetError()); //error messages must always output return NULL; } - uint32toSurface(dest,dst_img); + uint32toSurface(dest,dst_imgCache); - return dst_img; + return dst_imgCache; } diff --git a/libxbrzscale.h b/libxbrzscale.h index a20b1d9..a9b3c9a 100644 --- a/libxbrzscale.h +++ b/libxbrzscale.h @@ -16,20 +16,36 @@ * along with this program. If not, see . */ +#ifndef XBRZLIB_RELATIVEPATHSDL #include +#else +#include "SDL_stdinc.h" +#endif struct SDL_Surface; class libxbrzscale { public: - static inline Uint32 SDL_GetPixel(SDL_Surface *surface, int x, int y); - static inline void SDL_PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + static Uint32 SDL_GetPixel(SDL_Surface *surface, int x, int y); + static void SDL_PutPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); static SDL_Surface* createARGBSurface(int w, int h); static SDL_Surface* scale(SDL_Surface* src_img,int scale); - static void setEnableOutput(bool b){bEnableOutput=true;}; - static uint32_t* surfaceToUint32(SDL_Surface* img); + static SDL_Surface* scale(SDL_Surface* dst_imgCache,SDL_Surface* src_img,int scale); + static void setEnableOutput(bool b){bEnableOutput=b;}; + static void setDebugMsg(bool b){bDbgMsg=b;}; + static void setFreeSurfaceAfterScale(bool bInputSurface,bool bOutputSurface){ + bFreeInputSurfaceAfterScale=bInputSurface; + bFreeOutputSurfaceAfterScale=bOutputSurface; + }; + static void setUseCache(bool b){bUseCache=b;}; + static uint32_t* surfaceToUint32(bool bIn, SDL_Surface* img); static void uint32toSurface(uint32_t* dest, SDL_Surface* dst_img); + static bool isDbgMsg(){return bDbgMsg;} private: static bool bEnableOutput; + static bool bDbgMsg; + static bool bUseCache; + static bool bFreeInputSurfaceAfterScale; + static bool bFreeOutputSurfaceAfterScale; };