FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
image.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
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 
26 // 3rd party library includes
27 #include <SDL.h>
28 
29 // FIFE includes
30 // These includes are split up in two parts, separated by one empty line
31 // First block: files included from the FIFE root src directory
32 // Second block: files included from the same folder
33 #include "image.h"
34 
35 namespace FIFE {
36 
37  Image::Image(SDL_Surface* surface):
38  m_surface(NULL) {
39  reset(surface);
40  }
41 
42  Image::Image(const uint8_t* data, unsigned int width, unsigned int height):
43  m_surface(NULL) {
44  SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, width,height, 32,
45  RMASK, GMASK, BMASK ,AMASK);
46  SDL_LockSurface(surface);
47 
48  unsigned int size = width * height * 4;
49  uint8_t* pixeldata = static_cast<uint8_t*>(surface->pixels);
50  std::copy(data, data + size, pixeldata);
51  SDL_UnlockSurface(surface);
52  reset(surface);
53  }
54 
55  void Image::reset(SDL_Surface* surface) {
56  if( m_surface ) {
57  SDL_FreeSurface(m_surface);
58  }
59  m_surface = surface;
60  m_xshift = 0;
61  m_yshift = 0;
62  while (!m_clipstack.empty()) {
63  m_clipstack.pop();
64  }
65  m_area.x = m_area.y = m_area.w = m_area.h = 0;
66  m_surface = surface;
67  }
68 
69  Image::~Image() {
70  //assert(m_refcount == 0);
71  reset(NULL);
72  }
73 
74  SDL_Surface* Image::detachSurface() {
75  SDL_Surface* srf = m_surface;
76  m_surface = NULL;
77  return srf;
78  }
79 
80  unsigned int Image::getWidth() const {
81  if (!m_surface) {
82  return 0;
83  }
84  return m_surface->w;
85  }
86 
87  unsigned int Image::getHeight() const {
88  if (!m_surface) {
89  return 0;
90  }
91  return m_surface->h;
92  }
93 
94  const Rect& Image::getArea() {
95  m_area.w = getWidth();
96  m_area.h = getHeight();
97  return m_area;
98  }
99 
100  void Image::setXShift(int xshift) {
101  m_xshift = xshift;
102  }
103 
104  void Image::setYShift(int yshift) {
105  m_yshift = yshift;
106  }
107 
108  void Image::getPixelRGBA(int x, int y, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a) {
109  if ((x < 0) || (x >= m_surface->w) || (y < 0) || (y >= m_surface->h)) {
110  r = 0;
111  g = 0;
112  b = 0;
113  a = 0;
114  return;
115  }
116 
117  int bpp = m_surface->format->BytesPerPixel;
118  Uint8 *p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;
119  uint32_t pixel = 0;
120  switch(bpp) {
121  case 1:
122  pixel = *p;
123 
124  case 2:
125  pixel = *(Uint16 *)p;
126 
127  case 3:
128  if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
129  pixel = p[0] << 16 | p[1] << 8 | p[2];
130  } else {
131  pixel = p[0] | p[1] << 8 | p[2] << 16;
132  }
133 
134  case 4:
135  pixel = *(Uint32 *)p;
136  }
137  SDL_GetRGBA(pixel, m_surface->format, r, g, b, a);
138  }
139 
140  void Image::render(const Rect& rect, unsigned char alpha) {
141  render(rect, SDL_GetVideoSurface(), alpha);
142  }
143 
144  void Image::pushClipArea(const Rect& cliparea, bool clear) {
145  ClipInfo ci;
146  ci.r = cliparea;
147  ci.clearing = clear;
148  m_clipstack.push(ci);
149  setClipArea(cliparea, clear);
150  }
151 
152  void Image::popClipArea() {
153  assert(!m_clipstack.empty());
154  m_clipstack.pop();
155  if (m_clipstack.empty()) {
156  clearClipArea();
157  } else {
158  ClipInfo ci = m_clipstack.top();
159  setClipArea(ci.r, ci.clearing);
160  }
161  }
162 
163  const Rect& Image::getClipArea() const {
164  if (m_clipstack.empty()) {
165  return m_clipstack.top().r;
166  } else {
167  return m_area;
168  }
169  }
170 
172  setClipArea(m_area, true);
173  }
174 
175  void Image::saveAsPng(const std::string& filename, SDL_Surface& surface) {
176  FILE *fp;
177  png_structp pngptr;
178  png_infop infoptr;
179  int colortype;
180  png_bytep *rowpointers = NULL;
181 
182  fp = fopen(filename.c_str(), "wb");
183 
184  if (fp == NULL) {
185  return;
186  }
187 
188  //create the png file
189  pngptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
190  NULL, NULL, NULL);
191  if (pngptr == NULL) {
192  fclose(fp);
193  return;
194  }
195 
196  //create information struct
197  infoptr = png_create_info_struct(pngptr);
198  if (infoptr == NULL) {
199  fclose(fp);
200  png_destroy_write_struct(&pngptr, (png_infopp)NULL);
201  return;
202  }
203 
204  if (setjmp(png_jmpbuf(pngptr))) {
205  png_destroy_write_struct(&pngptr, &infoptr);
206  fclose(fp);
207  return;
208  }
209 
210  //initialize io
211  png_init_io(pngptr, fp);
212 
213  //lock the surface for access
214  SDL_LockSurface(&surface);
215 
216  colortype = PNG_COLOR_TYPE_RGB;
217  if(m_surface->format->palette){
218  colortype |= PNG_COLOR_TYPE_PALETTE;
219  }
220  else if (m_surface->format->Amask){
221  colortype |= PNG_COLOR_TYPE_RGB_ALPHA;
222  }
223  else{}
224 
225  png_set_IHDR(pngptr, infoptr, surface.w, surface.h, 8, colortype,
226  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
227 
228  png_write_info(pngptr, infoptr);
229  png_set_packing(pngptr);
230 
231  rowpointers = new png_bytep[surface.h];
232  for (int i = 0; i < surface.h; i++) {
233  rowpointers[i] = (png_bytep)(Uint8 *)surface.pixels + i*surface.pitch;
234  }
235  //write the image
236  png_write_image(pngptr, rowpointers);
237  png_write_end(pngptr, infoptr);
238 
239  SDL_UnlockSurface(&surface);
240  delete [] rowpointers;
241  png_destroy_write_struct(&pngptr, &infoptr);
242  fclose(fp);
243 
244  }
245 }