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