00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <cassert>
00024 #include <iostream>
00025 #include <sstream>
00026
00027
00028 #include <SDL.h>
00029
00030
00031
00032
00033
00034 #include "util/resource/resource.h"
00035 #include "loaders/native/video/imageloader.h"
00036
00037 #include "image.h"
00038
00039 namespace FIFE {
00040
00041 Image::Image(IResourceLoader* loader):
00042 IResource(createUniqueImageName(), loader),
00043 m_surface(NULL),
00044 m_xshift(0),
00045 m_yshift(0),
00046 m_shared(false){
00047 }
00048
00049 Image::Image(const std::string& name, IResourceLoader* loader):
00050 IResource(name, loader),
00051 m_surface(NULL),
00052 m_xshift(0),
00053 m_yshift(0),
00054 m_shared(false){
00055 }
00056
00057 Image::Image(SDL_Surface* surface):
00058 IResource(createUniqueImageName()),
00059 m_surface(NULL),
00060 m_xshift(0),
00061 m_yshift(0),
00062 m_shared(false){
00063 reset(surface);
00064 }
00065
00066 Image::Image(const std::string& name, SDL_Surface* surface):
00067 IResource(name),
00068 m_surface(NULL),
00069 m_xshift(0),
00070 m_yshift(0),
00071 m_shared(false){
00072 reset(surface);
00073 }
00074
00075
00076 Image::Image(const uint8_t* data, uint32_t width, uint32_t height):
00077 IResource(createUniqueImageName()),
00078 m_surface(NULL),
00079 m_xshift(0),
00080 m_yshift(0),
00081 m_shared(false){
00082 SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, width,height, 32,
00083 RMASK, GMASK, BMASK ,AMASK);
00084 SDL_LockSurface(surface);
00085
00086 uint32_t size = width * height * 4;
00087 uint8_t* pixeldata = static_cast<uint8_t*>(surface->pixels);
00088 std::copy(data, data + size, pixeldata);
00089 SDL_UnlockSurface(surface);
00090 reset(surface);
00091 }
00092
00093 Image::Image(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
00094 IResource(name),
00095 m_surface(NULL),
00096 m_xshift(0),
00097 m_yshift(0),
00098 m_shared(false) {
00099 SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, width,height, 32,
00100 RMASK, GMASK, BMASK ,AMASK);
00101 SDL_LockSurface(surface);
00102
00103 uint32_t size = width * height * 4;
00104 uint8_t* pixeldata = static_cast<uint8_t*>(surface->pixels);
00105 std::copy(data, data + size, pixeldata);
00106 SDL_UnlockSurface(surface);
00107 reset(surface);
00108 }
00109
00110 void Image::reset(SDL_Surface* surface) {
00111 if( m_surface && !m_shared) {
00112 SDL_FreeSurface(m_surface);
00113 }
00114
00115 m_xshift = 0;
00116 m_yshift = 0;
00117 m_surface = surface;
00118 }
00119
00120 Image::~Image() {
00121 reset(NULL);
00122 }
00123
00124 void Image::load() {
00125 if (m_loader){
00126 m_loader->load(this);
00127 }
00128 else {
00129 ImageLoader loader;
00130 loader.load(this);
00131 }
00132 m_state = IResource::RES_LOADED;
00133 }
00134
00135 void Image::free() {
00136 reset(NULL);
00137 m_state = IResource::RES_NOT_LOADED;
00138 }
00139
00140 SDL_Surface* Image::detachSurface() {
00141 SDL_Surface* srf = m_surface;
00142 m_surface = NULL;
00143 return srf;
00144 }
00145
00146 uint32_t Image::getWidth() const {
00147 if (m_shared) {
00148 return m_subimagerect.w;
00149 } else if (!m_surface) {
00150 return 0;
00151 }
00152 return m_surface->w;
00153 }
00154
00155 uint32_t Image::getHeight() const {
00156 if (m_shared) {
00157 return m_subimagerect.h;
00158 } else if (!m_surface) {
00159 return 0;
00160 }
00161 return m_surface->h;
00162 }
00163
00164 size_t Image::getSize() {
00165 if (!m_surface || m_shared) {
00166 return 0;
00167 }
00168 return m_surface->h * m_surface->pitch;
00169 }
00170
00171 const Rect& Image::getArea() const {
00172 static Rect r(0, 0, getWidth(), getHeight());
00173 return r;
00174 }
00175
00176 void Image::getPixelRGBA(int32_t x, int32_t y, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
00177 Uint8 *p;
00178
00179 assert(m_surface);
00180
00181 int32_t bpp = m_surface->format->BytesPerPixel;
00182
00183 if(!isSharedImage()) {
00184 if ((x < 0) || (x >= m_surface->w) || (y < 0) || (y >= m_surface->h)) {
00185 r = g = b = a = 0;
00186 return;
00187 }
00188 p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;
00189 } else {
00190 if ((x < 0) || ((x + m_subimagerect.x) >= m_surface->w) || (y < 0) || ((y + m_subimagerect.y) >= m_surface->h)) {
00191 r = g = b = a = 0;
00192 return;
00193 }
00194 p = (Uint8*)m_surface->pixels + (y + m_subimagerect.y) * m_surface->pitch + (x + m_subimagerect.x) * bpp;
00195 }
00196
00197 uint32_t pixel = 0;
00198 switch(bpp) {
00199 case 1:
00200 pixel = *p;
00201 break;
00202
00203 case 2:
00204 pixel = *(Uint16 *)p;
00205 break;
00206
00207 case 3:
00208 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00209 pixel = p[0] << 16 | p[1] << 8 | p[2];
00210 } else {
00211 pixel = p[0] | p[1] << 8 | p[2] << 16;
00212 }
00213 break;
00214
00215 case 4:
00216 pixel = *(Uint32 *)p;
00217 break;
00218 }
00219 SDL_GetRGBA(pixel, m_surface->format, r, g, b, a);
00220 }
00221
00222 void Image::saveImage(const std::string& filename) {
00223 saveAsPng(filename, *m_surface);
00224 }
00225
00226 void Image::saveAsPng(const std::string& filename, const SDL_Surface& surface) {
00227 FILE *fp;
00228 png_structp pngptr;
00229 png_infop infoptr;
00230 int32_t colortype;
00231 png_bytep *rowpointers = NULL;
00232
00233 fp = fopen(filename.c_str(), "wb");
00234
00235 if (fp == NULL) {
00236 return;
00237 }
00238
00239
00240 pngptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00241 NULL, NULL, NULL);
00242 if (pngptr == NULL) {
00243 fclose(fp);
00244 return;
00245 }
00246
00247
00248 infoptr = png_create_info_struct(pngptr);
00249 if (infoptr == NULL) {
00250 fclose(fp);
00251 png_destroy_write_struct(&pngptr, (png_infopp)NULL);
00252 return;
00253 }
00254
00255 if (setjmp(png_jmpbuf(pngptr))) {
00256 png_destroy_write_struct(&pngptr, &infoptr);
00257 fclose(fp);
00258 return;
00259 }
00260
00261
00262 png_init_io(pngptr, fp);
00263
00264
00265 SDL_LockSurface(const_cast<SDL_Surface*>(&surface));
00266
00267 colortype = PNG_COLOR_TYPE_RGB;
00268 if(surface.format->palette){
00269 colortype |= PNG_COLOR_TYPE_PALETTE;
00270 }
00271 else if (surface.format->Amask){
00272 colortype |= PNG_COLOR_TYPE_RGB_ALPHA;
00273 }
00274 else{}
00275
00276 png_set_IHDR(pngptr, infoptr, surface.w, surface.h, 8, colortype,
00277 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00278
00279 png_write_info(pngptr, infoptr);
00280 png_set_packing(pngptr);
00281
00282 rowpointers = new png_bytep[surface.h];
00283 for (int32_t i = 0; i < surface.h; i++) {
00284 rowpointers[i] = (png_bytep)(Uint8 *)surface.pixels + i*surface.pitch;
00285 }
00286
00287 png_write_image(pngptr, rowpointers);
00288 png_write_end(pngptr, infoptr);
00289
00290 SDL_UnlockSurface(const_cast<SDL_Surface*>(&surface));
00291 delete [] rowpointers;
00292 png_destroy_write_struct(&pngptr, &infoptr);
00293 fclose(fp);
00294 }
00295
00296 std::string Image::createUniqueImageName() {
00297
00298 static uint32_t uniqueNumber = 0;
00299 static std::string baseName = "image";
00300
00301 std::ostringstream oss;
00302 oss << uniqueNumber << "_" << baseName;
00303
00304 const std::string name = oss.str();
00305 ++uniqueNumber;
00306
00307 return name;
00308 }
00309
00310 void Image::copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr& srcimg){
00311 if (!srcimg->m_surface) {
00312 return;
00313 } else if (!m_surface) {
00314 m_surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, srcimg->getWidth(),
00315 srcimg->getHeight(), 32, RMASK, GMASK, BMASK ,AMASK);
00316 }
00317 SDL_SetAlpha(srcimg->m_surface, 0, 0);
00318 if(this->isSharedImage()) {
00319 Rect const& rect = this->getSubImageRect();
00320 SDL_Rect dstrect = {
00321 rect.x + xoffset, rect.y + yoffset,
00322 static_cast<Uint16>(srcimg->getWidth()),
00323 static_cast<Uint16>(srcimg->getHeight()) };
00324 if(srcimg->isSharedImage()) {
00325 Rect const& rect = srcimg->getSubImageRect();
00326 SDL_Rect srcrect = { rect.x, rect.y, rect.w, rect.h };
00327 SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
00328 } else {
00329 SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
00330 }
00331 } else {
00332 SDL_Rect dstrect = { xoffset, yoffset,
00333 static_cast<Uint16>(srcimg->getWidth()),
00334 static_cast<Uint16>(srcimg->getHeight()) };
00335 if(srcimg->isSharedImage()) {
00336 Rect const& rect = srcimg->getSubImageRect();
00337 SDL_Rect srcrect = { rect.x, rect.y, rect.w, rect.h };
00338 SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
00339 } else {
00340 SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
00341 }
00342 }
00343 SDL_SetAlpha(srcimg->m_surface, SDL_SRCALPHA, 0);
00344 }
00345
00346 bool Image::putPixel(SDL_Surface* surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00347 if ((x < 0) || (x >= surface->w) || (y < 0) || (y >= surface->h)) {
00348 return false;
00349 }
00350
00351 int32_t bpp = surface->format->BytesPerPixel;
00352 SDL_LockSurface(surface);
00353 Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
00354 Uint32 pixel = SDL_MapRGBA(surface->format, r, g, b, a);
00355 switch(bpp)
00356 {
00357 case 1:
00358 *p = pixel;
00359 break;
00360
00361 case 2:
00362 *(Uint16 *)p = pixel;
00363 break;
00364
00365 case 3:
00366 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00367 p[0] = (pixel >> 16) & 0xff;
00368 p[1] = (pixel >> 8) & 0xff;
00369 p[2] = pixel & 0xff;
00370 }
00371 else {
00372 p[0] = pixel & 0xff;
00373 p[1] = (pixel >> 8) & 0xff;
00374 p[2] = (pixel >> 16) & 0xff;
00375 }
00376 break;
00377
00378 case 4:
00379 *(Uint32 *)p = pixel;
00380 break;
00381 }
00382 SDL_UnlockSurface(surface);
00383 return true;
00384 }
00385 }