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