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