FIFE  2008.0
image.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2011 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"
35 #include "loaders/native/video/imageloader.h"
36 
37 #include "image.h"
38 
39 namespace FIFE {
40 
41  Image::Image(IResourceLoader* loader):
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  }
132  m_state = IResource::RES_LOADED;
133  }
134 
135  void Image::free() {
136  reset(NULL);
137  m_state = IResource::RES_NOT_LOADED;
138  }
139 
140  SDL_Surface* Image::detachSurface() {
141  SDL_Surface* srf = m_surface;
142  m_surface = NULL;
143  return srf;
144  }
145 
146  uint32_t Image::getWidth() const {
147  if (m_shared) {
148  return m_subimagerect.w;
149  } else if (!m_surface) {
150  return 0;
151  }
152  return m_surface->w;
153  }
154 
155  uint32_t Image::getHeight() const {
156  if (m_shared) {
157  return m_subimagerect.h;
158  } else if (!m_surface) {
159  return 0;
160  }
161  return m_surface->h;
162  }
163 
164  size_t Image::getSize() {
165  if (!m_surface || m_shared) {
166  return 0;
167  }
168  return m_surface->h * m_surface->pitch;
169  }
170 
171  const Rect& Image::getArea() const {
172  static Rect r(0, 0, getWidth(), getHeight());
173  return r;
174  }
175 
176  void Image::getPixelRGBA(int32_t x, int32_t y, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
177  Uint8 *p;
178 
179  assert(m_surface);
180 
181  int32_t bpp = m_surface->format->BytesPerPixel;
182 
183  if(!isSharedImage()) {
184  if ((x < 0) || (x >= m_surface->w) || (y < 0) || (y >= m_surface->h)) {
185  r = g = b = a = 0;
186  return;
187  }
188  p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;
189  } else {
190  if ((x < 0) || ((x + m_subimagerect.x) >= m_surface->w) || (y < 0) || ((y + m_subimagerect.y) >= m_surface->h)) {
191  r = g = b = a = 0;
192  return;
193  }
194  p = (Uint8*)m_surface->pixels + (y + m_subimagerect.y) * m_surface->pitch + (x + m_subimagerect.x) * bpp;
195  }
196 
197  uint32_t pixel = 0;
198  switch(bpp) {
199  case 1:
200  pixel = *p;
201  break;
202 
203  case 2:
204  pixel = *(Uint16 *)p;
205  break;
206 
207  case 3:
208  if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
209  pixel = p[0] << 16 | p[1] << 8 | p[2];
210  } else {
211  pixel = p[0] | p[1] << 8 | p[2] << 16;
212  }
213  break;
214 
215  case 4:
216  pixel = *(Uint32 *)p;
217  break;
218  }
219  SDL_GetRGBA(pixel, m_surface->format, r, g, b, a);
220  }
221 
222  void Image::saveImage(const std::string& filename) {
223  saveAsPng(filename, *m_surface);
224  }
225 
226  void Image::saveAsPng(const std::string& filename, const SDL_Surface& surface) {
227  FILE *fp;
228  png_structp pngptr;
229  png_infop infoptr;
230  int32_t colortype;
231  png_bytep *rowpointers = NULL;
232 
233  fp = fopen(filename.c_str(), "wb");
234 
235  if (fp == NULL) {
236  return;
237  }
238 
239  //create the png file
240  pngptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
241  NULL, NULL, NULL);
242  if (pngptr == NULL) {
243  fclose(fp);
244  return;
245  }
246 
247  //create information struct
248  infoptr = png_create_info_struct(pngptr);
249  if (infoptr == NULL) {
250  fclose(fp);
251  png_destroy_write_struct(&pngptr, (png_infopp)NULL);
252  return;
253  }
254 
255  if (setjmp(png_jmpbuf(pngptr))) {
256  png_destroy_write_struct(&pngptr, &infoptr);
257  fclose(fp);
258  return;
259  }
260 
261  //initialize io
262  png_init_io(pngptr, fp);
263 
264  // lock the surface for access (we strip it off of const but we promise not to modify it, just read)
265  SDL_LockSurface(const_cast<SDL_Surface*>(&surface));
266 
267  colortype = PNG_COLOR_TYPE_RGB;
268  if(surface.format->palette){
269  colortype |= PNG_COLOR_TYPE_PALETTE;
270  }
271  else if (surface.format->Amask){
272  colortype |= PNG_COLOR_TYPE_RGB_ALPHA;
273  }
274  else{}
275 
276  png_set_IHDR(pngptr, infoptr, surface.w, surface.h, 8, colortype,
277  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
278 
279  png_write_info(pngptr, infoptr);
280  png_set_packing(pngptr);
281 
282  rowpointers = new png_bytep[surface.h];
283  for (int32_t i = 0; i < surface.h; i++) {
284  rowpointers[i] = (png_bytep)(Uint8 *)surface.pixels + i*surface.pitch;
285  }
286  //write the image
287  png_write_image(pngptr, rowpointers);
288  png_write_end(pngptr, infoptr);
289 
290  SDL_UnlockSurface(const_cast<SDL_Surface*>(&surface));
291  delete [] rowpointers;
292  png_destroy_write_struct(&pngptr, &infoptr);
293  fclose(fp);
294  }
295 
296  std::string Image::createUniqueImageName() {
297  // automated counting for name generation, in case the user doesn't provide a name
298  static uint32_t uniqueNumber = 0;
299  static std::string baseName = "image";
300 
301  std::ostringstream oss;
302  oss << uniqueNumber << "_" << baseName;
303 
304  const std::string name = oss.str();
305  ++uniqueNumber;
306 
307  return name;
308  }
309 
310  void Image::copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr& srcimg){
311  if (!srcimg->m_surface) {
312  return;
313  } else if (!m_surface) {
314  m_surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, srcimg->getWidth(),
315  srcimg->getHeight(), 32, RMASK, GMASK, BMASK ,AMASK);
316  }
317  SDL_SetAlpha(srcimg->m_surface, 0, 0);
318  if(this->isSharedImage()) {
319  Rect const& rect = this->getSubImageRect();
320  SDL_Rect dstrect = {
321  rect.x + xoffset, rect.y + yoffset,
322  static_cast<Uint16>(srcimg->getWidth()),
323  static_cast<Uint16>(srcimg->getHeight()) };
324  if(srcimg->isSharedImage()) {
325  Rect const& rect = srcimg->getSubImageRect();
326  SDL_Rect srcrect = { rect.x, rect.y, rect.w, rect.h };
327  SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
328  } else {
329  SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
330  }
331  } else {
332  SDL_Rect dstrect = { xoffset, yoffset,
333  static_cast<Uint16>(srcimg->getWidth()),
334  static_cast<Uint16>(srcimg->getHeight()) };
335  if(srcimg->isSharedImage()) {
336  Rect const& rect = srcimg->getSubImageRect();
337  SDL_Rect srcrect = { rect.x, rect.y, rect.w, rect.h };
338  SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
339  } else {
340  SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
341  }
342  }
343  SDL_SetAlpha(srcimg->m_surface, SDL_SRCALPHA, 0);
344  }
345 
346  bool Image::putPixel(SDL_Surface* surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
347  if ((x < 0) || (x >= surface->w) || (y < 0) || (y >= surface->h)) {
348  return false;
349  }
350 
351  int32_t bpp = surface->format->BytesPerPixel;
352  SDL_LockSurface(surface);
353  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
354  Uint32 pixel = SDL_MapRGBA(surface->format, r, g, b, a);
355  switch(bpp)
356  {
357  case 1:
358  *p = pixel;
359  break;
360 
361  case 2:
362  *(Uint16 *)p = pixel;
363  break;
364 
365  case 3:
366  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
367  p[0] = (pixel >> 16) & 0xff;
368  p[1] = (pixel >> 8) & 0xff;
369  p[2] = pixel & 0xff;
370  }
371  else {
372  p[0] = pixel & 0xff;
373  p[1] = (pixel >> 8) & 0xff;
374  p[2] = (pixel >> 16) & 0xff;
375  }
376  break;
377 
378  case 4:
379  *(Uint32 *)p = pixel;
380  break;
381  }
382  SDL_UnlockSurface(surface);
383  return true;
384  }
385 }
Image(IResourceLoader *loader=0)
Definition: image.cpp:41
void reset(SDL_Surface *surface)
Definition: image.cpp:110
void saveImage(const std::string &filename)
Definition: image.cpp:222
const Rect & getSubImageRect() const
Definition: image.h:147
SDL_Surface * detachSurface()
Definition: image.cpp:140
static void saveAsPng(const std::string &filename, const SDL_Surface &surface)
Definition: image.cpp:226
virtual ~Image()
Definition: image.cpp:120
virtual void copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr &img)
Definition: image.cpp:310
bool isSharedImage() const
Definition: image.h:143
credit to phoku for his NodeDisplay example which the visitor code is adapted from ( he coded the qua...
Definition: soundclip.cpp:39