FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
renderbackendopengle.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2011 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 
24 // Platform specific includes
25 
26 // 3rd party library includes
27 #include <SDL.h>
28 
29 // FIFE includes
30 #include "util/base/exception.h"
31 #include "util/log/logger.h"
32 #include "video/devicecaps.h"
33 
34 #include "gleimage.h"
35 #include "renderbackendopengle.h"
36 #include "SDL_image.h"
37 
38 #define ALPHA_REF 0.3f
39 
40 
41 namespace FIFE {
42  static Logger _log(LM_VIDEO);
43 
44  class RenderBackendOpenGLe::RenderObject {
45  public:
46  RenderObject(GLenum m, uint16_t s, uint32_t t=0):
47  mode(m),
48  size(s),
49  texture_id(t),
50  src(4),
51  dst(5),
52  light(true),
53  stencil_test(false),
54  stencil_ref(0),
55  stencil_op(0),
56  stencil_func(0)
57  {}
58 
59  public:
60  GLenum mode;
61  uint16_t size;
62  uint32_t texture_id;
63  int32_t src;
64  int32_t dst;
65  bool light;
66  bool stencil_test;
67  uint8_t stencil_ref;
68  GLenum stencil_op;
69  GLenum stencil_func;
70  uint8_t rgb[3];
71  };
72 
73  const float RenderBackendOpenGLe::zfar = 100.0f;
74  const float RenderBackendOpenGLe::znear = -100.0f;
75 
76  static const int max_quads_per_texbatch = 600;
77  static const int max_tex = 400; // TODO: could do this expandable
78  static const int buffer_default_size = 4 * max_quads_per_texbatch * max_tex;
79 
80  RenderBackendOpenGLe::RenderBackendOpenGLe(const SDL_Color& colorkey)
81  : RenderBackend(colorkey), m_mask_overlays(0){
82 
83  m_state.tex_enabled[0] = false;
84  m_state.tex_enabled[1] = false;
85  m_state.texture[0] = 0;
86  m_state.texture[1] = 0;
87  m_state.active_tex = 0;
88 
89  m_state.lightmodel = 0;
90  m_state.light_enabled = false;
91 
92  m_state.sten_enabled = false;
93  m_state.sten_ref = 0;
94  m_state.sten_buf = 0;
95  m_state.sten_op = 0;
96  m_state.sten_func = 0;
97 
98  m_state.env_color[0] = 0;
99  m_state.env_color[1] = 0;
100  m_state.env_color[2] = 0;
101  m_state.blend_src = GL_SRC_ALPHA;
102  m_state.blend_dst = GL_ONE_MINUS_SRC_ALPHA;
103  m_state.alpha_enabled = true;
104  m_state.depth_enabled = true;
105  m_state.scissor_test = true;
106  }
107 
108  RenderBackendOpenGLe::~RenderBackendOpenGLe() {
109  glDeleteTextures(1, &m_mask_overlays);
110  if(GLEE_EXT_framebuffer_object && m_useframebuffer) {
111  glDeleteFramebuffers(1, &m_fbo_id);
112  }
113  deinit();
114  }
115 
116  const std::string& RenderBackendOpenGLe::getName() const {
117  static std::string backend_name = "OpenGLe";
118  return backend_name;
119  }
120 
121  void RenderBackendOpenGLe::init(const std::string& driver) {
122  // note: driver has no affect on the opengl renderer so do nothing with it here.
123  Uint32 flags = SDL_INIT_VIDEO;
124  if (SDL_InitSubSystem(flags) < 0)
125  throw SDLException(SDL_GetError());
126  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
127  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
128 
129  SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); // temporary hack
130  }
131 
133  disableScissorTest();
134  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135  enableScissorTest();
136  }
137 
138  void RenderBackendOpenGLe::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
139  if(icon != "") {
140  SDL_Surface *img = IMG_Load(icon.c_str());
141  if(img != NULL) {
142  SDL_WM_SetIcon(img, 0);
143  SDL_FreeSurface(img);
144  }
145  }
146 
147  setScreenMode(mode);
148  SDL_WM_SetCaption(title.c_str(), 0);
149  }
150 
151  void RenderBackendOpenGLe::setScreenMode(const ScreenMode& mode) {
152  uint16_t width = mode.getWidth();
153  uint16_t height = mode.getHeight();
154  uint16_t bitsPerPixel = mode.getBPP();
155  bool fs = mode.isFullScreen();
156  uint32_t flags = mode.getSDLFlags();
157 
158  if (bitsPerPixel != 0) {
159  uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
160  if (!bpp){
161  throw SDLException("Selected video mode not supported!");
162  }
163  }
164 
165  if(m_screen) {
166  SDL_FreeSurface(m_screen);
167  }
168  m_screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
169  if( !m_screen ) {
170  throw SDLException("Unable to set video mode selected!");
171  }
172  m_target = m_screen;
173 
174  FL_LOG(_log, LMsg("RenderBackendOpenGLe")
175  << "Videomode " << width << "x" << height
176  << " at " << int32_t(bitsPerPixel) << " bpp");
177 
178  m_rgba_format = *(m_screen->format);
179  m_rgba_format.Rmask = RMASK;
180  m_rgba_format.Gmask = GMASK;
181  m_rgba_format.Bmask = BMASK;
182  m_rgba_format.Amask = AMASK;
183 
184  //update the screen mode with the actual flags used
185  m_screenMode = ScreenMode(width,
186  height,
187  bitsPerPixel,
188  m_screen->flags);
189 
190  if (!m_screen) {
191  throw SDLException(SDL_GetError());
192  }
193 
194  glViewport(0, 0, width, height);
195  glMatrixMode(GL_PROJECTION);
196  glLoadIdentity();
197  glOrtho(0, width, height, 0, znear, zfar);
198  glMatrixMode(GL_MODELVIEW);
199  glLoadIdentity();
200 
201  glEnable(GL_CULL_FACE);
202  glFrontFace(GL_CCW);
203  glCullFace(GL_BACK);
204 
205  glPixelStorei(GL_PACK_ALIGNMENT, 1);
206  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
207 
208  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
209  glClearDepth(1.0f);
210  glClearStencil(0);
211 
212  glEnable(GL_BLEND);
213  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
214  glEnable(GL_ALPHA_TEST);
215  glAlphaFunc(GL_GREATER, ALPHA_REF);
216  glEnable(GL_DEPTH_TEST);
217  glDepthFunc(GL_LEQUAL);
218 
219  glEnable(GL_SCISSOR_TEST);
220 
221  glEnableClientState(GL_VERTEX_ARRAY);
222 
223  prepareForOverlays();
224 
225  glPointSize(1.0);
226  glLineWidth(1.0);
227 
228  if(GLEE_EXT_framebuffer_object && m_useframebuffer) {
229  glGenFramebuffers(1, &m_fbo_id);
230  }
231 
232  m_renderZ_datas.resize(buffer_default_size);
233  }
234 
237  }
238 
240  SDL_GL_SwapBuffers();
242  }
243 
244  Image* RenderBackendOpenGLe::createImage(IResourceLoader* loader) {
245  return new GLeImage(loader);
246  }
247 
248  Image* RenderBackendOpenGLe::createImage(const std::string& name, IResourceLoader* loader) {
249  return new GLeImage(name, loader);
250  }
251 
252  Image* RenderBackendOpenGLe::createImage(SDL_Surface* surface) {
253  // Given an abritary surface, we must convert it to the format GLeImage will understand.
254  // It's easiest to let SDL do this for us.
255 
256  // Uh. Gotta love this :-)
257  // Check for colorkey too?
258  // Leave out the loss/shift checks?
259  if (32 == surface->format->BitsPerPixel
260  && m_rgba_format.Rmask == surface->format->Rmask
261  && m_rgba_format.Gmask == surface->format->Gmask
262  && m_rgba_format.Bmask == surface->format->Bmask
263  && m_rgba_format.Amask == surface->format->Amask
264  && m_rgba_format.Rshift == surface->format->Rshift
265  && m_rgba_format.Gshift == surface->format->Gshift
266  && m_rgba_format.Bshift == surface->format->Bshift
267  && m_rgba_format.Ashift == surface->format->Ashift
268  && m_rgba_format.Rloss == surface->format->Rloss
269  && m_rgba_format.Gloss == surface->format->Gloss
270  && m_rgba_format.Bloss == surface->format->Bloss
271  && m_rgba_format.Aloss == surface->format->Aloss
272  && surface->flags & SDL_SRCALPHA ) {
273 
274  return new GLeImage(surface);
275  }
276 
277  uint8_t bpp = m_rgba_format.BitsPerPixel;
278  m_rgba_format.BitsPerPixel = 32;
279  SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
280  m_rgba_format.BitsPerPixel = bpp;
281  GLeImage* image = new GLeImage(conv);
282  SDL_FreeSurface( surface );
283  return image;
284  }
285 
286  Image* RenderBackendOpenGLe::createImage(const std::string& name, SDL_Surface* surface) {
287  // Given an abritary surface, we must convert it to the format GLeImage will understand.
288  // It's easiest to let SDL do this for us.
289 
290  // Uh. Gotta love this :-)
291  // Check for colorkey too?
292  // Leave out the loss/shift checks?
293  if (32 == surface->format->BitsPerPixel
294  && m_rgba_format.Rmask == surface->format->Rmask
295  && m_rgba_format.Gmask == surface->format->Gmask
296  && m_rgba_format.Bmask == surface->format->Bmask
297  && m_rgba_format.Amask == surface->format->Amask
298  && m_rgba_format.Rshift == surface->format->Rshift
299  && m_rgba_format.Gshift == surface->format->Gshift
300  && m_rgba_format.Bshift == surface->format->Bshift
301  && m_rgba_format.Ashift == surface->format->Ashift
302  && m_rgba_format.Rloss == surface->format->Rloss
303  && m_rgba_format.Gloss == surface->format->Gloss
304  && m_rgba_format.Bloss == surface->format->Bloss
305  && m_rgba_format.Aloss == surface->format->Aloss
306  && surface->flags & SDL_SRCALPHA ) {
307 
308  return new GLeImage(name, surface);
309  }
310 
311  uint8_t bpp = m_rgba_format.BitsPerPixel;
312  m_rgba_format.BitsPerPixel = 32;
313  SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
314  m_rgba_format.BitsPerPixel = bpp;
315  GLeImage* image = new GLeImage(name, conv);
316  SDL_FreeSurface( surface );
317  return image;
318  }
319 
320  Image* RenderBackendOpenGLe::createImage(const uint8_t* data, uint32_t width, uint32_t height) {
321  return new GLeImage(data, width, height);
322  }
323 
324  Image* RenderBackendOpenGLe::createImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height) {
325  return new GLeImage(name, data, width, height);
326  }
327 
328  void RenderBackendOpenGLe::setLightingModel(uint32_t lighting) {
329  if (m_state.lightmodel != lighting) {
330  if (m_state.lightmodel != 0) {
331  disableLighting();
332  glDisable(GL_COLOR_MATERIAL);
333  } else if (lighting != 0) {
334  m_state.lightmodel = lighting;
335  enableLighting();
336  glEnable(GL_LIGHT0);
337  glColorMaterial(GL_FRONT, GL_DIFFUSE);
338  glEnable(GL_COLOR_MATERIAL);
339  }
340  m_state.lightmodel = lighting;
341  }
342  }
343 
345  return m_state.lightmodel;
346  }
347 
348  void RenderBackendOpenGLe::enableTextures(uint32_t texUnit) {
349  if(m_state.tex_enabled[texUnit] == false) {
350  if(m_state.active_tex != texUnit) {
351  m_state.active_tex = texUnit;
352  glActiveTexture(GL_TEXTURE0 + texUnit);
353  }
354  m_state.tex_enabled[texUnit] = true;
355 
356  glEnable(GL_TEXTURE_2D);
357  if(texUnit == 0) {
358  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
359  }
360  }
361  }
362 
363  void RenderBackendOpenGLe::disableTextures(uint32_t texUnit)
364  {
365  if(m_state.tex_enabled[texUnit] == true) {
366  if(m_state.active_tex != texUnit) {
367  m_state.active_tex = texUnit;
368  glActiveTexture(GL_TEXTURE0 + texUnit);
369  }
370  m_state.tex_enabled[texUnit] = false;
371 
372  glDisable(GL_TEXTURE_2D);
373  if(texUnit == 0) {
374  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
375  }
376  }
377  }
378 
379  void RenderBackendOpenGLe::bindTexture(uint32_t texUnit, GLuint texId) {
380  enableTextures(texUnit);
381 
382  if(m_state.texture[texUnit] != texId) {
383  if(m_state.active_tex != texUnit) {
384  m_state.active_tex = texUnit;
385  glActiveTexture(GL_TEXTURE0 + texUnit);
386  }
387  m_state.texture[texUnit] = texId;
388  glBindTexture(GL_TEXTURE_2D, texId);
389  }
390  }
391 
392  void RenderBackendOpenGLe::bindTexture(GLuint texId) {
393  if(m_state.texture[m_state.active_tex] != texId) {
394  m_state.texture[m_state.active_tex] = texId;
395  glBindTexture(GL_TEXTURE_2D, texId);
396  }
397  }
398 
399  void RenderBackendOpenGLe::enableLighting() {
400  if (m_state.lightmodel != 0 && !m_state.light_enabled) {
401  glEnable(GL_LIGHTING);
402  m_state.light_enabled = true;
403  }
404  }
405 
406  void RenderBackendOpenGLe::disableLighting() {
407  if (m_state.lightmodel != 0 && m_state.light_enabled) {
408  glDisable(GL_LIGHTING);
409  m_state.light_enabled = false;
410  }
411  }
412 
413  void RenderBackendOpenGLe::setLighting(float red, float green, float blue) {
414  if (m_state.lightmodel != 0) {
415  GLfloat lightDiffuse[] = {red, green, blue, 1.0f};
416  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
417  }
418  }
419 
421  m_state.light_enabled = false;
422  }
423 
424  void RenderBackendOpenGLe::enableStencilTest() {
425  if (!m_state.sten_enabled) {
426  glEnable(GL_STENCIL_TEST);
427  m_state.sten_enabled = true;
428  }
429  }
430 
431  void RenderBackendOpenGLe::disableStencilTest() {
432  if (m_state.sten_enabled) {
433  glDisable(GL_STENCIL_TEST);
434  m_state.sten_enabled = false;
435  }
436  }
437 
438  void RenderBackendOpenGLe::setStencilTest(uint8_t stencil_ref, GLenum stencil_op, GLenum stencil_func) {
439  enableStencilTest();
440  if(m_state.sten_op != stencil_op) {
441  m_state.sten_op = stencil_op;
442  glStencilOp(GL_KEEP, GL_KEEP, m_state.sten_op);
443  }
444 
445  if(m_state.sten_ref != stencil_ref || m_state.sten_func != stencil_func) {
446  m_state.sten_ref = stencil_ref;
447  m_state.sten_func = stencil_func;
448  glStencilFunc(m_state.sten_func, stencil_ref, 0xff);
449  }
450  }
451 
453  if (buffer != m_state.sten_buf) {
454  m_state.sten_buf = buffer;
455  glClearStencil(buffer);
456  }
457  disableScissorTest();
458  glClear(GL_STENCIL_BUFFER_BIT);
459  enableScissorTest();
460  }
461 
462  void RenderBackendOpenGLe::enableAlphaTest() {
463  if (!m_state.alpha_enabled) {
464  glEnable(GL_ALPHA_TEST);
465  m_state.alpha_enabled = true;
466  }
467  }
468 
469  void RenderBackendOpenGLe::disableAlphaTest() {
470  if (m_state.alpha_enabled) {
471  glDisable(GL_ALPHA_TEST);
472  m_state.alpha_enabled = false;
473  }
474  }
475 
476  void RenderBackendOpenGLe::setAlphaTest(float ref_alpha) {
477  enableAlphaTest();
478  glAlphaFunc(GL_GREATER, ref_alpha);
479  }
480 
481  void RenderBackendOpenGLe::enableDepthTest() {
482  if (!m_state.depth_enabled) {
483  glEnable(GL_DEPTH_TEST);
484  m_state.depth_enabled = true;
485  }
486  }
487 
488  void RenderBackendOpenGLe::disableDepthTest() {
489  if (m_state.depth_enabled) {
490  glDisable(GL_DEPTH_TEST);
491  m_state.depth_enabled = false;
492  }
493  }
494 
495  void RenderBackendOpenGLe::setEnvironmentalColor(const uint8_t* rgb) {
496  if (memcmp(m_state.env_color, rgb, sizeof(uint8_t) * 3)) {
497  memcpy(m_state.env_color, rgb, sizeof(uint8_t) * 3);
498  GLfloat rgbf[4] = {
499  static_cast<float>(m_state.env_color[0]) / 255.0f,
500  static_cast<float>(m_state.env_color[1]) / 255.0f,
501  static_cast<float>(m_state.env_color[2]) / 255.0f, 0.0f};
502  glActiveTexture(GL_TEXTURE1);
503  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgbf);
504  glActiveTexture(GL_TEXTURE0);
505  }
506  }
507 
508  void RenderBackendOpenGLe::enableScissorTest() {
509  if(m_state.scissor_test == false) {
510  m_state.scissor_test = true;
511  glEnable(GL_SCISSOR_TEST);
512  }
513  }
514 
515  void RenderBackendOpenGLe::disableScissorTest() {
516  if(m_state.scissor_test == true) {
517  m_state.scissor_test = false;
518  glDisable(GL_SCISSOR_TEST);
519  }
520  }
521 
522  void RenderBackendOpenGLe::changeBlending(int32_t src, int32_t dst) {
523  GLenum src_fact;
524  GLenum dst_fact;
525 
526  switch(src) {
527  case 0 : src_fact = GL_ZERO; break;
528  case 1 : src_fact = GL_ONE; break;
529  case 2 : src_fact = GL_DST_COLOR; break;
530  case 3 : src_fact = GL_ONE_MINUS_DST_COLOR; break;
531  case 4 : src_fact = GL_SRC_ALPHA; break;
532  case 5 : src_fact = GL_ONE_MINUS_SRC_ALPHA; break;
533  case 6 : src_fact = GL_DST_ALPHA; break;
534  case 7 : src_fact = GL_ONE_MINUS_DST_ALPHA; break;
535 
536  default : src_fact = GL_DST_COLOR; break;
537  }
538 
539  switch(dst) {
540  case 0 : dst_fact = GL_ZERO; break;
541  case 1 : dst_fact = GL_ONE; break;
542  case 2 : dst_fact = GL_SRC_COLOR; break;
543  case 3 : dst_fact = GL_ONE_MINUS_SRC_COLOR; break;
544  case 4 : dst_fact = GL_SRC_ALPHA; break;
545  case 5 : dst_fact = GL_ONE_MINUS_SRC_ALPHA; break;
546  case 6 : dst_fact = GL_DST_ALPHA; break;
547  case 7 : dst_fact = GL_ONE_MINUS_DST_ALPHA; break;
548 
549  default : dst_fact = GL_SRC_ALPHA; break;
550  }
551 
552  if (m_state.blend_src != src_fact || m_state.blend_dst != dst_fact) {
553  m_state.blend_src = src_fact;
554  m_state.blend_dst = dst_fact;
555  glBlendFunc(src_fact, dst_fact);
556  }
557  }
558 
559  void RenderBackendOpenGLe::changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light,
560  bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc) {
561 
562  uint16_t count = 0;
563  uint32_t size = m_render_objects.size();
564  while (count != elements) {
565  ++count;
566  RenderObject& r = m_render_objects.at(size-count);
567 
568  r.src = src;
569  r.dst = dst;
570  r.light = light;
571  if (stentest) {
572  r.stencil_test = stentest;
573  r.stencil_ref = stenref;
574  r.stencil_op = stenop;
575  r.stencil_func = stenfunc;
576  }
577  }
578  }
579 
581  // Rendering order:
582  // * batched ordinary, full opacity textured quads
583  // * outlines and unlit with optional stencil test on (write on) if light is enabled
584  // * colored overlays - full opacity and (semi)transparent
585  // * semi transparent textured quads (sorted by instancerenderer)
586  if(!m_renderZ_objects.empty() || !m_renderZ_objects_forced.empty()) {
587  renderWithZ();
588  }
589 
590  // * everything else that doesn't use Z value or features like
591  // stencil test/alpha test/colored overlays/semi transparency:
592  // - different renderers (aside from instance one)
593  // - gui
594  if(!m_render_objects.empty()) {
595  renderWithoutZ();
596  }
597  }
598 
599  void RenderBackendOpenGLe::renderWithZ() {
600  enableAlphaTest();
601  enableDepthTest();
602  enableTextures(0);
603  enableLighting();
604  glDisableClientState(GL_COLOR_ARRAY);
605 
606  /* 1) ordinary z-valued quads */ {
607  static const uint32_t stride = sizeof(RenderZData);
608 
609  glVertexPointer(3, GL_FLOAT, stride, &m_renderZ_datas[0].vertex);
610  glTexCoordPointer(2, GL_FLOAT, stride, &m_renderZ_datas[0].texel);
611 
612  std::vector<RenderZObject>::iterator iter = m_renderZ_objects.begin();
613  for ( ; iter != m_renderZ_objects.end(); ++iter) {
614  bindTexture(iter->texture_id);
615  glDrawArrays(GL_QUADS, iter->index, iter->elements);
616  }
617  m_renderZ_objects.clear();
618  }
619 
620  // 2) forced batches (for unlit quads like outlines and unlit demanded instances)
621  if (!m_renderZ_objects_forced.empty()) {
622  static const uint32_t stride = sizeof(RenderZData);
623 
624 
625  glVertexPointer(3, GL_FLOAT, stride, &m_renderZ_datas[0].vertex);
626  glTexCoordPointer(2, GL_FLOAT, stride, &m_renderZ_datas[0].texel);
627  setStencilTest(255, GL_REPLACE, GL_ALWAYS);
628  disableLighting();
629 
630  std::vector<RenderZObject>::iterator iter = m_renderZ_objects_forced.begin();
631  for ( ; iter != m_renderZ_objects_forced.end(); ++iter) {
632  bindTexture(iter->texture_id);
633  glDrawArrays(GL_QUADS, iter->index, iter->elements);
634  }
635  disableStencilTest();
636  enableLighting();
637  m_renderZ_objects_forced.clear();
638  }
639 
640  // now we gonna need color values
641  glEnableClientState(GL_COLOR_ARRAY);
642 
643  // 3) full opacity and (semi)transparent colored overlays
644  if (!m_render_objects2T.empty()) {
645  static const uint32_t stride = sizeof(RenderZData2T);
646 
647  glActiveTexture(GL_TEXTURE1);
648  glEnable(GL_TEXTURE_2D);
649  glActiveTexture(GL_TEXTURE0);
650 
651  glVertexPointer(3, GL_FLOAT, stride, &m_render_datas2T[0].vertex);
652  glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_datas2T[0].color);
653 
654  glClientActiveTexture(GL_TEXTURE1);
655  glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas2T[0].texel2);
656  glClientActiveTexture(GL_TEXTURE0);
657  glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas2T[0].texel);
658 
659  // array index
660  GLint index = 0;
661  // elements to render
662  GLsizei elements = 0;
663  // texture id
664  uint32_t texture_id = 0;
665  // color of overlay
666  uint8_t rgb[3] = {0};
667 
668  std::vector<RenderObject>::iterator iter = m_render_objects2T.begin();
669  for (; iter != m_render_objects2T.end(); ++iter) {
670  if (iter->texture_id != texture_id || memcmp(rgb, iter->rgb, sizeof(uint8_t)*3)) {
671  if (elements > 0) {
672  glDrawArrays(GL_QUADS, index, elements);
673  index += elements;
674  }
675 
676  setEnvironmentalColor(iter->rgb);
677  bindTexture(iter->texture_id);
678  texture_id = iter->texture_id;
679  elements = iter->size;;
680  memcpy(rgb, iter->rgb, sizeof(uint8_t)*3);
681  } else {
682  elements += iter->size;
683  }
684  }
685  glDrawArrays(GL_QUADS, index, elements);
686 
687  glActiveTexture(GL_TEXTURE1);
688  glDisable(GL_TEXTURE_2D);
689  glActiveTexture(GL_TEXTURE0);
690 
691  m_render_objects2T.clear();
692  m_render_datas2T.clear();
693  }
694 
695  // we should stop using alpha test now
696  disableAlphaTest();
697 
698  // 4) now render (semi)transparent data (they are already sorted by instancerenderer)
699  if (!m_render_trans_objects.empty()) {
700  static const uint32_t stride = sizeof(RenderZData2T);
701 
702  glVertexPointer(3, GL_FLOAT, stride, &m_render_trans_datas[0].vertex);
703  glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_trans_datas[0].color);
704  glClientActiveTexture(GL_TEXTURE0);
705  glTexCoordPointer(2, GL_FLOAT, stride, &m_render_trans_datas[0].texel);
706 
707  // array index
708  GLint index = 0;
709  // elements to render
710  GLsizei elements = 0;
711  // texture id
712  uint32_t texture_id = 0;
713  // color of overlay
714  GLfloat rgb[3] = {0};
715 
716  std::vector<RenderObject>::iterator iter = m_render_trans_objects.begin();
717  for( ; iter != m_render_trans_objects.end(); ++iter) {
718  if (iter->texture_id != texture_id) {
719  if (elements > 0) {
720  glDrawArrays(GL_QUADS, index, elements);
721  index += elements;
722  }
723 
724  bindTexture(iter->texture_id);
725  texture_id = iter->texture_id;
726  elements = iter->size;;
727  } else {
728  elements += iter->size;
729  }
730  }
731  glDrawArrays(GL_QUADS, index, elements);
732 
733  m_render_trans_datas.clear();
734  m_render_trans_objects.clear();
735  }
736 
737  disableTextures(0);
738  disableDepthTest();
739  disableLighting();
740  }
741 
742  void RenderBackendOpenGLe::renderWithoutZ() {
743  //bools to indicate changes
744  bool type = false;
745  bool texture = false;
746  bool render = false;
747  bool blending = false;
748  bool stencil = false;
749 
750  static const uint32_t stride = sizeof(RenderData);
751 
752  glEnableClientState(GL_COLOR_ARRAY);
753  glVertexPointer(2, GL_FLOAT, stride, &m_render_datas[0].vertex);
754  glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas[0].texel);
755  glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_datas[0].color);
756 
757  disableAlphaTest();
758  disableDepthTest();
759  disableTextures(0);
760 
761  // array index
762  int32_t index = 0;
763  // elements to render
764  uint32_t elements = 0;
765  // render mode
766  GLenum mode = GL_QUADS;
767  // texture id
768  uint32_t texture_id = 0;
769  // src blending mode
770  int32_t src = 4;
771  // dst blending mode
772  int32_t dst = 5;
773 
774  for(std::vector<RenderObject>::iterator iter = m_render_objects.begin(); iter != m_render_objects.end(); ++iter) {
775  //first we look for changes
776  if (iter->mode != mode) {
777  type = true;
778  render = true;
779  }
780  if (iter->texture_id != texture_id) {
781  texture = true;
782  render = true;
783  }
784  if (m_state.lightmodel != 0) {
785  if (iter->src != src || iter->dst != dst) {
786  blending = true;
787  render = true;
788  }
789  // Note that we don't need to check iter->light_enabled since only Instances can be lightened
790  if (iter->stencil_test != m_state.sten_enabled) {
791  stencil = true;
792  render = true;
793  }
794  if (iter->stencil_ref != m_state.sten_ref ||
795  iter->stencil_op != m_state.sten_op ||
796  iter->stencil_func != m_state.sten_func) {
797  stencil = true;
798  render = true;
799  }
800  }
801 
802  // if no changes then we iterate to next element
803  if (!render) {
804  elements += iter->size;
805  // else we render everything so far
806  } else {
807  if (elements > 0) {
808  //render
809  glDrawArrays(mode, index, elements);
810  index += elements;
811  }
812  // set element to current size
813  elements = iter->size;
814 
815  // switch mode
816  if (type) {
817  mode = iter->mode;
818  type = false;
819  }
820  // switch texturing
821  if (texture) {
822  if (iter->texture_id != 0) {
823  enableTextures(0);
824  bindTexture(iter->texture_id);
825  texture_id = iter->texture_id;
826  } else {
827  disableTextures(0);
828  texture_id = 0;
829  }
830  texture = false;
831  }
832  // if lighting is enabled we have to consider a few more values
833  if (m_state.lightmodel != 0) {
834  // change blending
835  if (blending) {
836  src = iter->src;
837  dst = iter->dst;
838  changeBlending(src, dst);
839  blending = false;
840  }
841  // change stencil
842  if (stencil) {
843  if (iter->stencil_test) {
844  setStencilTest(iter->stencil_ref, iter->stencil_op, iter->stencil_func);
845  enableAlphaTest();
846  } else {
847  disableStencilTest();
848  disableAlphaTest();
849  }
850  stencil = false;
851  }
852  }
853 
854  render = false;
855  }
856  }
857  // render
858  glDrawArrays(mode, index, elements);
859 
860  changeBlending(4, 5);
861  disableStencilTest();
862  disableTextures(0);
863 
864  //reset all states
865  glDisableClientState(GL_COLOR_ARRAY);
866 
867  m_render_objects.clear();
868  m_render_datas.clear();
869  }
870 
871  bool RenderBackendOpenGLe::putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
872  if ((x < 0) || (x >= (int32_t)m_target->w) ||
873  (y < 0) || (y >= (int32_t)m_target->h)) {
874  return false;
875  }
876  RenderData rd;
877  rd.vertex[0] = static_cast<float>(x);
878  rd.vertex[1] = static_cast<float>(y);
879  rd.color[0] = r;
880  rd.color[1] = g;
881  rd.color[2] = b;
882  rd.color[3] = a;
883  m_render_datas.push_back(rd);
884 
885  RenderObject ro(GL_POINTS, 1);
886  m_render_objects.push_back(ro);
887 
888  return true;
889  }
890 
891  void RenderBackendOpenGLe::drawLine(const Point& p1, const Point& p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
892  RenderData rd;
893  rd.vertex[0] = static_cast<float>(p1.x);
894  rd.vertex[1] = static_cast<float>(p1.y);
895  rd.color[0] = r;
896  rd.color[1] = g;
897  rd.color[2] = b;
898  rd.color[3] = a;
899  m_render_datas.push_back(rd);
900 
901  rd.vertex[0] = static_cast<float>(p2.x);
902  rd.vertex[1] = static_cast<float>(p2.y);
903  m_render_datas.push_back(rd);
904 
905  RenderObject ro(GL_LINES, 2);
906  m_render_objects.push_back(ro);
907  }
908 
909  void RenderBackendOpenGLe::drawTriangle(const Point& p1, const Point& p2, const Point& p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
910  RenderData rd;
911  rd.vertex[0] = static_cast<float>(p1.x);
912  rd.vertex[1] = static_cast<float>(p1.y);
913  rd.color[0] = r;
914  rd.color[1] = g;
915  rd.color[2] = b;
916  rd.color[3] = a;
917  m_render_datas.push_back(rd);
918 
919  rd.vertex[0] = static_cast<float>(p2.x);
920  rd.vertex[1] = static_cast<float>(p2.y);
921  m_render_datas.push_back(rd);
922 
923  rd.vertex[0] = static_cast<float>(p3.x);
924  rd.vertex[1] = static_cast<float>(p3.y);
925  m_render_datas.push_back(rd);
926 
927  RenderObject ro(GL_TRIANGLES, 3);
928  m_render_objects.push_back(ro);
929  }
930 
931  void RenderBackendOpenGLe::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
932  RenderData rd;
933  rd.vertex[0] = static_cast<float>(p.x);
934  rd.vertex[1] = static_cast<float>(p.y);
935  rd.color[0] = r;
936  rd.color[1] = g;
937  rd.color[2] = b;
938  rd.color[3] = a;
939  m_render_datas.push_back(rd);
940  rd.vertex[0] = static_cast<float>(p.x+w);
941 
942  m_render_datas.push_back(rd);
943  rd.vertex[1] = static_cast<float>(p.y+h);
944 
945  m_render_datas.push_back(rd);
946  rd.vertex[0] = static_cast<float>(p.x);
947  m_render_datas.push_back(rd);
948 
949  RenderObject ro(GL_LINE_LOOP, 4);
950  m_render_objects.push_back(ro);
951  }
952 
953  void RenderBackendOpenGLe::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
954  RenderData rd;
955  rd.vertex[0] = static_cast<float>(p.x);
956  rd.vertex[1] = static_cast<float>(p.y);
957  rd.color[0] = r;
958  rd.color[1] = g;
959  rd.color[2] = b;
960  rd.color[3] = a;
961  m_render_datas.push_back(rd);
962 
963  rd.vertex[1] = static_cast<float>(p.y+h);
964  m_render_datas.push_back(rd);
965 
966  rd.vertex[0] = static_cast<float>(p.x+w);
967  m_render_datas.push_back(rd);
968 
969  rd.vertex[1] = static_cast<float>(p.y);
970  m_render_datas.push_back(rd);
971 
972  RenderObject ro(GL_QUADS, 4);
973  m_render_objects.push_back(ro);
974  }
975 
976  void RenderBackendOpenGLe::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
977  RenderData rd;
978  rd.vertex[0] = static_cast<float>(p1.x);
979  rd.vertex[1] = static_cast<float>(p1.y);
980  rd.color[0] = r;
981  rd.color[1] = g;
982  rd.color[2] = b;
983  rd.color[3] = a;
984  m_render_datas.push_back(rd);
985 
986  rd.vertex[0] = static_cast<float>(p2.x);
987  rd.vertex[1] = static_cast<float>(p2.y);
988  m_render_datas.push_back(rd);
989 
990  rd.vertex[0] = static_cast<float>(p3.x);
991  rd.vertex[1] = static_cast<float>(p3.y);
992  m_render_datas.push_back(rd);
993 
994  rd.vertex[0] = static_cast<float>(p4.x);
995  rd.vertex[1] = static_cast<float>(p4.y);
996  m_render_datas.push_back(rd);
997 
998  RenderObject ro(GL_QUADS, 4);
999  m_render_objects.push_back(ro);
1000  }
1001 
1002  void RenderBackendOpenGLe::drawVertex(const Point& p, const uint8_t size, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1003  RenderData rd;
1004  rd.vertex[0] = static_cast<float>(p.x-size);
1005  rd.vertex[1] = static_cast<float>(p.y+size);
1006  rd.color[0] = r;
1007  rd.color[1] = g;
1008  rd.color[2] = b;
1009  rd.color[3] = a;
1010  m_render_datas.push_back(rd);
1011 
1012  rd.vertex[0] = static_cast<float>(p.x+size);
1013  m_render_datas.push_back(rd);
1014 
1015  rd.vertex[1] = static_cast<float>(p.y-size);
1016  m_render_datas.push_back(rd);
1017 
1018  rd.vertex[0] = static_cast<float>(p.x-size);
1019  m_render_datas.push_back(rd);
1020 
1021  RenderObject ro(GL_LINE_LOOP, 4);
1022  m_render_objects.push_back(ro);
1023  }
1024 
1025  void RenderBackendOpenGLe::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int32_t subdivisions,
1026  float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
1027  const float step = Mathf::twoPi()/subdivisions;
1028  RenderData rd;;
1029  for(float angle=0; angle<=Mathf::twoPi(); angle+=step){
1030  rd.vertex[0] = static_cast<float>(p.x);
1031  rd.vertex[1] = static_cast<float>(p.y);
1032  rd.color[0] = red;
1033  rd.color[1] = green;
1034  rd.color[2] = blue;
1035  rd.color[3] = intensity;
1036  m_render_datas.push_back(rd);
1037 
1038  rd.vertex[0] = radius*Mathf::Cos(angle+step)*xstretch + p.x;
1039  rd.vertex[1] = radius*Mathf::Sin(angle+step)*ystretch + p.y;
1040  rd.color[0] = 0;
1041  rd.color[1] = 0;
1042  rd.color[2] = 0;
1043  rd.color[3] = 255;
1044  m_render_datas.push_back(rd);
1045 
1046  rd.vertex[0] = radius*Mathf::Cos(angle)*xstretch + p.x;
1047  rd.vertex[1] = radius*Mathf::Sin(angle)*ystretch + p.y;
1048  m_render_datas.push_back(rd);
1049 
1050  RenderObject ro(GL_TRIANGLES, 3);
1051  m_render_objects.push_back(ro);
1052  }
1053  }
1054 
1055  void RenderBackendOpenGLe::addImageToArray(uint32_t id, const Rect& rect, float const* st, uint8_t alpha, uint8_t const* rgb) {
1056  RenderData rd;
1057  rd.vertex[0] = static_cast<float>(rect.x);
1058  rd.vertex[1] = static_cast<float>(rect.y);
1059  rd.texel[0] = st[0];
1060  rd.texel[1] = st[1];
1061  rd.color[0] = 255;
1062  rd.color[1] = 255;
1063  rd.color[2] = 255;
1064  rd.color[3] = alpha;
1065  m_render_datas.push_back(rd);
1066 
1067  rd.vertex[0] = static_cast<float>(rect.x);
1068  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1069  rd.texel[1] = st[3];
1070  m_render_datas.push_back(rd);
1071 
1072  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1073  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1074  rd.texel[0] = st[2];
1075  m_render_datas.push_back(rd);
1076 
1077  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1078  rd.vertex[1] = static_cast<float>(rect.y);
1079  rd.texel[1] = st[1];
1080  m_render_datas.push_back(rd);
1081 
1082  RenderObject ro(GL_QUADS, 4, id);
1083  m_render_objects.push_back(ro);
1084  }
1085 
1086  RenderBackendOpenGLe::RenderZObject* RenderBackendOpenGLe::getRenderBufferObject(GLuint texture_id, bool forceNewBatch) {
1087  if (!forceNewBatch) {
1088  for (std::vector<RenderZObject>::iterator it = m_renderZ_objects.begin(); it != m_renderZ_objects.end(); ++it) {
1089  if (it->texture_id == texture_id) {
1090  if (it->elements < it->max_size - 4) {
1091  return &(*it);
1092  }
1093  }
1094  }
1095  }
1096  static int last_forced = 0;
1097 
1098  // nothing was found (or we were forced to make new batch), we need to create new one
1099  RenderZObject obj;
1100  if (!m_renderZ_objects.empty()) {
1101  obj.index = m_renderZ_objects.back().index + m_renderZ_objects.back().max_size;
1102  obj.index += last_forced * 4;
1103  } else {
1104  obj.index = 0;
1105  }
1106  obj.texture_id = texture_id;
1107  obj.elements = 0;
1108  obj.max_size = forceNewBatch ? 4 : max_quads_per_texbatch * 4;
1109 
1110  if (!forceNewBatch) {
1111  last_forced = 0;
1112  m_renderZ_objects.push_back(obj);
1113  return &m_renderZ_objects.back();
1114  } else {
1115  ++last_forced;
1116  m_renderZ_objects_forced.push_back(obj);
1117  return &m_renderZ_objects_forced.back();
1118  }
1119  }
1120 
1121  void RenderBackendOpenGLe::addImageToArrayZ(uint32_t id, const Rect& rect, float vertexZ, float const* st, uint8_t alpha, bool forceNewBatch, uint8_t const* rgb) {
1122  if (alpha == 255) {
1123  if (rgb == NULL) {
1124  // ordinary z-valued quad
1125  RenderZObject* renderObj = getRenderBufferObject(id, forceNewBatch);
1126  uint32_t offset = renderObj->index + renderObj->elements;
1127  renderObj->elements += 4;
1128  RenderZData* rd;
1129 
1130  rd = &m_renderZ_datas[offset];
1131  rd->vertex[0] = static_cast<float>(rect.x);
1132  rd->vertex[1] = static_cast<float>(rect.y);
1133  rd->vertex[2] = vertexZ;
1134  rd->texel[0] = st[0];
1135  rd->texel[1] = st[1];
1136 
1137  ++rd;
1138  rd->vertex[0] = static_cast<float>(rect.x);
1139  rd->vertex[1] = static_cast<float>(rect.y+rect.h);
1140  rd->vertex[2] = vertexZ;
1141  rd->texel[0] = st[0];
1142  rd->texel[1] = st[3];
1143 
1144  ++rd;
1145  rd->vertex[0] = static_cast<float>(rect.x+rect.w);
1146  rd->vertex[1] = static_cast<float>(rect.y+rect.h);
1147  rd->vertex[2] = vertexZ;
1148  rd->texel[0] = st[2];
1149  rd->texel[1] = st[3];
1150 
1151  ++rd;
1152  rd->vertex[0] = static_cast<float>(rect.x+rect.w);
1153  rd->vertex[1] = static_cast<float>(rect.y);
1154  rd->vertex[2] = vertexZ;
1155  rd->texel[0] = st[2];
1156  rd->texel[1] = st[1];
1157  } else {
1158  // full opacity colored overlay
1159  RenderZData2T rd;
1160  rd.vertex[0] = static_cast<float>(rect.x);
1161  rd.vertex[1] = static_cast<float>(rect.y);
1162  rd.vertex[2] = vertexZ;
1163  rd.texel[0] = st[0];
1164  rd.texel[1] = st[1];
1165  rd.texel2[0] = 0.0;
1166  rd.texel2[1] = 0.0;
1167  rd.color[0] = 255;
1168  rd.color[1] = 255;
1169  rd.color[2] = 255;
1170  rd.color[3] = 255;
1171  m_render_datas2T.push_back(rd);
1172 
1173  rd.vertex[0] = static_cast<float>(rect.x);
1174  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1175  rd.texel[1] = st[3];
1176  rd.texel2[1] = 1.0;
1177  m_render_datas2T.push_back(rd);
1178 
1179  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1180  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1181  rd.texel[0] = st[2];
1182  rd.texel2[0] = 1.0;
1183  m_render_datas2T.push_back(rd);
1184 
1185  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1186  rd.vertex[1] = static_cast<float>(rect.y);
1187  rd.texel[1] = st[1];
1188  rd.texel2[1] = 0.0;
1189  m_render_datas2T.push_back(rd);
1190 
1191  RenderObject ro(GL_QUADS, 4, id);
1192  ro.rgb[0] = rgb[0];
1193  ro.rgb[1] = rgb[1];
1194  ro.rgb[2] = rgb[2];
1195  m_render_objects2T.push_back(ro);
1196  }
1197  } else {
1198  RenderZData2T rd;
1199  rd.vertex[0] = static_cast<float>(rect.x);
1200  rd.vertex[1] = static_cast<float>(rect.y);
1201  rd.vertex[2] = vertexZ;
1202  rd.texel[0] = st[0];
1203  rd.texel[1] = st[1];
1204  rd.color[0] = 255;
1205  rd.color[1] = 255;
1206  rd.color[2] = 255;
1207  rd.color[3] = alpha;
1208  m_render_trans_datas.push_back(rd);
1209 
1210  rd.vertex[0] = static_cast<float>(rect.x);
1211  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1212  rd.texel[1] = st[3];
1213  m_render_trans_datas.push_back(rd);
1214 
1215  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1216  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1217  rd.texel[0] = st[2];
1218  m_render_trans_datas.push_back(rd);
1219 
1220  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1221  rd.vertex[1] = static_cast<float>(rect.y);
1222  rd.texel[1] = st[1];
1223  m_render_trans_datas.push_back(rd);
1224 
1225  RenderObject ro(GL_QUADS, 4, id);
1226  if (rgb != NULL) {
1227  RenderObject ro(GL_QUADS, 4, id);
1228  ro.rgb[0] = rgb[0];
1229  ro.rgb[1] = rgb[1];
1230  ro.rgb[2] = rgb[2];
1231  }
1232  m_render_trans_objects.push_back(ro);
1233 
1234  }
1235  }
1236 
1237  void RenderBackendOpenGLe::prepareForOverlays() {
1238  glActiveTexture(GL_TEXTURE1);
1239  glEnable(GL_TEXTURE_2D);
1240 
1241  if(m_mask_overlays == 0) {
1242  // Constant texture - can be constant across every tilesets
1243  glGenTextures(1, &m_mask_overlays);
1244 
1245  uint8_t dummydata[3] = {127, 127, 127};
1246  glBindTexture(GL_TEXTURE_2D, m_mask_overlays);
1247  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1248  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1249  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1250  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1251  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0,
1252  GL_RGB, GL_UNSIGNED_BYTE, dummydata);
1253  } else {
1254  glBindTexture(GL_TEXTURE_2D, m_mask_overlays);
1255  }
1256 
1257  m_state.texture[1] = m_mask_overlays;
1258 
1259  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1260  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
1261  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
1262 
1263  // Arg0
1264  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
1265  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
1266  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
1267  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
1268 
1269  // The alpha component is taken only from 0th tex unit which is
1270  // Arg0 in our case, therefore we doesn't need to set operands
1271  // and sources for the rest of arguments
1272 
1273  // Arg1
1274  glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
1275  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
1276 
1277  // Arg2
1278  glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE1);
1279  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
1280 
1281  // Return to normal sampling mode
1282  glActiveTexture(GL_TEXTURE1);
1283  glDisable(GL_TEXTURE_2D);
1284  glActiveTexture(GL_TEXTURE0);
1285 
1286  // For now it's unneecessary - Only needed if we intend to use the 2nd texture unit in different case
1287  //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1288  }
1289 
1290  void RenderBackendOpenGLe::captureScreen(const std::string& filename) {
1291  const uint32_t swidth = getWidth();
1292  const uint32_t sheight = getHeight();
1293 
1294  uint8_t *pixels;
1295  SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24,
1296  RMASK, GMASK, BMASK, NULLMASK);
1297 
1298  if (!surface) {
1299  return;
1300  }
1301 
1302  SDL_LockSurface(surface);
1303  pixels = new uint8_t[swidth * sheight * 3];
1304  glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
1305  uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
1306  // Copy the "reversed_image" memory to the "image" memory
1307  for (int32_t y = (sheight - 1); y >= 0; --y) {
1308  uint8_t *rowbegin = pixels + y * swidth * 3;
1309  uint8_t *rowend = rowbegin + swidth * 3;
1310 
1311  std::copy(rowbegin, rowend, imagepixels);
1312 
1313  // Advance a row in the output surface.
1314  imagepixels += surface->pitch;
1315  }
1316 
1317  SDL_UnlockSurface(surface);
1318  Image::saveAsPng(filename, *surface);
1319 
1320  SDL_FreeSurface(surface);
1321  delete[] pixels;
1322  }
1323 
1324  void RenderBackendOpenGLe::captureScreen(const std::string& filename, uint32_t width, uint32_t height) {
1325  const uint32_t swidth = getWidth();
1326  const uint32_t sheight = getHeight();
1327  const bool same_size = (width == swidth && height == sheight);
1328 
1329  if (width < 1 || height < 1) {
1330  return;
1331  }
1332 
1333  if (same_size) {
1334  captureScreen(filename);
1335  return;
1336  }
1337 
1338  uint8_t *pixels;
1339  // create source surface
1340  SDL_Surface* src = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 32,
1341  RMASK, GMASK, BMASK, AMASK);
1342 
1343  if (!src) {
1344  return;
1345  }
1346 
1347  if (SDL_MUSTLOCK(src)) {
1348  SDL_LockSurface(src);
1349  }
1350  pixels = new uint8_t[swidth * sheight * 4];
1351  glReadPixels(0, 0, swidth, sheight, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
1352 
1353  uint8_t* imagepixels = reinterpret_cast<uint8_t*>(src->pixels);
1354  // Copy the "reversed_image" memory to the "image" memory
1355  for (int32_t y = (sheight - 1); y >= 0; --y) {
1356  uint8_t *rowbegin = pixels + y * swidth * 4;
1357  uint8_t *rowend = rowbegin + swidth * 4;
1358 
1359  std::copy(rowbegin, rowend, imagepixels);
1360 
1361  // Advance a row in the output surface.
1362  imagepixels += src->pitch;
1363  }
1364 
1365  // create destination surface
1366  SDL_Surface* dst = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
1367  RMASK, GMASK, BMASK, AMASK);
1368 
1369  uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
1370  uint32_t* src_help_pointer = src_pointer;
1371  uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
1372 
1373  int32_t x, y, *sx_ca, *sy_ca;
1374  int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
1375  int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
1376  int32_t sx_c = 0;
1377  int32_t sy_c = 0;
1378 
1379  // Allocates memory and calculates row wide&height
1380  int32_t* sx_a = new int32_t[dst->w + 1];
1381  sx_ca = sx_a;
1382  for (x = 0; x <= dst->w; x++) {
1383  *sx_ca = sx_c;
1384  sx_ca++;
1385  sx_c &= 0xffff;
1386  sx_c += sx;
1387  }
1388 
1389  int32_t* sy_a = new int32_t[dst->h + 1];
1390  sy_ca = sy_a;
1391  for (y = 0; y <= dst->h; y++) {
1392  *sy_ca = sy_c;
1393  sy_ca++;
1394  sy_c &= 0xffff;
1395  sy_c += sy;
1396  }
1397  sy_ca = sy_a;
1398 
1399  // Transfers the image data
1400 
1401  if (SDL_MUSTLOCK(dst)) {
1402  SDL_LockSurface(dst);
1403  }
1404 
1405  for (y = 0; y < dst->h; y++) {
1406  src_pointer = src_help_pointer;
1407  sx_ca = sx_a;
1408  for (x = 0; x < dst->w; x++) {
1409  *dst_pointer = *src_pointer;
1410  sx_ca++;
1411  src_pointer += (*sx_ca >> 16);
1412  dst_pointer++;
1413  }
1414  sy_ca++;
1415  src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
1416  }
1417 
1418  if (SDL_MUSTLOCK(dst)) {
1419  SDL_UnlockSurface(dst);
1420  }
1421  if (SDL_MUSTLOCK(src)) {
1422  SDL_UnlockSurface(src);
1423  }
1424 
1425  Image::saveAsPng(filename, *dst);
1426 
1427  // Free memory
1428  SDL_FreeSurface(src);
1429  SDL_FreeSurface(dst);
1430  delete[] sx_a;
1431  delete[] sy_a;
1432  delete[] pixels;
1433  }
1434 
1435  void RenderBackendOpenGLe::setClipArea(const Rect& cliparea, bool clear) {
1436  glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
1437  if (clear) {
1438  if (m_isbackgroundcolor) {
1439  float red = float(m_backgroundcolor.r/255.0);
1440  float green = float(m_backgroundcolor.g/255.0);
1441  float blue = float(m_backgroundcolor.b/255.0);
1442  glClearColor(red, green, blue, 0.0);
1443  m_isbackgroundcolor = false;
1444  }
1445  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1446  }
1447  }
1448 
1450  m_img_target = img;
1451  m_target_discard = discard;
1452 
1453  // to render on something, we need to make sure its loaded already in gpu memory
1454  m_img_target->forceLoadInternal();
1455  m_target = m_img_target->getSurface();
1456 
1457  GLeImage* glimage = static_cast<GLeImage*>(m_img_target.get());
1458 
1459  GLuint targetid = glimage->getTexId();
1460  uint32_t w = m_img_target->getWidth();
1461  uint32_t h = m_img_target->getHeight();
1462 
1463  // quick & dirty hack for attaching compressed texture
1464  if(glimage->isCompressed()) {
1465  bindTexture(targetid);
1466  GLubyte* pixels = new GLubyte[w*h*4];
1467  // here we get decompressed pixels
1468  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1469  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1470  delete [] pixels;
1471  glimage->setCompressed(false);
1472  }
1473 
1474  // can we use fbo?
1475  if (GLEE_EXT_framebuffer_object && m_useframebuffer) {
1476  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo_id);
1477  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1478  GL_TEXTURE_2D, targetid, 0);
1479  }
1480 
1481  glViewport(0, 0, w, h);
1482  glMatrixMode(GL_PROJECTION);
1483  glLoadIdentity();
1484  // invert top with bottom
1485  glOrtho(0, w, 0, h, -1, 1);
1486  glMatrixMode(GL_MODELVIEW);
1487  // because of inversion 2 lines above we need to also invert culling faces
1488  glCullFace(GL_FRONT);
1489 
1490  if (m_target_discard) {
1491  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1492  } else if (!m_target_discard && (!GLEE_EXT_framebuffer_object || !m_useframebuffer)) {
1493  // if we wanna just add something to render target, we need to first render previous contents
1494  addImageToArray(targetid, m_img_target->getArea(),
1495  static_cast<GLeImage*>(m_img_target.get())->getTexCoords(), 255, 0);
1496  // flush it down
1497  renderWithoutZ();
1498  }
1499  }
1500 
1502  assert(m_target != m_screen);
1503 
1504  // flush down what we batched
1506 
1507  if (GLEE_EXT_framebuffer_object && m_useframebuffer) {
1508  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1509  } else {
1510  bindTexture(0, static_cast<GLeImage*>(m_img_target.get())->getTexId());
1511  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0,
1512  m_img_target->getWidth(), m_img_target->getHeight(), 0);
1513  glClear(GL_DEPTH_BUFFER_BIT);
1514  }
1515 
1516  m_target = m_screen;
1517  glViewport(0, 0, m_screen->w, m_screen->h);
1518  glMatrixMode(GL_PROJECTION);
1519  glLoadIdentity();
1520  glOrtho(0, m_screen->w, m_screen->h, 0, znear, zfar);
1521  glMatrixMode(GL_MODELVIEW);
1522  glCullFace(GL_BACK);
1523  }
1524 }