FIFE  be64c707dea6b3250bd4355bf5c825d25920087d
image.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2019 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):
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):
78  m_surface(NULL),
79  m_xshift(0),
80  m_yshift(0),
81  m_shared(false){
82  SDL_Surface* surface = SDL_CreateRGBSurface(0, 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(0, 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 
177  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(0, srcimg->getWidth(),
320  srcimg->getHeight(), 32, RMASK, GMASK, BMASK ,AMASK);
321  }
322  // disable blending
323  SDL_SetSurfaceBlendMode(srcimg->m_surface, SDL_BLENDMODE_NONE);
324  if(this->isSharedImage()) {
325  Rect const& rect = this->getSubImageRect();
326  SDL_Rect dstrect = {
327  static_cast<Sint16>(rect.x + xoffset),
328  static_cast<Sint16>(rect.y + yoffset),
329  static_cast<Uint16>(srcimg->getWidth()),
330  static_cast<Uint16>(srcimg->getHeight()) };
331  if(srcimg->isSharedImage()) {
332  Rect const& rect = srcimg->getSubImageRect();
333  SDL_Rect srcrect = {
334  static_cast<Sint16>(rect.x),
335  static_cast<Sint16>(rect.y),
336  static_cast<Uint16>(rect.w),
337  static_cast<Uint16>(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  } else {
343  SDL_Rect dstrect = {
344  static_cast<Sint16>(xoffset),
345  static_cast<Sint16>(yoffset),
346  static_cast<Uint16>(srcimg->getWidth()),
347  static_cast<Uint16>(srcimg->getHeight()) };
348  if(srcimg->isSharedImage()) {
349  Rect const& rect = srcimg->getSubImageRect();
350  SDL_Rect srcrect = {
351  static_cast<Sint16>(rect.x),
352  static_cast<Sint16>(rect.y),
353  static_cast<Uint16>(rect.w),
354  static_cast<Uint16>(rect.h) };
355  SDL_BlitSurface(srcimg->m_surface, &srcrect, m_surface, &dstrect);
356  } else {
357  SDL_BlitSurface(srcimg->m_surface, NULL, m_surface, &dstrect);
358  }
359  }
360  // enable blending
361  SDL_SetSurfaceBlendMode(srcimg->m_surface, SDL_BLENDMODE_BLEND);
362  }
363 
364  bool Image::putPixel(SDL_Surface* surface, int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
365  if ((x < 0) || (x >= surface->w) || (y < 0) || (y >= surface->h)) {
366  return false;
367  }
368 
369  int32_t bpp = surface->format->BytesPerPixel;
370  SDL_LockSurface(surface);
371  Uint8* p = (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
372  Uint32 pixel = SDL_MapRGBA(surface->format, r, g, b, a);
373  switch(bpp)
374  {
375  case 1:
376  *p = pixel;
377  break;
378 
379  case 2:
380  *(Uint16 *)p = pixel;
381  break;
382 
383  case 3:
384  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
385  p[0] = (pixel >> 16) & 0xff;
386  p[1] = (pixel >> 8) & 0xff;
387  p[2] = pixel & 0xff;
388  }
389  else {
390  p[0] = pixel & 0xff;
391  p[1] = (pixel >> 8) & 0xff;
392  p[2] = (pixel >> 16) & 0xff;
393  }
394  break;
395 
396  case 4:
397  *(Uint32 *)p = pixel;
398  break;
399  }
400  SDL_UnlockSurface(surface);
401  return true;
402  }
403 }
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:364
virtual void load()
Definition: image.cpp:124
int32_t m_xshift
Definition: image.h:162
SDL_Surface * m_surface
Definition: image.h:160
T h
Height of the rectangle.
Definition: rect.h:93
ImageLoader for some basic formats like jpeg, png etc.
Definition: imageloader.h:38
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
Rect getArea() const
Definition: image.cpp:176
const uint32_t RMASK
Definition: fife_stdint.h:53
const uint32_t AMASK
Definition: fife_stdint.h:56
virtual size_t getSize()
Definition: image.cpp:169
virtual ~Image()
Destructor.
Definition: image.cpp:120
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
uint32_t getHeight() const
Definition: image.cpp:160
virtual void load(IResource *res)
Definition: imageloader.cpp:44
const uint32_t BMASK
Definition: fife_stdint.h:55
ResourceState m_state
Definition: resource.h:81
T y
The Y Coordinate.
Definition: rect.h:87
Rect m_subimagerect
Definition: image.h:177
bool isSharedImage() const
Returns true if this image shares data with another one.
Definition: image.h:148
virtual void free()
Definition: image.cpp:135
bool m_shared
Definition: image.h:175
const Rect & getSubImageRect() const
Returns area of the image it occupies in the shared image.
Definition: image.h:152
virtual void load(IResource *resource)=0
unsigned int uint32_t
Definition: core.h:40
T w
Width of the rectangle.
Definition: rect.h:90
uint32_t getWidth() const
Definition: image.cpp:151
int32_t m_yshift
Definition: image.h:164