FIFE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
image.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2013 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <cassert>
24 #include <iostream>
25 #include <sstream>
26 
27 // 3rd party library includes
28 #include <SDL.h>
29 
30 // FIFE includes
31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder
34 #include "util/resource/resource.h"
36 
37 #include "image.h"
38 
39 namespace FIFE {
40 
42  IResource(createUniqueImageName(), loader),
43  m_surface(NULL),
44  m_xshift(0),
45  m_yshift(0),
46  m_shared(false){
47  }
48 
49  Image::Image(const std::string& name, IResourceLoader* loader):
50  IResource(name, loader),
51  m_surface(NULL),
52  m_xshift(0),
53  m_yshift(0),
54  m_shared(false){
55  }
56 
57  Image::Image(SDL_Surface* surface):
58  IResource(createUniqueImageName()),
59  m_surface(NULL),
60  m_xshift(0),
61  m_yshift(0),
62  m_shared(false){
63  reset(surface);
64  }
65 
66  Image::Image(const std::string& name, SDL_Surface* surface):
67  IResource(name),
68  m_surface(NULL),
69  m_xshift(0),
70  m_yshift(0),
71  m_shared(false){
72  reset(surface);
73  }
74 
75  //@todo make a private function to handle this
76  Image::Image(const uint8_t* data, uint32_t width, uint32_t height):
77  IResource(createUniqueImageName()),
78  m_surface(NULL),
79  m_xshift(0),
80  m_yshift(0),
81  m_shared(false){
82  SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, width,height, 32,
83  RMASK, GMASK, BMASK ,AMASK);
84  SDL_LockSurface(surface);
85 
86  uint32_t size = width * height * 4;
87  uint8_t* pixeldata = static_cast<uint8_t*>(surface->pixels);
88  std::copy(data, data + size, pixeldata);
89  SDL_UnlockSurface(surface);
90  reset(surface);
91  }
92 
93  Image::Image(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
94  IResource(name),
95  m_surface(NULL),
96  m_xshift(0),
97  m_yshift(0),
98  m_shared(false) {
99  SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, width,height, 32,
100  RMASK, GMASK, BMASK ,AMASK);
101  SDL_LockSurface(surface);
102 
103  uint32_t size = width * height * 4;
104  uint8_t* pixeldata = static_cast<uint8_t*>(surface->pixels);
105  std::copy(data, data + size, pixeldata);
106  SDL_UnlockSurface(surface);
107  reset(surface);
108  }
109 
110  void Image::reset(SDL_Surface* surface) {
111  if( m_surface && !m_shared) {
112  SDL_FreeSurface(m_surface);
113  }
114 
115  m_xshift = 0;
116  m_yshift = 0;
117  m_surface = surface;
118  }
119 
121  reset(NULL);
122  }
123 
124  void Image::load() {
125  if (m_loader){
126  m_loader->load(this);
127  }
128  else {
129  ImageLoader loader;
130  loader.load(this);
131  }
133  }
134 
135  void Image::free() {
136  // save the image offsets
137  int32_t xshift = m_xshift;
138  int32_t yshift = m_yshift;
139  reset(NULL);
140  m_xshift = xshift;
141  m_yshift = yshift;
143  }
144 
145  SDL_Surface* Image::detachSurface() {
146  SDL_Surface* srf = m_surface;
147  m_surface = NULL;
148  return srf;
149  }
150 
152  if (m_shared) {
153  return m_subimagerect.w;
154  } else if (!m_surface) {
155  return 0;
156  }
157  return m_surface->w;
158  }
159 
161  if (m_shared) {
162  return m_subimagerect.h;
163  } else if (!m_surface) {
164  return 0;
165  }
166  return m_surface->h;
167  }
168 
169  size_t Image::getSize() {
170  if (!m_surface || m_shared) {
171  return 0;
172  }
173  return m_surface->h * m_surface->pitch;
174  }
175 
176  const Rect& Image::getArea() const {
177  static Rect r(0, 0, getWidth(), getHeight());
178  return r;
179  }
180 
181  void Image::getPixelRGBA(int32_t x, int32_t y, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
182  Uint8 *p;
183 
184  assert(m_surface);
185 
186  int32_t bpp = m_surface->format->BytesPerPixel;
187 
188  if(!isSharedImage()) {
189  if ((x < 0) || (x >= m_surface->w) || (y < 0) || (y >= m_surface->h)) {
190  r = g = b = a = 0;
191  return;
192  }
193  p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;
194  } else {
195  if ((x < 0) || ((x + m_subimagerect.x) >= m_surface->w) || (y < 0) || ((y + m_subimagerect.y) >= m_surface->h)) {
196  r = g = b = a = 0;
197  return;
198  }
199  p = (Uint8*)m_surface->pixels + (y + m_subimagerect.y) * m_surface->pitch + (x + m_subimagerect.x) * bpp;
200  }
201 
202  uint32_t pixel = 0;
203  switch(bpp) {
204  case 1:
205  pixel = *p;
206  break;
207 
208  case 2:
209  pixel = *(Uint16 *)p;
210  break;
211 
212  case 3:
213  if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
214  pixel = p[0] << 16 | p[1] << 8 | p[2];
215  } else {
216  pixel = p[0] | p[1] << 8 | p[2] << 16;
217  }
218  break;
219 
220  case 4:
221  pixel = *(Uint32 *)p;
222  break;
223  }
224  SDL_GetRGBA(pixel, m_surface->format, r, g, b, a);
225  }
226 
227  void Image::saveImage(const std::string& filename) {
228  saveAsPng(filename, *m_surface);
229  }
230 
231  void Image::saveAsPng(const std::string& filename, const SDL_Surface& surface) {
232  FILE *fp;
233  png_structp pngptr;
234  png_infop infoptr;
235  int32_t colortype;
236  png_bytep *rowpointers = NULL;
237 
238  fp = fopen(filename.c_str(), "wb");
239 
240  if (fp == NULL) {
241  return;
242  }
243 
244  //create the png file
245  pngptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
246  NULL, NULL, NULL);
247  if (pngptr == NULL) {
248  fclose(fp);
249  return;
250  }
251 
252  //create information struct
253  infoptr = png_create_info_struct(pngptr);
254  if (infoptr == NULL) {
255  fclose(fp);
256  png_destroy_write_struct(&pngptr, (png_infopp)NULL);
257  return;
258  }
259 
260  if (setjmp(png_jmpbuf(pngptr))) {
261  png_destroy_write_struct(&pngptr, &infoptr);
262  fclose(fp);
263  return;
264  }
265 
266  //initialize io
267  png_init_io(pngptr, fp);
268 
269  // lock the surface for access (we strip it off of const but we promise not to modify it, just read)
270  SDL_LockSurface(const_cast<SDL_Surface*>(&surface));
271 
272  colortype = PNG_COLOR_TYPE_RGB;
273  if(surface.format->palette){
274  colortype |= PNG_COLOR_TYPE_PALETTE;
275  }
276  else if (surface.format->Amask){
277  colortype |= PNG_COLOR_TYPE_RGB_ALPHA;
278  }
279  else{}
280 
281  png_set_IHDR(pngptr, infoptr, surface.w, surface.h, 8, colortype,
282  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
283 
284  png_write_info(pngptr, infoptr);
285  png_set_packing(pngptr);
286 
287  rowpointers = new png_bytep[surface.h];
288  for (int32_t i = 0; i < surface.h; i++) {
289  rowpointers[i] = (png_bytep)(Uint8 *)surface.pixels + i*surface.pitch;
290  }
291  //write the image
292  png_write_image(pngptr, rowpointers);
293  png_write_end(pngptr, infoptr);
294 
295  SDL_UnlockSurface(const_cast<SDL_Surface*>(&surface));
296  delete [] rowpointers;
297  png_destroy_write_struct(&pngptr, &infoptr);
298  fclose(fp);
299  }
300 
302  // automated counting for name generation, in case the user doesn't provide a name
303  static uint32_t uniqueNumber = 0;
304  static std::string baseName = "image";
305 
306  std::ostringstream oss;
307  oss << uniqueNumber << "_" << baseName;
308 
309  const std::string name = oss.str();
310  ++uniqueNumber;
311 
312  return name;
313  }
314 
315  void Image::copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr& srcimg){
316  if (!srcimg->m_surface) {
317  return;
318  } else if (!m_surface) {
319  m_surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, srcimg->getWidth(),
320  srcimg->getHeight(), 32, RMASK, GMASK, BMASK ,AMASK);
321  }
322  SDL_SetAlpha(srcimg->m_surface, 0, 0);
323  if(this->isSharedImage()) {
324  Rect const& rect = this->getSubImageRect();
325  SDL_Rect dstrect = {
326  static_cast<Sint16>(rect.x + xoffset),
327  static_cast<Sint16>(rect.y + yoffset),
328  static_cast<Uint16>(srcimg->getWidth()),
329  static_cast<Uint16>(srcimg->getHeight()) };
330  if(srcimg->isSharedImage()) {
331  Rect const& rect = srcimg->getSubImageRect();
332  SDL_Rect srcrect = {
333  static_cast<Sint16>(rect.x),
334  static_cast<Sint16>(rect.y),
335  static_cast<Uint16>(rect.w),
336  static_cast<Uint16>(rect.h) };
337  SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
338  } else {
339  SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
340  }
341  } else {
342  SDL_Rect dstrect = {
343  static_cast<Sint16>(xoffset),
344  static_cast<Sint16>(yoffset),
345  static_cast<Uint16>(srcimg->getWidth()),
346  static_cast<Uint16>(srcimg->getHeight()) };
347  if(srcimg->isSharedImage()) {
348  Rect const& rect = srcimg->getSubImageRect();
349  SDL_Rect srcrect = {
350  static_cast<Sint16>(rect.x),
351  static_cast<Sint16>(rect.y),
352  static_cast<Uint16>(rect.w),
353  static_cast<Uint16>(rect.h) };
354  SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
355  } else {
356  SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
357  }
358  }
359  SDL_SetAlpha(srcimg->m_surface, SDL_SRCALPHA, 0);
360  }
361 
362  bool Image::putPixel(SDL_Surface* surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
363  if ((x < 0) || (x >= surface->w) || (y < 0) || (y >= surface->h)) {
364  return false;
365  }
366 
367  int32_t bpp = surface->format->BytesPerPixel;
368  SDL_LockSurface(surface);
369  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
370  Uint32 pixel = SDL_MapRGBA(surface->format, r, g, b, a);
371  switch(bpp)
372  {
373  case 1:
374  *p = pixel;
375  break;
376 
377  case 2:
378  *(Uint16 *)p = pixel;
379  break;
380 
381  case 3:
382  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
383  p[0] = (pixel >> 16) & 0xff;
384  p[1] = (pixel >> 8) & 0xff;
385  p[2] = pixel & 0xff;
386  }
387  else {
388  p[0] = pixel & 0xff;
389  p[1] = (pixel >> 8) & 0xff;
390  p[2] = (pixel >> 16) & 0xff;
391  }
392  break;
393 
394  case 4:
395  *(Uint32 *)p = pixel;
396  break;
397  }
398  SDL_UnlockSurface(surface);
399  return true;
400  }
401 }
std::string createUniqueImageName()
Definition: image.cpp:301
Image(IResourceLoader *loader=0)
Constructor.
Definition: image.cpp:41
void reset(SDL_Surface *surface)
Resets the image to default values (including the x and y shift values), frees the current surface an...
Definition: image.cpp:110
void saveImage(const std::string &filename)
Saves the image using given filename.
Definition: image.cpp:227
static bool putPixel(SDL_Surface *surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Definition: image.cpp:362
virtual void load()
Definition: image.cpp:124
int32_t m_xshift
Definition: image.h:161
SDL_Surface * m_surface
Definition: image.h:159
T h
Height of the rectangle.
Definition: rect.h:93
ImageLoader for some basic formats like jpeg, png etc.
Definition: imageloader.h:38
const Rect & getSubImageRect() const
Returns area of the image it occupies in the shared image.
Definition: image.h:151
T x
The X Coordinate.
Definition: rect.h:84
SDL_Surface * detachSurface()
Removes underlying SDL_Surface from the image (if exists) and returns this.
Definition: image.cpp:145
static void saveAsPng(const std::string &filename, const SDL_Surface &surface)
Saves the SDL_Surface to png format.
Definition: image.cpp:231
void getPixelRGBA(int32_t x, int32_t y, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a)
Definition: image.cpp:181
IResourceLoader * m_loader
Definition: resource.h:80
const uint32_t RMASK
Definition: fife_stdint.h:53
const uint32_t AMASK
Definition: fife_stdint.h:56
const Rect & getArea() const
Definition: image.cpp:176
virtual size_t getSize()
Definition: image.cpp:169
virtual ~Image()
Destructor.
Definition: image.cpp:120
uint32_t getHeight() const
Definition: image.cpp:160
unsigned char uint8_t
Definition: core.h:38
const uint32_t GMASK
Definition: fife_stdint.h:54
virtual void copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr &img)
Copies given image into this one with respect to given offsets.
Definition: image.cpp:315
virtual void load(IResource *res)
Definition: imageloader.cpp:45
const uint32_t BMASK
Definition: fife_stdint.h:55
uint32_t getWidth() const
Definition: image.cpp:151
ResourceState m_state
Definition: resource.h:81
T y
The Y Coordinate.
Definition: rect.h:87
Rect m_subimagerect
Definition: image.h:176
bool isSharedImage() const
Returns true if this image shares data with another one.
Definition: image.h:147
virtual void free()
Definition: image.cpp:135
bool m_shared
Definition: image.h:174
virtual void load(IResource *resource)=0
unsigned int uint32_t
Definition: core.h:40
T w
Width of the rectangle.
Definition: rect.h:90
int32_t m_yshift
Definition: image.h:163