FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
glimage.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 // 3rd party library includes
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "util/structures/rect.h"
32 #include "video/sdl/sdlimage.h"
33 #include "video/renderbackend.h"
34 
35 #include "glimage.h"
36 
37 namespace FIFE {
38  GLImage::GLImage(SDL_Surface* surface):
39  Image(surface) {
40  m_sdlimage = new SDLImage(surface);
41 
42  m_textureids = NULL;
43 
44  resetGlimage();
45  }
46 
47  GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height):
48  Image(data, width, height) {
49  assert(m_surface);
50  m_sdlimage = new SDLImage(m_surface);
51 
52  m_textureids = NULL;
53 
54  resetGlimage();
55  }
56 
57  GLImage::~GLImage() {
58  // remove surface so that deletion happens correctly (by base class destructor)
59  m_sdlimage->detachSurface();
60  delete m_sdlimage;
61 
62  cleanup();
63  }
64 
66  resetGlimage();
67  }
68 
69  void GLImage::resetGlimage() {
70  cleanup();
71 
72  m_chunk_size_w = 0;
73  m_chunk_size_h = 0;
74 
75  m_colorkey = RenderBackend::instance()->getColorKey();
76  }
77 
78  void GLImage::cleanup() {
79  if (m_textureids) {
80  glDeleteTextures(1, &m_textureids[0]);
81 
82  delete[] m_textureids;
83  m_textureids = NULL;
84  }
85 
86  m_col_tex_coord = 0;
87  m_row_tex_coord = 0;
88  }
89 
90  void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
91  if (!m_textureids) {
92  generateGLTexture();
93  }
94 
95  //not on the screen. dont render
96  if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
97  return;
98  }
99 
100  //completely transparent so dont bother rendering
101  if (0 == alpha) {
102  return;
103  }
104 
105  // the amount of "zooming" for the image
106  float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
107  float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
108 
109  // apply the scale to the width and height of the image
110  uint16_t w = static_cast<int>(round(scale_x*m_surface->w));
111  uint16_t h = static_cast<int>(round(scale_y*m_surface->h));
112 
113  // setting transparency for the whole primitive:
114  glColor4ub( 255, 255, 255, alpha );
115 
116  glEnable(GL_TEXTURE_2D);
117  glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
118 
119  glBegin(GL_QUADS);
120  glTexCoord2f(0.0f, 0.0f);
121  glVertex2i(rect.x, rect.y);
122 
123  glTexCoord2f(0.0f, m_row_tex_coord);
124  glVertex2i(rect.x, rect.y + h);
125 
126  glTexCoord2f(m_col_tex_coord, m_row_tex_coord);
127  glVertex2i(rect.x + w, rect.y + h);
128 
129  glTexCoord2f(m_col_tex_coord, 0.0f);
130  glVertex2i(rect.x + w, rect.y);
131  glEnd();
132  glDisable(GL_TEXTURE_2D);
133 
134  }
135 
136  void GLImage::generateGLTexture() {
137  const unsigned int width = m_surface->w;
138  const unsigned int height = m_surface->h;
139 
140  //calculate the nearest larger power of 2
141  m_chunk_size_w = nextPow2(width);
142  m_chunk_size_h = nextPow2(height);
143 
144  // used to calculate the fill ratio for given chunk
145  m_col_tex_coord = static_cast<float>(m_surface->w%m_chunk_size_w) / static_cast<float>(m_chunk_size_w);
146  m_row_tex_coord = static_cast<float>(m_surface->h%m_chunk_size_h) / static_cast<float>(m_chunk_size_h);
147 
148  if (m_col_tex_coord == 0.0f){
149  m_col_tex_coord = 1.0f;
150  }
151 
152  if (m_row_tex_coord == 0.0f){
153  m_row_tex_coord = 1.0f;
154  }
155 
156  uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
157  int pitch = m_surface->pitch;
158 
159 
160  assert(!m_textureids);
161 
162  m_textureids = new GLuint[1];
163  memset(m_textureids, 0x00, 1*sizeof(GLuint));
164 
165 
166  uint32_t* oglbuffer = new uint32_t[m_chunk_size_w * m_chunk_size_h];
167  memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint32_t));
168 
169  for (unsigned int y = 0; y < height; ++y) {
170  for (unsigned int x = 0; x < width; ++x) {
171  unsigned int pos = (y * pitch) + (x * 4);
172 
173  uint8_t r = data[pos + 3];
174  uint8_t g = data[pos + 2];
175  uint8_t b = data[pos + 1];
176  uint8_t a = data[pos + 0];
177 
178  if (RenderBackend::instance()->isColorKeyEnabled()) {
179  // only set alpha to zero if colorkey feature is enabled
180  if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
181  a = 0;
182  }
183  }
184 
185  oglbuffer[(y*m_chunk_size_w) + x] = r | (g << 8) | (b << 16) | (a<<24);
186  }
187  }
188 
189  // get texture id from opengl
190  glGenTextures(1, &m_textureids[0]);
191  // set focus on that texture
192  glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
193  // set filters for texture
194  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
195  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
196  // transfer data from sdl buffer
197  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_chunk_size_w, m_chunk_size_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
198 
199  delete[] oglbuffer;
200  }
201 
202  void GLImage::saveImage(const std::string& filename) {
203  const unsigned int swidth = getWidth();
204  const unsigned int sheight = getHeight();
205  SDL_Surface *surface = NULL;
206  uint8_t *pixels;
207 
208  surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
209  sheight, 24,
210  RMASK,GMASK,BMASK, NULLMASK);
211 
212  if(surface == NULL) {
213  return;
214  }
215 
216  SDL_LockSurface(surface);
217  pixels = new uint8_t[swidth * sheight * 3];
218  glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
219 
220  uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
221  // Copy the "reversed_image" memory to the "image" memory
222  for (int y = (sheight - 1); y >= 0; --y) {
223  uint8_t *rowbegin = pixels + y * swidth * 3;
224  uint8_t *rowend = rowbegin + swidth * 3;
225 
226  std::copy(rowbegin, rowend, imagepixels);
227 
228  // Advance a row in the output surface.
229  imagepixels += surface->pitch;
230  }
231 
232  SDL_UnlockSurface(surface);
233  saveAsPng(filename, *surface);
234  SDL_FreeSurface(surface);
235  delete [] pixels;
236  }
237 
238  void GLImage::setClipArea(const Rect& cliparea, bool clear) {
239  glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
240 
241  if (clear) {
242  glClear(GL_COLOR_BUFFER_BIT);
243  }
244  }
245 
246  bool GLImage::putPixel(int x, int y, int r, int g, int b, int a) {
247  cleanup();
248  return m_sdlimage->putPixel(x, y, r, g, b, a);
249  }
250 
251  void GLImage::drawLine(const Point& p1, const Point& p2, int r, int g, int b, int a) {
252  cleanup();
253  m_sdlimage->drawLine(p1, p2, r, g, b, a);
254  }
255 
256  void GLImage::drawTriangle(const Point& p1, const Point& p2, const Point& p3, int r, int g, int b, int a) {
257  cleanup();
258  m_sdlimage->drawTriangle(p1, p2, p3, r, g, b, a);
259  }
260 
261  void GLImage::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
262  cleanup();
263  m_sdlimage->drawRectangle(p, w, h, r, g, b, a);
264  }
265 
266  void GLImage::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
267  cleanup();
268  m_sdlimage->fillRectangle(p, w, h, r, g, b, a);
269  }
270 
271  void GLImage::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b, int a) {
272  cleanup();
273  m_sdlimage->drawQuad(p1, p2, p3, p4, r, g, b, a);
274  }
275 
276  void GLImage::drawVertex(const Point& p, const uint8_t size, int r, int g, int b, int a) {
277  cleanup();
278  m_sdlimage->drawVertex(p, size, r, g, b, a);
279  }
280 
281  void GLImage::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
282  cleanup();
283  m_sdlimage->drawLightPrimitive(p, intensity, radius, subdivisions, xstretch, ystretch, red, green, blue);
284  }
285 }