FIFE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
glimage.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 // 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/imagemanager.h"
33 #include "video/sdl/sdlimage.h"
34 #include "video/renderbackend.h"
36 
37 #include "glimage.h"
38 
39 namespace FIFE {
41  Image(loader),
42  m_compressed(false),
43  m_texId(0) {
44 
45  resetGlimage();
46  }
47 
48  GLImage::GLImage(const std::string& name, IResourceLoader* loader):
49  Image(name, loader),
50  m_compressed(false),
51  m_texId(0) {
52 
53  resetGlimage();
54  }
55 
56  GLImage::GLImage(SDL_Surface* surface):
57  Image(surface),
58  m_compressed(false),
59  m_texId(0) {
60 
61  resetGlimage();
62  }
63 
64  GLImage::GLImage(const std::string& name, SDL_Surface* surface):
65  Image(name, surface),
66  m_compressed(false),
67  m_texId(0) {
68 
69  resetGlimage();
70  }
71 
72  GLImage::GLImage(const uint8_t* data, uint32_t width, uint32_t height):
73  Image(data, width, height),
74  m_compressed(false),
75  m_texId(0) {
76 
77  assert(m_surface);
78  resetGlimage();
79  }
80 
81  GLImage::GLImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
82  Image(name, data, width, height),
83  m_compressed(false),
84  m_texId(0) {
85 
86  assert(m_surface);
87  resetGlimage();
88  }
89 
91  cleanup();
92  }
93 
95  resetGlimage();
96  }
97 
98  void GLImage::setSurface(SDL_Surface* surface) {
99  reset(surface);
100  resetGlimage();
101  }
102 
104  cleanup();
105 
106  m_chunk_size_w = 0;
107  m_chunk_size_h = 0;
108 
110  }
111 
113  if (m_texId) {
114  if(!m_shared) {
115  glDeleteTextures(1, &m_texId);
116  }
117  m_texId = 0;
118  m_compressed = false;
119  }
120 
121  m_tex_coords[0] = m_tex_coords[1] =
122  m_tex_coords[2] = m_tex_coords[3] = 0.0f;
123  }
124 
125  void GLImage::render(const Rect& rect, uint8_t alpha, uint8_t const* rgb) {
126  // completely transparent so dont bother rendering
127  if (0 == alpha) {
128  return;
129  }
131  SDL_Surface* target = rb->getRenderTargetSurface();
132  assert(target != m_surface); // can't draw on the source surface
133 
134  // not on the screen. dont render
135  if (rect.right() < 0 || rect.x > static_cast<int32_t>(target->w) ||
136  rect.bottom() < 0 || rect.y > static_cast<int32_t>(target->h)) {
137  return;
138  }
139 
140  if (!m_texId) {
142  } else if (m_shared) {
143  validateShared();
144  }
145 
146  rb->addImageToArray(m_texId, rect, m_tex_coords, alpha, rgb);
147  }
148 
150  if (m_shared) {
151  // First make sure we loaded big image to opengl
152  validateShared();
153  return;
154  }
155  // ultimate possibility to load the image
156  // is used e.g. in case a cursor or gui image is freed even if there is a reference
157  if (!m_surface) {
159  load();
160  }
161  }
162  const uint32_t width = m_surface->w;
163  const uint32_t height = m_surface->h;
164 
165  // With OpenGL 2.0 or GL_ARB_texture_non_power_of_two we don't really need to care
166  // about non power of 2 textures
167  if(GLEE_ARB_texture_non_power_of_two && RenderBackend::instance()->isNPOTEnabled()) {
168  m_chunk_size_w = width;
169  m_chunk_size_h = height;
170  }
171  else {
172  //calculate the nearest larger power of 2
173  m_chunk_size_w = nextPow2(width);
174  m_chunk_size_h = nextPow2(height);
175  }
176 
177  // used to calculate the fill ratio for given chunk
178  m_tex_coords[0] = m_tex_coords[1] = 0.0f;
179  m_tex_coords[2] = static_cast<float>(m_surface->w%m_chunk_size_w) / static_cast<float>(m_chunk_size_w);
180  m_tex_coords[3] = static_cast<float>(m_surface->h%m_chunk_size_h) / static_cast<float>(m_chunk_size_h);
181 
182  if (m_tex_coords[2] == 0.0f){
183  m_tex_coords[2] = 1.0f;
184  }
185 
186  if (m_tex_coords[3] == 0.0f){
187  m_tex_coords[3] = 1.0f;
188  }
189 
190  uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
191  int32_t pitch = m_surface->pitch;
192 
193  assert(!m_texId);
194 
195  // get texture id from opengl
196  glGenTextures(1, &m_texId);
197  // set focus on that texture
198  static_cast<RenderBackendOpenGL*>(RenderBackend::instance())->bindTexture(m_texId);
199  // set filters for texture
200  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
201  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
202 
203  GLint internalFormat = GL_RGBA8;
204  if(GLEE_ARB_texture_compression && RenderBackend::instance()->isImageCompressingEnabled()) {
205  internalFormat = GL_COMPRESSED_RGBA;
206  m_compressed = true;
207  } else {
208  m_compressed = false;
209  }
210 
211  SDL_Surface* target = RenderBackend::instance()->getRenderTargetSurface();
212  int32_t bpp_target = target->format->BitsPerPixel;
213  int32_t bpp_source = m_surface->format->BitsPerPixel;
214  // create 16 bit texture, RGBA_4444
215  if (bpp_target == 16 && bpp_source == 32) {
216  uint16_t* oglbuffer = new uint16_t[m_chunk_size_w * m_chunk_size_h];
217  memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint16_t));
218 
219  for (uint32_t y = 0; y < height; ++y) {
220  for (uint32_t x = 0; x < width; ++x) {
221  uint32_t pos = (y * pitch) + (x * 4);
222 
223  uint8_t r = data[pos + 0];
224  uint8_t g = data[pos + 1];
225  uint8_t b = data[pos + 2];
226  uint8_t a = data[pos + 3];
227 
229  // only set alpha to zero if colorkey feature is enabled
230  if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
231  a = 0;
232  }
233  }
234 
235  oglbuffer[(y*m_chunk_size_w) + x] = ((r >> 4) << 12) |
236  ((g >> 4) << 8) |
237  ((b >> 4) << 4) |
238  ((a >> 4) << 0);
239  }
240  }
241  // in case of compression we let OpenGL handle it
242  if (!m_compressed) {
243  internalFormat = GL_RGBA4;
244  }
245 
246  // transfer data from sdl buffer
247  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
248  0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, oglbuffer);
249 
250  delete[] oglbuffer;
251  return;
252  }
253 
254  if(GLEE_ARB_texture_non_power_of_two && RenderBackend::instance()->isNPOTEnabled()) {
255  if(RenderBackend::instance()->isColorKeyEnabled()) {
256  uint8_t* oglbuffer = new uint8_t[width * height * 4];
257  memcpy(oglbuffer, data, width * height * 4 * sizeof(uint8_t));
258 
259  for (uint32_t y = 0; y < height; ++y) {
260  for (uint32_t x = 0; x < width * 4; x += 4) {
261  uint32_t gid = x + y * width;
262 
263  uint8_t r = oglbuffer[gid + 0];
264  uint8_t g = oglbuffer[gid + 1];
265  uint8_t b = oglbuffer[gid + 2];
266 
267  // set alpha to zero
268  if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
269  oglbuffer[gid + 3] = 0;
270  }
271  }
272  }
273 
274  // transfer data from sdl buffer
275  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
276  0, GL_RGBA, GL_UNSIGNED_BYTE, oglbuffer);
277 
278  delete [] oglbuffer;
279  } else {
280  // transfer data directly from sdl buffer
281  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
282  0, GL_RGBA, GL_UNSIGNED_BYTE, data);
283  }
284  // Non power of 2 textures are not supported, we need to pad the size of texture to nearest power of 2
285  } else {
286  uint32_t* oglbuffer = new uint32_t[m_chunk_size_w * m_chunk_size_h];
287  memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint32_t));
288 
289  for (uint32_t y = 0; y < height; ++y) {
290  for (uint32_t x = 0; x < width; ++x) {
291  uint32_t pos = (y * pitch) + (x * 4);
292 
293  uint8_t a = data[pos + 3];
294  uint8_t b = data[pos + 2];
295  uint8_t g = data[pos + 1];
296  uint8_t r = data[pos + 0];
297 
299  // only set alpha to zero if colorkey feature is enabled
300  if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
301  a = 0;
302  }
303  }
304 
305  oglbuffer[(y*m_chunk_size_w) + x] = r | (g << 8) | (b << 16) | (a<<24);
306  }
307  }
308 
309  // transfer data from sdl buffer
310  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
311  0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
312 
313  delete[] oglbuffer;
314  }
315  }
316 
317  void GLImage::generateGLSharedTexture(const GLImage* shared, const Rect& region) {
318  uint32_t width = shared->getWidth();
319  uint32_t height = shared->getHeight();
320 
321  if(!GLEE_ARB_texture_non_power_of_two || !RenderBackend::instance()->isNPOTEnabled()) {
322  width = nextPow2(width);
323  height = nextPow2(height);
324  }
325 
326  m_tex_coords[0] = static_cast<GLfloat>(region.x) / static_cast<GLfloat>(width);
327  m_tex_coords[1] = static_cast<GLfloat>(region.y) / static_cast<GLfloat>(height);
328  m_tex_coords[2] = static_cast<GLfloat>(region.x + region.w) / static_cast<GLfloat>(width);
329  m_tex_coords[3] = static_cast<GLfloat>(region.y + region.h) / static_cast<GLfloat>(height);
330  }
331 
332  void GLImage::useSharedImage(const ImagePtr& shared, const Rect& region) {
333  GLImage* img = static_cast<GLImage*>(shared.get());
334 
335  m_shared_img = img;
336  m_texId = img->m_texId;
337  m_shared = true;
338  m_subimagerect = region;
339  m_atlas_img = shared;
343 
344  if(m_texId) {
345  generateGLSharedTexture(img, region);
346  }
347 
349  }
350 
352  if (m_texId == 0) {
354  } else if (m_shared) {
355  validateShared();
356  }
357  }
358 
360  // if image is valid we can return
362  return;
363  }
364 
366  m_shared_img->load();
368  }
369 
374  }
375 
376  void GLImage::copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr& img) {
377  Image::copySubimage(xoffset, yoffset, img);
378 
379  if(m_texId) {
380  static_cast<RenderBackendOpenGL*>(RenderBackend::instance())->bindTexture(m_texId);
381  glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, img->getWidth(), img->getHeight(),
382  GL_RGBA, GL_UNSIGNED_BYTE, img->getSurface()->pixels);
383  }
384  }
385 
386  void GLImage::load() {
387  if (m_shared) {
388  // check atlas image
389  // if it does not exist, it is generated.
390  if (!ImageManager::instance()->exists(m_atlas_name)) {
392  GLImage* img = static_cast<GLImage*>(newAtlas.get());
393  m_atlas_img = newAtlas;
394  m_shared_img = img;
395  }
396 
397  // check if texture ids and surfaces are identical
402  if (m_texId) {
404  }
405  }
407  } else {
408  Image::load();
409  }
410  }
411 
412  void GLImage::free() {
413  setSurface(NULL);
415  }
416 
417  GLuint GLImage::getTexId() const {
418  return m_texId;
419  }
420 
421  const GLfloat* GLImage::getTexCoords() const {
422  return m_tex_coords;
423  }
424 }
virtual ImagePtr create(IResourceLoader *loader=0)
Creates a blank Image but does not load it immediately.
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
virtual void addImageToArray(uint32_t id, const Rect &rec, float const *st, uint8_t alpha, uint8_t const *rgba)=0
Add the Image data to the array.
Abstract interface for all the renderbackends.
Definition: renderbackend.h:92
T * get() const
allows direct access to underlying pointer
Definition: sharedptr.h:155
virtual void invalidate()
Invalidates the Image causing it to be reset or re-loaded.
Definition: glimage.cpp:94
void generateGLTexture()
Generates the GL Texture for use when rendering.
Definition: glimage.cpp:149
virtual ResourceState getState()
Definition: resource.h:70
virtual void load()
Definition: glimage.cpp:386
virtual void load()
Definition: image.cpp:124
uint32_t m_chunk_size_w
Definition: glimage.h:114
Base Class for Images.
Definition: image.h:47
SDL_Surface * m_surface
Definition: image.h:155
T h
Height of the rectangle.
Definition: rect.h:93
T x
The X Coordinate.
Definition: rect.h:84
GLfloat m_tex_coords[4]
Definition: glimage.h:78
virtual void setSurface(SDL_Surface *surface)
This frees the current suface and replaces it with the surface passed in the parameter (which can be ...
Definition: glimage.cpp:98
unsigned nextPow2(unsigned x)
Returns the next higher power of 2 based on the passed argument.
Definition: fife_math.h:292
void resetGlimage()
Resets GLImage variables.
Definition: glimage.cpp:103
GLImage(IResourceLoader *loader=0)
Definition: glimage.cpp:40
GLuint getTexId() const
Definition: glimage.cpp:417
std::string m_atlas_name
Definition: glimage.h:123
const GLfloat * getTexCoords() const
Definition: glimage.cpp:421
virtual void copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr &img)
Copies given image into this one with respect to given offsets.
Definition: glimage.cpp:376
virtual void useSharedImage(const ImagePtr &shared, const Rect &region)
After this call all image data will be taken from the given image and its subregion.
Definition: glimage.cpp:332
SDL_Color m_colorkey
Definition: glimage.h:117
static RenderBackend * instance()
Definition: singleton.h:84
uint32_t getHeight() const
Definition: image.cpp:155
bool isColorKeyEnabled() const
Gets whether the colorkey feature is in use.
unsigned char uint8_t
Definition: core.h:38
GLuint m_texId
Holds texture ids that are used to access textures in GL rendering context.
Definition: glimage.h:98
T bottom() const
The Y coordinate of the bottom edge.
Definition: rect.h:173
SDL_Surface * getSurface()
Definition: image.h:91
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:310
const SDL_Color & getColorKey() const
Gets the global colorkey setting.
virtual ~GLImage()
Definition: glimage.cpp:90
void generateGLSharedTexture(const GLImage *shared, const Rect &region)
Definition: glimage.cpp:317
virtual const std::string & getName()
Definition: resource.h:66
uint32_t getWidth() const
Definition: image.cpp:146
ResourceState m_state
Definition: resource.h:81
unsigned short uint16_t
Definition: core.h:39
T y
The Y Coordinate.
Definition: rect.h:87
Rect m_subimagerect
Definition: image.h:172
GLImage * m_shared_img
Definition: glimage.h:119
T right() const
The X coordinate of the right edge.
Definition: rect.h:168
virtual void setState(const ResourceState &state)
Definition: resource.h:71
virtual void forceLoadInternal()
Forces to load the image into internal memory of GPU.
Definition: glimage.cpp:351
void cleanup()
Frees allocated memory and calls resetGlImage.
Definition: glimage.cpp:112
bool m_compressed
Definition: glimage.h:81
SDL_Surface * getRenderTargetSurface()
Returns currently attached render surface.
uint32_t m_chunk_size_h
Definition: glimage.h:115
virtual void free()
Definition: glimage.cpp:412
bool m_shared
Definition: image.h:170
Implements an Image using OpenGL.
Definition: glimage.h:53
virtual void render(const Rect &rect, uint8_t alpha=255, uint8_t const *rgb=0)
Renders itself to the current render target (main screen or attached destination image) at the rectan...
Definition: glimage.cpp:125
unsigned int uint32_t
Definition: core.h:40
ImagePtr m_atlas_img
Definition: glimage.h:121
T w
Width of the rectangle.
Definition: rect.h:90
The main class of the OpenGL-based renderer.
void validateShared()
Definition: glimage.cpp:359