FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
renderbackendopengl.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 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 {
43  static Logger _log(LM_VIDEO);
44 
46  public:
47  RenderObject(GLenum m, uint16_t s, uint32_t t1=0, uint32_t t2=0):
48  mode(m),
49  size(s),
50  texture_id(t1),
51  overlay_id(t2),
52  src(4),
53  dst(5),
54  light(true),
55  stencil_test(false),
56  color(true),
58  stencil_ref(0),
59  stencil_op(0),
60  stencil_func(0) {}
61 
62  GLenum mode;
66  int32_t src;
67  int32_t dst;
68  bool light;
70  bool color;
73  GLenum stencil_op;
74  GLenum stencil_func;
76  };
77 
78  RenderBackendOpenGL::RenderBackendOpenGL(const SDL_Color& colorkey)
79  : RenderBackend(colorkey), m_maskOverlay(0){
80 
81  m_state.tex_enabled[0] = false;
82  m_state.tex_enabled[1] = false;
83  m_state.tex_enabled[2] = false;
84  m_state.tex_enabled[3] = false;
85  m_state.texture[0] = 0;
86  m_state.texture[1] = 0;
87  m_state.texture[2] = 0;
88  m_state.texture[3] = 0;
89  m_state.active_tex = 0;
90  m_state.alpha_test = 0.0;
93  m_state.tex_pointer[0] = 0;
94  m_state.tex_pointer[1] = 0;
95  m_state.tex_pointer[2] = 0;
96  m_state.tex_pointer[3] = 0;
98 
99  m_state.sten_enabled = false;
100  m_state.sten_ref = 0;
101  m_state.sten_buf = 0;
102  m_state.sten_op = 0;
103  m_state.sten_func = 0;
104 
105  m_state.lightmodel = 0;
106  m_state.light_enabled = false;
107 
108  m_state.env_color[0] = 0;
109  m_state.env_color[1] = 0;
110  m_state.env_color[2] = 0;
111  m_state.env_color[3] = 0;
112  m_state.blend_src = GL_SRC_ALPHA;
113  m_state.blend_dst = GL_ONE_MINUS_SRC_ALPHA;
114  m_state.alpha_enabled = true;
115  m_state.scissor_test = true;
116  m_state.depth_enabled = true;
117  m_state.color_enabled = true;
118  }
119 
121  glDeleteTextures(1, &m_maskOverlay);
122  if(GLEW_EXT_framebuffer_object && m_useframebuffer) {
123  glDeleteFramebuffers(1, &m_fbo_id);
124  }
125  SDL_GL_DeleteContext(m_context);
126  SDL_DestroyWindow(m_window);
127  deinit();
128  }
129 
130  const std::string& RenderBackendOpenGL::getName() const {
131  static std::string backend_name = "OpenGL";
132  return backend_name;
133  }
134 
135  void RenderBackendOpenGL::init(const std::string& driver) {
136  Uint32 flags = SDL_INIT_VIDEO;
137  if (SDL_InitSubSystem(flags) < 0) {
138  throw SDLException(SDL_GetError());
139  }
140  if (driver != "") {
141  if (SDL_VideoInit(driver.c_str()) < 0) {
142  throw SDLException(SDL_GetError());
143  }
144  }
145 
146  // setup OpenGL
147  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
148  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
149 
150  // defines buffer sizes
151  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
152  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
153  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
154  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
155  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
156  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
157  SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
158  //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
159  }
160 
163  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
165  }
166 
167  void RenderBackendOpenGL::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
168  setScreenMode(mode);
169  if (m_window) {
170  if (icon != "") {
171  SDL_Surface *img = IMG_Load(icon.c_str());
172  if (img != NULL) {
173  SDL_SetWindowIcon(m_window, img);
174  SDL_FreeSurface(img);
175  }
176  }
177  SDL_SetWindowTitle(m_window, title.c_str());
178  }
179  }
180 
182  bool recreate = m_window != NULL;
183  uint16_t width = mode.getWidth();
184  uint16_t height = mode.getHeight();
185  uint16_t bitsPerPixel = mode.getBPP();
186  uint32_t flags = mode.getSDLFlags();
187  // in case of recreating
188  if (recreate) {
189  SDL_DestroyWindow(m_window);
190  m_window = NULL;
191  m_screen = NULL;
192 
193  if (GLEW_EXT_framebuffer_object && m_useframebuffer) {
194  glDeleteFramebuffers(1, &m_fbo_id);
195  }
196  }
197  // create window
198  uint8_t displayIndex = mode.getDisplay();
199  if (mode.isFullScreen()) {
200  m_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), width, height, flags | SDL_WINDOW_SHOWN);
201  } else {
202  m_window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), width, height, flags | SDL_WINDOW_SHOWN);
203  }
204 
205  if (!m_window) {
206  throw SDLException(SDL_GetError());
207  }
208  // make sure the window have the right settings
209  SDL_DisplayMode displayMode;
210  displayMode.format = mode.getFormat();
211  displayMode.w = width;
212  displayMode.h = height;
213  displayMode.refresh_rate = mode.getRefreshRate();
214  if (SDL_SetWindowDisplayMode(m_window, &displayMode) != 0) {
215  throw SDLException(SDL_GetError());
216  }
217 
218  // create render context or use the old with new window
219  if (recreate) {
220  if (SDL_GL_MakeCurrent(m_window, m_context) < 0) {
221  throw SDLException(SDL_GetError());
222  }
223  } else {
224  m_context = SDL_GL_CreateContext(m_window);
225  }
226  // set the window surface as main surface, not really needed anymore
227  m_screen = SDL_GetWindowSurface(m_window);
228  m_target = m_screen;
229  if (!m_screen) {
230  throw SDLException(SDL_GetError());
231  }
232 
233  // initialize GLEW
234  glewExperimental = GL_TRUE;
235  GLenum glewError = glewInit();
236  if (glewError != GLEW_OK) {
237  FL_LOG(_log, LMsg("RenderBackendOpenGL") << "Error initializing GLEW!" << glewGetErrorString(glewError));
238  }
239 
240  FL_LOG(_log, LMsg("RenderBackendOpenGL")
241  << "Videomode " << width << "x" << height
242  << " at " << int32_t(bitsPerPixel) << " bpp with " << displayMode.refresh_rate << " Hz");
243 
244  // this is needed, otherwise we would have screen pixel formats which will not work with
245  // our texture generation. 32 bit surfaces to BitsPerPixel texturen.
246  m_rgba_format = *(m_screen->format);
247  if (bitsPerPixel != 16) {
248  m_rgba_format.format = SDL_PIXELFORMAT_RGBA8888;
249  m_rgba_format.BitsPerPixel = 32;
250  } else {
251  m_rgba_format.format = SDL_PIXELFORMAT_RGBA4444;
252  m_rgba_format.BitsPerPixel = 16;
253  }
254  m_rgba_format.Rmask = RMASK;
255  m_rgba_format.Gmask = GMASK;
256  m_rgba_format.Bmask = BMASK;
257  m_rgba_format.Amask = AMASK;
258 
259  //update the screen mode with the actual flags used
260  m_screenMode = mode;
261 
262  glViewport(0, 0, width, height);
263  glMatrixMode(GL_PROJECTION);
264  glLoadIdentity();
265  glOrtho(0, width, height, 0, -100, 100);
266  glMatrixMode(GL_MODELVIEW);
267  glLoadIdentity();
268 
269  glEnable(GL_CULL_FACE);
270  glFrontFace(GL_CCW);
271  glCullFace(GL_BACK);
272 
273  glPixelStorei(GL_PACK_ALIGNMENT, 1);
274  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
275 
276  // dont reset
277  if (!recreate) {
278  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
279  glClearDepth(1.0f);
280  glClearStencil(0);
281  }
282 
283  glEnable(GL_BLEND);
284  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
285 
287 
288  glEnable(GL_DEPTH_TEST);
289  glDepthFunc(GL_LEQUAL);
290 
291  glEnable(GL_SCISSOR_TEST);
292 
293  glEnableClientState(GL_COLOR_ARRAY);
294  glEnableClientState(GL_VERTEX_ARRAY);
295 
297 
298  glPointSize(1.0);
299  glLineWidth(1.0);
300 
301  if(GLEW_EXT_framebuffer_object && m_useframebuffer) {
302  glGenFramebuffers(1, &m_fbo_id);
303  }
304 
306  if (GLEW_EXT_texture_filter_anisotropic) {
307  GLint largest = 0;
308  glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest);
309  m_maxAnisotropy = static_cast<int32_t>(largest);
310  } else {
311  // if not available use trilinear filter
312  m_maxAnisotropy = 0;
314  }
315  }
316 
317  // sync swaping with refresh rate if VSync is enabled
318  SDL_GL_SetSwapInterval(static_cast<uint8_t>(m_vSync));
319 
320  // currently unused, 1000 objects x 400 textures x 4 renderDataZ
321  //m_renderZ_datas.resize(1600000);
322 
323  // 6 indices x 100000 objects
324  m_indices.resize(600000);
325  // a rough way to fill the index buffer, result is: 0, 1, 2, 0, 2, 3 | 4, 5, 6, 4, 6, 7
326  uint32_t index = 0;
327  for(std::vector<uint32_t>::size_type i = 0; i != m_indices.size(); i+=6) {
328  m_indices[i] = index;
329  m_indices[i+1] = index+1;
330  m_indices[i+2] = index+2;
331  m_indices[i+3] = index;
332  m_indices[i+4] = index+2;
333  m_indices[i+5] = index+3;
334  index += 4;
335  }
336 
337  // currently unused, create buffer and send data
338  //glGenBuffers(1, &m_indicebufferId);
339  //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indicebufferId);
340  //glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32_t), &indices[0], GL_STATIC_DRAW);
341  //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
342  }
343 
346  }
347 
349  if (m_window) {
350  SDL_GL_SwapWindow(m_window);
351  }
353  }
354 
356  return new GLImage(loader);
357  }
358 
359  Image* RenderBackendOpenGL::createImage(const std::string& name, IResourceLoader* loader) {
360  return new GLImage(name, loader);
361  }
362 
363  Image* RenderBackendOpenGL::createImage(SDL_Surface* surface) {
364  // Given an abritary surface, we must convert it to the format GLImage will understand.
365  // It's easiest to let SDL do this for us.
366 
367  // Uh. Gotta love this :-)
368  // Check for colorkey too?
369  // Leave out the loss/shift checks?
370  if (32 == surface->format->BitsPerPixel
371  && m_rgba_format.Rmask == surface->format->Rmask
372  && m_rgba_format.Gmask == surface->format->Gmask
373  && m_rgba_format.Bmask == surface->format->Bmask
374  && m_rgba_format.Amask == surface->format->Amask
375  && m_rgba_format.Rshift == surface->format->Rshift
376  && m_rgba_format.Gshift == surface->format->Gshift
377  && m_rgba_format.Bshift == surface->format->Bshift
378  && m_rgba_format.Ashift == surface->format->Ashift
379  && m_rgba_format.Rloss == surface->format->Rloss
380  && m_rgba_format.Gloss == surface->format->Gloss
381  && m_rgba_format.Bloss == surface->format->Bloss
382  && m_rgba_format.Aloss == surface->format->Aloss) {
383 
384  return new GLImage(surface);
385  }
386 
387  uint8_t bpp = m_rgba_format.BitsPerPixel;
388  m_rgba_format.BitsPerPixel = 32;
389  SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, 0);
390  m_rgba_format.BitsPerPixel = bpp;
391  GLImage* image = new GLImage(conv);
392 
393  SDL_FreeSurface(surface);
394  return image;
395  }
396 
397  Image* RenderBackendOpenGL::createImage(const std::string& name, SDL_Surface* surface) {
398  // Given an abritary surface, we must convert it to the format GLImage will understand.
399  // It's easiest to let SDL do this for us.
400 
401  // Uh. Gotta love this :-)
402  // Check for colorkey too?
403  // Leave out the loss/shift checks?
404  if (32 == surface->format->BitsPerPixel
405  && m_rgba_format.Rmask == surface->format->Rmask
406  && m_rgba_format.Gmask == surface->format->Gmask
407  && m_rgba_format.Bmask == surface->format->Bmask
408  && m_rgba_format.Amask == surface->format->Amask
409  && m_rgba_format.Rshift == surface->format->Rshift
410  && m_rgba_format.Gshift == surface->format->Gshift
411  && m_rgba_format.Bshift == surface->format->Bshift
412  && m_rgba_format.Ashift == surface->format->Ashift
413  && m_rgba_format.Rloss == surface->format->Rloss
414  && m_rgba_format.Gloss == surface->format->Gloss
415  && m_rgba_format.Bloss == surface->format->Bloss
416  && m_rgba_format.Aloss == surface->format->Aloss) {
417 
418  return new GLImage(name, surface);
419  }
420 
421  uint8_t bpp = m_rgba_format.BitsPerPixel;
422  m_rgba_format.BitsPerPixel = 32;
423  SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, 0);
424  m_rgba_format.BitsPerPixel = bpp;
425  GLImage* image = new GLImage(name, conv);
426 
427  SDL_FreeSurface(surface);
428  return image;
429  }
430 
432  return new GLImage(data, width, height);
433  }
434 
435  Image* RenderBackendOpenGL::createImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height) {
436  return new GLImage(name, data, width, height);
437  }
438 
440  if (m_state.lightmodel != lighting) {
441  if (m_state.lightmodel != 0) {
442  disableLighting();
443  glDisable(GL_COLOR_MATERIAL);
444  } else if (lighting != 0) {
445  enableLighting();
446  glEnable(GL_LIGHT0);
447  glColorMaterial(GL_FRONT, GL_DIFFUSE);
448  glEnable(GL_COLOR_MATERIAL);
449  }
450  m_state.lightmodel = lighting;
451  }
452  }
453 
455  return m_state.lightmodel;
456  }
457 
459  if(m_state.tex_enabled[texUnit] == false) {
460  if(m_state.active_tex != texUnit) {
461  m_state.active_tex = texUnit;
462  glActiveTexture(GL_TEXTURE0 + texUnit);
463  }
464  if (m_state.active_client_tex != texUnit) {
465  m_state.active_client_tex = texUnit;
466  glClientActiveTexture(GL_TEXTURE0 + texUnit);
467  }
468  m_state.tex_enabled[texUnit] = true;
469 
470  glEnable(GL_TEXTURE_2D);
471  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
472  }
473  }
474 
476  if(m_state.tex_enabled[texUnit] == true) {
477  if(m_state.active_tex != texUnit) {
478  m_state.active_tex = texUnit;
479  glActiveTexture(GL_TEXTURE0 + texUnit);
480  }
481  if (m_state.active_client_tex != texUnit) {
482  m_state.active_client_tex = texUnit;
483  glClientActiveTexture(GL_TEXTURE0 + texUnit);
484  }
485  m_state.tex_enabled[texUnit] = false;
486 
487  glDisable(GL_TEXTURE_2D);
488  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
489  }
490  }
491 
492  void RenderBackendOpenGL::bindTexture(uint32_t texUnit, GLuint texId) {
493  enableTextures(texUnit);
494 
495  if(m_state.texture[texUnit] != texId) {
496  if(m_state.active_tex != texUnit) {
497  m_state.active_tex = texUnit;
498  glActiveTexture(GL_TEXTURE0 + texUnit);
499  }
500  if (m_state.active_client_tex != texUnit) {
501  m_state.active_client_tex = texUnit;
502  glClientActiveTexture(GL_TEXTURE0 + texUnit);
503  }
504  m_state.texture[texUnit] = texId;
505  glBindTexture(GL_TEXTURE_2D, texId);
506  }
507  }
508 
509  void RenderBackendOpenGL::bindTexture(GLuint texId) {
510  if(m_state.texture[m_state.active_tex] != texId) {
512  glBindTexture(GL_TEXTURE_2D, texId);
513  }
514  }
515 
517  if (m_state.lightmodel != 0 && !m_state.light_enabled) {
518  glEnable(GL_LIGHTING);
519  m_state.light_enabled = true;
520  }
521  }
522 
524  if (m_state.lightmodel != 0 && m_state.light_enabled) {
525  glDisable(GL_LIGHTING);
526  m_state.light_enabled = false;
527  }
528  }
529 
530  void RenderBackendOpenGL::setLighting(float red, float green, float blue) {
531  if (m_state.lightmodel != 0) {
532  GLfloat lightDiffuse[] = {red, green, blue, 1.0f};
533  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
534  }
535  }
536 
538  if (m_state.lightmodel != 0) {
539  setLighting(1.0, 1.0, 1.0);
540  }
541  }
542 
544  if (!m_state.sten_enabled) {
545  glEnable(GL_STENCIL_TEST);
546  m_state.sten_enabled = true;
547  }
548  }
549 
551  if (m_state.sten_enabled) {
552  glDisable(GL_STENCIL_TEST);
553  m_state.sten_enabled = false;
554  }
555  }
556 
557  void RenderBackendOpenGL::setStencilTest(uint8_t stencil_ref, GLenum stencil_op, GLenum stencil_func) {
559  if(m_state.sten_op != stencil_op) {
560  m_state.sten_op = stencil_op;
561  glStencilOp(GL_KEEP, GL_KEEP, m_state.sten_op);
562  }
563 
564  if(m_state.sten_ref != stencil_ref || m_state.sten_func != stencil_func) {
565  m_state.sten_ref = stencil_ref;
566  m_state.sten_func = stencil_func;
567  glStencilFunc(m_state.sten_func, stencil_ref, 0xff);
568  }
569  }
570 
572  if (buffer != m_state.sten_buf) {
573  m_state.sten_buf = buffer;
574  glClearStencil(buffer);
575  }
577  glClear(GL_STENCIL_BUFFER_BIT);
579  }
580 
582  return m_state.sten_ref;
583  }
584 
586  if (!m_state.alpha_enabled) {
587  glEnable(GL_ALPHA_TEST);
588  m_state.alpha_enabled = true;
589  }
590  }
591 
593  if (m_state.alpha_enabled) {
594  glDisable(GL_ALPHA_TEST);
595  m_state.alpha_enabled = false;
596  }
597  }
598 
599  void RenderBackendOpenGL::setAlphaTest(float ref_alpha) {
600  enableAlphaTest();
601  if (!Mathf::Equal(m_state.alpha_test, ref_alpha)) {
602  m_state.alpha_test = ref_alpha;
603  glAlphaFunc(GL_GREATER, ref_alpha);
604  }
605  }
606 
608  if (!m_state.depth_enabled) {
609  glEnable(GL_DEPTH_TEST);
610  m_state.depth_enabled = true;
611  }
612  }
613 
615  if (m_state.depth_enabled) {
616  glDisable(GL_DEPTH_TEST);
617  m_state.depth_enabled = false;
618  }
619  }
620 
622  if (!m_state.color_enabled) {
623  glEnableClientState(GL_COLOR_ARRAY);
624  m_state.color_enabled = true;
625  }
626  }
627 
629  if (m_state.color_enabled) {
630  glDisableClientState(GL_COLOR_ARRAY);
631  glColor4ub(255,255,255,255);
632  m_state.color_enabled = false;
633  }
634  }
635 
637  if (memcmp(m_state.env_color, rgba, sizeof(uint8_t) * 4) || m_state.active_tex != texUnit) {
638 
639  memcpy(m_state.env_color, rgba, sizeof(uint8_t) * 4);
640  GLfloat rgbaf[4] = {
641  static_cast<float>(m_state.env_color[0]) / 255.0f,
642  static_cast<float>(m_state.env_color[1]) / 255.0f,
643  static_cast<float>(m_state.env_color[2]) / 255.0f,
644  static_cast<float>(m_state.env_color[3]) / 255.0f};
645 
646  if(m_state.active_tex != texUnit) {
647  m_state.active_tex = texUnit;
648  glActiveTexture(GL_TEXTURE0 + texUnit);
649  m_state.active_client_tex = texUnit;
650  glClientActiveTexture(GL_TEXTURE0 + texUnit);
651  }
652 
653  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgbaf);
654  }
655  }
656 
657  void RenderBackendOpenGL::setVertexPointer(GLint size, GLsizei stride, const GLvoid* ptr) {
658  if(m_state.vertex_pointer != ptr || m_state.vertex_pointer_size != size) {
659  m_state.vertex_pointer = ptr;
661  glVertexPointer(size, GL_FLOAT, stride, ptr);
662  }
663  }
664 
665  void RenderBackendOpenGL::setColorPointer(GLsizei stride, const GLvoid* ptr) {
666  if(m_state.color_pointer != ptr) {
667  m_state.color_pointer = ptr;
668  glColorPointer(4, GL_UNSIGNED_BYTE, stride, ptr);
669  }
670  }
671 
672  void RenderBackendOpenGL::setTexCoordPointer(uint32_t texUnit, GLsizei stride, const GLvoid* ptr) {
673  if(m_state.tex_pointer[texUnit] != ptr) {
674  if(m_state.active_tex != texUnit) {
675  m_state.active_tex = texUnit;
676  glActiveTexture(GL_TEXTURE0 + texUnit);
677  }
678  if (m_state.active_client_tex != texUnit) {
679  m_state.active_client_tex = texUnit;
680  glClientActiveTexture(GL_TEXTURE0 + texUnit);
681  }
682  m_state.tex_pointer[texUnit] = ptr;
683  glTexCoordPointer(2, GL_FLOAT, stride, ptr);
684  }
685  }
686 
688  if(m_state.scissor_test == false) {
689  m_state.scissor_test = true;
690  glEnable(GL_SCISSOR_TEST);
691  }
692  }
693 
695  if(m_state.scissor_test == true) {
696  m_state.scissor_test = false;
697  glDisable(GL_SCISSOR_TEST);
698  }
699  }
700 
701  void RenderBackendOpenGL::changeBlending(int32_t src, int32_t dst) {
702  GLenum src_fact;
703  GLenum dst_fact;
704 
705  switch(src) {
706  case 0 : src_fact = GL_ZERO; break;
707  case 1 : src_fact = GL_ONE; break;
708  case 2 : src_fact = GL_DST_COLOR; break;
709  case 3 : src_fact = GL_ONE_MINUS_DST_COLOR; break;
710  case 4 : src_fact = GL_SRC_ALPHA; break;
711  case 5 : src_fact = GL_ONE_MINUS_SRC_ALPHA; break;
712  case 6 : src_fact = GL_DST_ALPHA; break;
713  case 7 : src_fact = GL_ONE_MINUS_DST_ALPHA; break;
714 
715  default : src_fact = GL_DST_COLOR; break;
716  }
717 
718  switch(dst) {
719  case 0 : dst_fact = GL_ZERO; break;
720  case 1 : dst_fact = GL_ONE; break;
721  case 2 : dst_fact = GL_SRC_COLOR; break;
722  case 3 : dst_fact = GL_ONE_MINUS_SRC_COLOR; break;
723  case 4 : dst_fact = GL_SRC_ALPHA; break;
724  case 5 : dst_fact = GL_ONE_MINUS_SRC_ALPHA; break;
725  case 6 : dst_fact = GL_DST_ALPHA; break;
726  case 7 : dst_fact = GL_ONE_MINUS_DST_ALPHA; break;
727 
728  default : dst_fact = GL_SRC_ALPHA; break;
729  }
730 
731  if (m_state.blend_src != src_fact || m_state.blend_dst != dst_fact) {
732  m_state.blend_src = src_fact;
733  m_state.blend_dst = dst_fact;
734  glBlendFunc(src_fact, dst_fact);
735  }
736  }
737 
738  void RenderBackendOpenGL::changeRenderInfos(RenderDataType type, uint16_t elements, int32_t src, int32_t dst, bool light,
739  bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc, OverlayType otype) {
740 
741  uint16_t count = 0;
742  switch (type) {
743  case RENDER_DATA_WITHOUT_Z: {
744  uint32_t size = m_renderObjects.size();
745  while (count != elements) {
746  ++count;
747  RenderObject& r = m_renderObjects.at(size-count);
748 
749  r.src = src;
750  r.dst = dst;
751  r.light = light;
752  r.overlay_type = otype;
753  if (stentest) {
754  r.stencil_test = stentest;
755  r.stencil_ref = stenref;
756  r.stencil_op = stenop;
757  r.stencil_func = stenfunc;
758  }
759  }
760  } break;
761  case RENDER_DATA_TEXTURE_Z: {
762  // not needed currently
763  } break;
764  case RENDER_DATA_TEXCOLOR_Z : {
765  // not needed currently
766  } break;
769  while (count != elements) {
770  ++count;
771  RenderObject& r = m_renderMultitextureObjectsZ.at(size-count);
772  // only overlay_type is important
773  r.src = src;
774  r.dst = dst;
775  r.light = light;
776  r.overlay_type = otype;
777  if (stentest) {
778  r.stencil_test = stentest;
779  r.stencil_ref = stenref;
780  r.stencil_op = stenop;
781  r.stencil_func = stenfunc;
782  }
783  }
784  } break;
785  default: {
786  // nothing
787  } break;
788  }
789  }
790 
792  // bools to indicate changes
793  bool type = false;
794  bool texture = false;
795  bool blending = false;
796  bool light = false;
797  bool stencil = false;
798  bool color = false;
799  bool mt = false;
800  bool render = false;
801 
802  // render mode
803  GLenum mode = GL_TRIANGLES;
804  // texture id
805  uint32_t texture_id = 0;
806  uint32_t texture_id2 = 0;
807  // src blending mode
808  int32_t src = 4;
809  // dst blending mode
810  int32_t dst = 5;
811  // overlay type
812  OverlayType overlay_type = OVERLAY_TYPE_NONE;
813  // overlay color
814  uint8_t rgba[4] = {0};
815 
816  // array indices
817  int32_t indexP = 0;
818  int32_t indexT = 0;
819  int32_t indexTC = 0;
820  int32_t index2TC = 0;
821  // elements to render
822  uint32_t elementsP = 0;
823  uint32_t elementsT = 0;
824  uint32_t elementsTC = 0;
825  uint32_t elements2TC = 0;
826 
827  int32_t* currentIndex = 0;
828  uint32_t* currentElements = 0;
829 
830  // index buffer pointer
831  uint32_t* indexBuffer = 0;
832 
833  //stride
834  const uint32_t strideP = sizeof(renderDataP);
835  const uint32_t strideT = sizeof(renderDataT);
836  const uint32_t strideTC = sizeof(renderDataTC);
837  const uint32_t stride2TC = sizeof(renderData2TC);
838 
839  // disable alpha and depth tests
842 
843  if (m_renderObjects[0].overlay_type == OVERLAY_TYPE_NONE) {
844  // texture without color/alpha
845  if (!m_renderObjects[0].color) {
846  // set pointer
848  setVertexPointer(2, strideT, &m_renderTextureDatas[0].vertex);
849  setTexCoordPointer(0, strideT, &m_renderTextureDatas[0].texel);
850  indexBuffer = &m_tIndices[0];
851  currentIndex = &indexT;
852  currentElements = &elementsT;
853  // texture with color/alpha
854  } else if (m_renderObjects[0].texture_id != 0){
855  // set pointer
857  setVertexPointer(2, strideTC, &m_renderTextureColorDatas[0].vertex);
858  setTexCoordPointer(0, strideTC, &m_renderTextureColorDatas[0].texel);
859  setColorPointer(strideTC, &m_renderTextureColorDatas[0].color);
860  indexBuffer = &m_tcIndices[0];
861  currentIndex = &indexTC;
862  currentElements = &elementsTC;
863  // primitive
864  } else {
865  // set pointer
867  setVertexPointer(2, strideP, &m_renderPrimitiveDatas[0].vertex);
868  setColorPointer(strideP, &m_renderPrimitiveDatas[0].color);
869  indexBuffer = &m_pIndices[0];
870  currentIndex = &indexP;
871  currentElements = &elementsP;
872  }
873  // multitexture overlay
874  } else {
875  // set pointer
876  setVertexPointer(2, stride2TC, &m_renderMultitextureDatas[0].vertex);
877  setColorPointer(stride2TC, &m_renderMultitextureDatas[0].color);
878  setTexCoordPointer(0, stride2TC, &m_renderMultitextureDatas[0].texel);
879  indexBuffer = &m_tc2Indices[0];
880  currentIndex = &index2TC;
881  currentElements = &elements2TC;
882  }
883 
884  for(std::vector<RenderObject>::iterator ir = m_renderObjects.begin(); ir != m_renderObjects.end(); ++ir) {
885  RenderObject& ro = (*ir);
886 
887  // first we look for changes
888  if (ro.mode != mode) {
889  type = true;
890  render = true;
891  } else if (ro.mode == GL_LINE_STRIP || ro.mode == GL_LINE_LOOP) {
892  // do not batch line strips, loops or triangle fans to avoid side effects
893  render = true;
894  }
895  if (ro.texture_id != texture_id) {
896  texture = true;
897  render = true;
898  }
899  if (ro.color != m_state.color_enabled) {
900  color = true;
901  render = true;
902  }
903  if (ro.overlay_type != overlay_type ||
904  (ro.overlay_type != OVERLAY_TYPE_NONE && (memcmp(rgba, ro.rgba, sizeof(uint8_t) * 4) || ro.overlay_id != texture_id2))) {
905  mt = true;
906  render = true;
907  }
908  if (m_state.lightmodel) {
909  if (ro.src != src || ro.dst != dst) {
910  blending = true;
911  render = true;
912  }
913  if (ro.light != m_state.light_enabled) {
914  light = true;
915  render = true;
916  }
917  if (ro.stencil_test != m_state.sten_enabled) {
918  stencil = true;
919  render = true;
920  } else if (ro.stencil_test) {
921  if (ro.stencil_ref != m_state.sten_ref ||
922  ro.stencil_op != m_state.sten_op ||
924  stencil = true;
925  render = true;
926  }
927  }
928  }
929 
930  // if changes then we render all previously elements
931  if (render) {
932  if (*currentElements > 0) {
933  //render
934  glDrawElements(mode, *currentElements, GL_UNSIGNED_INT, indexBuffer + *currentIndex);
935  *currentIndex += *currentElements;
936  }
937  // switch mode
938  if (type) {
939  mode = ro.mode;
940  type = false;
941  }
942  // switch coloring
943  if (color) {
944  if (ro.color && !m_state.color_enabled) {
946  if (ro.overlay_type == OVERLAY_TYPE_NONE) {
947  if (ro.texture_id != 0) {
948  setVertexPointer(2, strideTC, &m_renderTextureColorDatas[0].vertex);
949  setTexCoordPointer(0, strideTC, &m_renderTextureColorDatas[0].texel);
950  setColorPointer(strideTC, &m_renderTextureColorDatas[0].color);
951  indexBuffer = &m_tcIndices[0];
952  currentElements = &elementsTC;
953  currentIndex = &indexTC;
954  } else {
955  setVertexPointer(2, strideP, &m_renderPrimitiveDatas[0].vertex);
956  setColorPointer(strideP, &m_renderPrimitiveDatas[0].color);
957  indexBuffer = &m_pIndices[0];
958  currentElements = &elementsP;
959  currentIndex = &indexP;
960  }
961  }
962  } else if (!ro.color && m_state.color_enabled) {
964  if (ro.overlay_type == OVERLAY_TYPE_NONE) {
965  setVertexPointer(2, strideT, &m_renderTextureDatas[0].vertex);
966  setTexCoordPointer(0, strideT, &m_renderTextureDatas[0].texel);
967  indexBuffer = &m_tIndices[0];
968  currentElements = &elementsT;
969  currentIndex = &indexT;
970  }
971  }
972  color = false;
973  }
974  // multitexturing
975  if (mt) {
976  switch (ro.overlay_type) {
977  case OVERLAY_TYPE_NONE:
978  disableTextures(3);
979  disableTextures(2);
980  disableTextures(1);
981 
982  if (ro.texture_id != 0) {
983  enableTextures(0);
984  if (m_state.color_enabled) {
985  setVertexPointer(2, strideTC, &m_renderTextureColorDatas[0].vertex);
986  setTexCoordPointer(0, strideTC, &m_renderTextureColorDatas[0].texel);
987  setColorPointer(strideTC, &m_renderTextureColorDatas[0].color);
988  indexBuffer = &m_tcIndices[0];
989  currentElements = &elementsTC;
990  currentIndex = &indexTC;
991  } else {
992  setVertexPointer(2, strideT, &m_renderTextureDatas[0].vertex);
993  setTexCoordPointer(0, strideT, &m_renderTextureDatas[0].texel);
994  indexBuffer = &m_tIndices[0];
995  currentIndex = &indexT;
996  currentElements = &elementsT;
997  }
998  } else {
999  setVertexPointer(2, strideP, &m_renderPrimitiveDatas[0].vertex);
1000  setColorPointer(strideP, &m_renderPrimitiveDatas[0].color);
1001  indexBuffer = &m_pIndices[0];
1002  currentElements = &elementsP;
1003  currentIndex = &indexP;
1004  }
1005  texture_id2 = 0;
1006  break;
1007  case OVERLAY_TYPE_COLOR:
1008  disableTextures(3);
1009  disableTextures(2);
1011  setEnvironmentalColor(1, ro.rgba);
1012  enableTextures(0);
1013 
1014  // set pointer
1015  setVertexPointer(2, stride2TC, &m_renderMultitextureDatas[0].vertex);
1016  setColorPointer(stride2TC, &m_renderMultitextureDatas[0].color);
1017  setTexCoordPointer(1, stride2TC, &m_renderMultitextureDatas[0].texel2);
1018  setTexCoordPointer(0, stride2TC, &m_renderMultitextureDatas[0].texel);
1019  indexBuffer = &m_tc2Indices[0];
1020 
1021  texture_id2 = m_maskOverlay;
1022  currentElements = &elements2TC;
1023  currentIndex = &index2TC;
1024  break;
1026  disableTextures(3);
1027  disableTextures(1);
1028  bindTexture(2, ro.overlay_id);
1029  setEnvironmentalColor(2, ro.rgba);
1030  enableTextures(0);
1031 
1032  // set pointer
1033  setVertexPointer(2, stride2TC, &m_renderMultitextureDatas[0].vertex);
1034  setColorPointer(stride2TC, &m_renderMultitextureDatas[0].color);
1035  setTexCoordPointer(2, stride2TC, &m_renderMultitextureDatas[0].texel2);
1036  setTexCoordPointer(0, stride2TC, &m_renderMultitextureDatas[0].texel);
1037  indexBuffer = &m_tc2Indices[0];
1038 
1039  texture_id2 = ro.overlay_id;
1040  currentElements = &elements2TC;
1041  currentIndex = &index2TC;
1042  break;
1044  disableTextures(2);
1045  disableTextures(1);
1046  bindTexture(3, ro.overlay_id);
1047  setEnvironmentalColor(3, ro.rgba);
1048  enableTextures(0);
1049 
1050  // set pointer
1051  setVertexPointer(2, stride2TC, &m_renderMultitextureDatas[0].vertex);
1052  setColorPointer(stride2TC, &m_renderMultitextureDatas[0].color);
1053  setTexCoordPointer(3, stride2TC, &m_renderMultitextureDatas[0].texel2);
1054  setTexCoordPointer(0, stride2TC, &m_renderMultitextureDatas[0].texel);
1055  indexBuffer = &m_tc2Indices[0];
1056 
1057  texture_id2 = ro.overlay_id;
1058  currentElements = &elements2TC;
1059  currentIndex = &index2TC;
1060  break;
1061  }
1062  memcpy(rgba, ro.rgba, sizeof(uint8_t) * 4);
1063  overlay_type = ro.overlay_type;
1064  mt = false;
1065  }
1066  // switch texturing
1067  if (texture) {
1068  if (ro.texture_id != 0) {
1069  bindTexture(0, ro.texture_id);
1070  texture_id = ro.texture_id;
1071  if (ro.overlay_type == OVERLAY_TYPE_NONE) {
1072  if (m_state.color_enabled) {
1073  setVertexPointer(2, strideTC, &m_renderTextureColorDatas[0].vertex);
1074  setTexCoordPointer(0, strideTC, &m_renderTextureColorDatas[0].texel);
1075  setColorPointer(strideTC, &m_renderTextureColorDatas[0].color);
1076  indexBuffer = &m_tcIndices[0];
1077  currentElements = &elementsTC;
1078  currentIndex = &indexTC;
1079  } else {
1080  setVertexPointer(2, strideT, &m_renderTextureDatas[0].vertex);
1081  setTexCoordPointer(0, strideT, &m_renderTextureDatas[0].texel);
1082  indexBuffer = &m_tIndices[0];
1083  currentElements = &elementsT;
1084  currentIndex = &indexT;
1085  }
1086  }
1087  } else {
1088  disableTextures(0);
1089  texture_id = 0;
1090  if (ro.overlay_type == OVERLAY_TYPE_NONE) {
1091  setVertexPointer(2, strideP, &m_renderPrimitiveDatas[0].vertex);
1092  setColorPointer(strideP, &m_renderPrimitiveDatas[0].color);
1093  indexBuffer = &m_pIndices[0];
1094  currentElements = &elementsP;
1095  currentIndex = &indexP;
1096  }
1097  }
1098  texture = false;
1099  }
1100 
1101  // set element to current size
1102  *currentElements = ro.size;
1103 
1104  // if lighting is enabled we have to consider a few more values
1105  if (m_state.lightmodel) {
1106  // change blending
1107  if (blending) {
1108  src = ro.src;
1109  dst = ro.dst;
1110  changeBlending(ro.src, ro.dst);
1111  blending = false;
1112  }
1113  // change light
1114  if (light) {
1115  if (ro.light && !m_state.light_enabled) {
1116  enableLighting();
1117  } else if (!ro.light && m_state.light_enabled) {
1118  disableLighting();
1119  }
1120  light = false;
1121  }
1122  // change stencil
1123  if (stencil) {
1124  if (ro.stencil_test) {
1126  setAlphaTest(0.0);
1127  } else {
1128  disableAlphaTest();
1130  }
1131  stencil = false;
1132  }
1133  }
1134 
1135  render = false;
1136  } else {
1137  // else add the element
1138  *currentElements += ro.size;
1139  }
1140  }
1141  // render
1142  glDrawElements(mode, *currentElements, GL_UNSIGNED_INT, indexBuffer + *currentIndex);
1143 
1144  // reset all states
1145  if (overlay_type != OVERLAY_TYPE_NONE) {
1146  disableTextures(3);
1147  disableTextures(2);
1148  disableTextures(1);
1149  }
1150  disableTextures(0);
1151  enableColorArray();
1152 
1153  if (m_state.lightmodel != 0) {
1154  changeBlending(4, 5);
1155  disableLighting();
1157  disableAlphaTest();
1158  }
1159 
1160  m_renderPrimitiveDatas.clear();
1161  m_renderTextureDatas.clear();
1162  m_renderTextureColorDatas.clear();
1163  m_renderMultitextureDatas.clear();
1164  m_renderObjects.clear();
1165 
1166  m_pIndices.clear();
1167  m_tIndices.clear();
1168  m_tcIndices.clear();
1169  m_tc2Indices.clear();
1170  }
1171 
1173  // stride
1174  const uint32_t stride = sizeof(renderDataZ);
1175 
1176  // set pointer
1177  setVertexPointer(3, stride, &m_renderTextureDatasZ[0].vertex);
1178  setTexCoordPointer(0, stride, &m_renderTextureDatasZ[0].texel);
1179 
1180  // array index
1181  int32_t index = 0;
1182  // elements to render
1183  uint32_t elements = 0;
1184  // texture id
1185  uint32_t texture_id = 0;
1186 
1187  int32_t* currentIndex = &index;
1188  uint32_t* currentElements = &elements;
1189 
1190  enableAlphaTest();
1191  enableDepthTest();
1192  enableTextures(0);
1193  enableLighting();
1195 
1196  for(std::vector<RenderZObject>::iterator ir = m_renderTextureObjectsZ.begin(); ir != m_renderTextureObjectsZ.end(); ++ir) {
1197  RenderZObject& ro = (*ir);
1198  // if changes then we render all previously elements
1199  if (ro.texture_id != texture_id) {
1200  if (*currentElements > 0) {
1201  //render
1202  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1203  *currentIndex += *currentElements;
1204  }
1205 
1206  if (ro.texture_id != 0) {
1207  bindTexture(0, ro.texture_id);
1208  texture_id = ro.texture_id;
1209  } else {
1210  disableTextures(0);
1211  texture_id = 0;
1212  }
1213 
1214  // set element to current size
1215  *currentElements = 6;
1216  } else {
1217  // else add the element
1218  *currentElements += 6;
1219  }
1220  }
1221 
1222  // render
1223  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1224 
1225  //reset all states
1226  disableLighting();
1227  disableTextures(0);
1228  disableAlphaTest();
1229  disableDepthTest();
1230  enableColorArray();
1231 
1232  m_renderTextureDatasZ.clear();
1233  m_renderTextureObjectsZ.clear();
1234  }
1235 
1237  // stride
1238  const uint32_t stride = sizeof(renderDataZ);
1239 
1240  // set pointer
1241  setVertexPointer(3, stride, &m_renderZ_datas[0].vertex);
1242  setTexCoordPointer(0, stride, &m_renderZ_datas[0].texel);
1243 
1244  enableAlphaTest();
1245  enableDepthTest();
1246  enableTextures(0);
1247  enableLighting();
1249 
1250  std::vector<RenderZObjectTest>::iterator iter = m_renderZ_objects.begin();
1251  for ( ; iter != m_renderZ_objects.end(); ++iter) {
1252  bindTexture(iter->texture_id);
1253  glDrawArrays(GL_QUADS, iter->index, iter->elements);
1254  }
1255  m_renderZ_objects.clear();
1256 
1257  //reset all states
1258  disableLighting();
1259  disableTextures(0);
1260  disableAlphaTest();
1261  disableDepthTest();
1262  enableColorArray();
1263  }
1264 
1266  // stride
1267  const uint32_t stride = sizeof(renderDataColorZ);
1268 
1269  // set pointer
1270  setVertexPointer(3, stride, &m_renderTextureColorDatasZ[0].vertex);
1271  setTexCoordPointer(0, stride, &m_renderTextureColorDatasZ[0].texel);
1272  setColorPointer(stride, &m_renderTextureColorDatasZ[0].color);
1273 
1274  // array index
1275  int32_t index = 0;
1276  // elements to render
1277  uint32_t elements = 0;
1278  // texture id
1279  uint32_t texture_id = 0;
1280 
1281  int32_t* currentIndex = &index;
1282  uint32_t* currentElements = &elements;
1283 
1284  enableDepthTest();
1285  // use own value, other option would be to disable it
1286  setAlphaTest(0.008);
1287  enableTextures(0);
1288  enableLighting();
1289 
1290  for(std::vector<RenderZObject>::iterator ir = m_renderTextureColorObjectsZ.begin(); ir != m_renderTextureColorObjectsZ.end(); ++ir) {
1291  RenderZObject& ro = (*ir);
1292  // if changes then we render all previously elements
1293  if (ro.texture_id != texture_id) {
1294  if (*currentElements > 0) {
1295  //render
1296  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1297  *currentIndex += *currentElements;
1298  }
1299 
1300  if (ro.texture_id != 0) {
1301  bindTexture(0, ro.texture_id);
1302  texture_id = ro.texture_id;
1303  } else {
1304  disableTextures(0);
1305  texture_id = 0;
1306  }
1307 
1308  // set element to current size
1309  *currentElements = 6;
1310  } else {
1311  // else add the element
1312  *currentElements += 6;
1313  }
1314  }
1315 
1316  // render
1317  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1318 
1319  //reset all states
1320  disableLighting();
1321  disableTextures(0);
1323  disableAlphaTest();
1324  disableDepthTest();
1325 
1328  }
1329 
1331  //bools to indicate changes
1332  bool texture = false;
1333  bool render = false;
1334  bool mt = false;
1335 
1336  // stride
1337  const uint32_t stride = sizeof(renderData2TCZ);
1338 
1339  // set pointer
1340  setVertexPointer(3, stride, &m_renderMultitextureDatasZ[0].vertex);
1341  setTexCoordPointer(0, stride, &m_renderMultitextureDatasZ[0].texel);
1342  setTexCoordPointer(1, stride, &m_renderMultitextureDatasZ[0].texel2);
1343  setTexCoordPointer(2, stride, &m_renderMultitextureDatasZ[0].texel2);
1344  setTexCoordPointer(3, stride, &m_renderMultitextureDatasZ[0].texel2);
1345  setColorPointer(stride, &m_renderMultitextureDatasZ[0].color);
1346 
1347  // array index
1348  int32_t index = 0;
1349  // elements to render
1350  uint32_t elements = 0;
1351  // texture id
1352  uint32_t texture_id = 0;
1353  uint32_t texture_id2 = 0;
1354  // overlay type
1355  OverlayType overlay_type = OVERLAY_TYPE_NONE;
1356  // overlay color
1357  uint8_t color[4] = {0};
1358 
1359  int32_t* currentIndex = &index;
1360  uint32_t* currentElements = &elements;
1361 
1362  enableDepthTest();
1363  enableAlphaTest();
1364  enableTextures(0);
1365  enableLighting();
1366 
1367  for(std::vector<RenderObject>::iterator ir = m_renderMultitextureObjectsZ.begin(); ir != m_renderMultitextureObjectsZ.end(); ++ir) {
1368  RenderObject& ro = (*ir);
1369 
1370  // first we look for changes
1371  if (ro.texture_id != texture_id) {
1372  texture = true;
1373  render = true;
1374  }
1375  if (ro.overlay_type != overlay_type ||
1376  (ro.overlay_type != OVERLAY_TYPE_NONE && (memcmp(color, ro.rgba, sizeof(uint8_t) * 4) || ro.overlay_id != texture_id2))) {
1377  mt = true;
1378  render = true;
1379  }
1380 
1381  // if changes then we render all previously elements
1382  if (render) {
1383  if (*currentElements > 0) {
1384  //render
1385  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1386  *currentIndex += *currentElements;
1387  }
1388  // multitexturing
1389  if(mt) {
1390  switch (ro.overlay_type) {
1391  case OVERLAY_TYPE_NONE:
1392  disableTextures(3);
1393  disableTextures(2);
1394  disableTextures(1);
1395  enableTextures(0);
1396 
1397  texture_id2 = 0;
1398  break;
1399  case OVERLAY_TYPE_COLOR:
1400  disableTextures(3);
1401  disableTextures(2);
1403  setEnvironmentalColor(1, ro.rgba);
1404  enableTextures(0);
1405 
1406  texture_id2 = m_maskOverlay;
1407  break;
1409  disableTextures(3);
1410  disableTextures(1);
1411  bindTexture(2, ro.overlay_id);
1412  setEnvironmentalColor(2, ro.rgba);
1413  enableTextures(0);
1414 
1415  texture_id2 = ro.overlay_id;
1416  break;
1418  disableTextures(2);
1419  disableTextures(1);
1420  bindTexture(3, ro.overlay_id);
1421  setEnvironmentalColor(3, ro.rgba);
1422  enableTextures(0);
1423 
1424  texture_id2 = ro.overlay_id;
1425  break;
1426  }
1427  memcpy(color, ro.rgba, sizeof(uint8_t) * 4);
1428  overlay_type = ro.overlay_type;
1429  mt = false;
1430  }
1431 
1432  // switch texturing
1433  if (texture) {
1434  if (ro.texture_id != 0) {
1435  bindTexture(0, ro.texture_id);
1436  texture_id = ro.texture_id;
1437  } else {
1438  disableTextures(0);
1439  texture_id = 0;
1440  }
1441  texture = false;
1442  }
1443 
1444  // set element to current size
1445  *currentElements = ro.size;
1446  render = false;
1447  } else {
1448  // else add the element
1449  *currentElements += ro.size;
1450  }
1451  }
1452  // render
1453  glDrawElements(GL_TRIANGLES, *currentElements, GL_UNSIGNED_INT, &m_indices[*currentIndex]);
1454 
1455  //reset all states
1456  if (overlay_type != OVERLAY_TYPE_NONE) {
1457  disableTextures(3);
1458  disableTextures(2);
1459  disableTextures(1);
1460  }
1461  disableTextures(0);
1462  disableLighting();
1463  disableAlphaTest();
1464  disableDepthTest();
1465 
1468  }
1469 
1471  // z stuff
1472  if (!m_renderZ_objects.empty()) {
1473  renderWithZTest();
1474  }
1475  if (!m_renderTextureObjectsZ.empty()) {
1476  renderWithZ();
1477  }
1478  if (!m_renderMultitextureObjectsZ.empty()) {
1480  }
1481  if (!m_renderTextureColorObjectsZ.empty()) {
1483  }
1484 
1485  // objects without z
1486  if (!m_renderObjects.empty()) {
1487  renderWithoutZ();
1488  }
1489  }
1490 
1491  bool RenderBackendOpenGL::putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1492  if ((x < 0) || (x >= (int32_t)m_target->w) ||
1493  (y < 0) || (y >= (int32_t)m_target->h)) {
1494  return false;
1495  }
1496  renderDataP rd;
1497  rd.vertex[0] = static_cast<float>(x)+0.375;
1498  rd.vertex[1] = static_cast<float>(y)+0.375;
1499  rd.color[0] = r;
1500  rd.color[1] = g;
1501  rd.color[2] = b;
1502  rd.color[3] = a;
1503  m_renderPrimitiveDatas.push_back(rd);
1504 
1505  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1506 
1507  RenderObject ro(GL_POINTS, 1);
1508  m_renderObjects.push_back(ro);
1509 
1510  return true;
1511  }
1512 
1513  void RenderBackendOpenGL::drawLine(const Point& p1, const Point& p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1514  renderDataP rd;
1515  rd.vertex[0] = static_cast<float>(p1.x)+0.375;
1516  rd.vertex[1] = static_cast<float>(p1.y)+0.375;
1517  rd.color[0] = r;
1518  rd.color[1] = g;
1519  rd.color[2] = b;
1520  rd.color[3] = a;
1521  m_renderPrimitiveDatas.push_back(rd);
1522 
1523  rd.vertex[0] = static_cast<float>(p2.x)+0.375;
1524  rd.vertex[1] = static_cast<float>(p2.y)+0.375;
1525  m_renderPrimitiveDatas.push_back(rd);
1526 
1527  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1528  m_pIndices.push_back(m_pIndices.back() + 1);
1529 
1530  RenderObject ro(GL_LINES, 2);
1531  m_renderObjects.push_back(ro);
1532  }
1533 
1534  void RenderBackendOpenGL::drawThickLine(const Point& p1, const Point& p2, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1535  float xDiff = p2.x - p1.x;
1536  float yDiff = p2.y - p1.y;
1537  float halfW = static_cast<float>(width) / 2.0;
1538  float angle = Mathf::ATan2(yDiff, xDiff) * (180.0 / Mathf::pi()) + 90.0;
1539  if (angle < 0.0) {
1540  angle += 360.0;
1541  } else if (angle > 360.0) {
1542  angle -= 360.0;
1543  }
1544  angle *= Mathf::pi() / 180.0;
1545  float cornerX = halfW * Mathf::Cos(angle);
1546  float cornerY = halfW * Mathf::Sin(angle);
1547 
1548  renderDataP rd;
1549  rd.vertex[0] = static_cast<float>(p1.x) + cornerX;
1550  rd.vertex[1] = static_cast<float>(p1.y) + cornerY;
1551  rd.color[0] = r;
1552  rd.color[1] = g;
1553  rd.color[2] = b;
1554  rd.color[3] = a;
1555  m_renderPrimitiveDatas.push_back(rd);
1556  rd.vertex[0] = static_cast<float>(p2.x) + cornerX;
1557  rd.vertex[1] = static_cast<float>(p2.y) + cornerY;
1558  m_renderPrimitiveDatas.push_back(rd);
1559  rd.vertex[0] = static_cast<float>(p2.x) - cornerX;
1560  rd.vertex[1] = static_cast<float>(p2.y) - cornerY;
1561  m_renderPrimitiveDatas.push_back(rd);
1562  rd.vertex[0] = static_cast<float>(p1.x) - cornerX;
1563  rd.vertex[1] = static_cast<float>(p1.y) - cornerY;
1564  m_renderPrimitiveDatas.push_back(rd);
1565 
1566  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1567  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
1568  m_pIndices.insert(m_pIndices.end(), indices, indices + 6);
1569 
1570  RenderObject ro(GL_TRIANGLES, 6);
1571  m_renderObjects.push_back(ro);
1572  }
1573 
1574  void RenderBackendOpenGL::drawPolyLine(const std::vector<Point>& points, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1575  if (points.size() < 2) {
1576  return;
1577  }
1578  std::vector<Point>::const_iterator it = points.begin();
1579  if (width > 1) {
1580  Point old = *it;
1581  ++it;
1582  for (; it != points.end(); ++it) {
1583  drawThickLine(old, *it, width, r, g, b, a);
1584  drawFillCircle(old, width / 2, r, g, b, a);
1585  old = *it;
1586  }
1587  drawFillCircle(old, width / 2, r, g, b, a);
1588  } else {
1589  renderDataP rd;
1590  rd.color[0] = r;
1591  rd.color[1] = g;
1592  rd.color[2] = b;
1593  rd.color[3] = a;
1594  for (; it != points.end(); ++it) {
1595  rd.vertex[0] = static_cast<float>((*it).x);
1596  rd.vertex[1] = static_cast<float>((*it).y);
1597  m_renderPrimitiveDatas.push_back(rd);
1598  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1599  }
1600  RenderObject ro(GL_LINE_STRIP, points.size());
1601  m_renderObjects.push_back(ro);
1602  }
1603  }
1604 
1605  void RenderBackendOpenGL::drawBezier(const std::vector<Point>& points, int32_t steps, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1606  if (points.size() < 2) {
1607  return;
1608  }
1609  int32_t elements = points.size();
1610  if (elements < 3 || steps < 2) {
1611  return;
1612  }
1613 
1614  bool thick = width > 1;
1615  float step = 1.0 / static_cast<float>(steps-1);
1616  float t = 0.0;
1617  Point old = getBezierPoint(points, elements+1, t);
1618  if (thick) {
1619  for (int32_t i = 0; i <= (elements*steps); ++i) {
1620  t += step;
1621  Point next = getBezierPoint(points, elements, t);
1622  drawThickLine(old, next, width, r, g, b, a);
1623  drawFillCircle(old, width / 2, r, g, b, a);
1624  old = next;
1625  }
1626  drawFillCircle(old, width / 2, r, g, b, a);
1627  } else {
1628  renderDataP rd;
1629  rd.color[0] = r;
1630  rd.color[1] = g;
1631  rd.color[2] = b;
1632  rd.color[3] = a;
1633  for (int32_t i = 0; i <= (elements*steps); ++i) {
1634  t += step;
1635  Point next = getBezierPoint(points, elements, t);
1636  rd.vertex[0] = static_cast<float>(old.x);
1637  rd.vertex[1] = static_cast<float>(old.y);
1638  m_renderPrimitiveDatas.push_back(rd);
1639  old = next;
1640  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1641  }
1642  RenderObject ro(GL_LINE_STRIP, (elements*steps)+1);
1643  m_renderObjects.push_back(ro);
1644  }
1645  }
1646 
1647  void RenderBackendOpenGL::drawTriangle(const Point& p1, const Point& p2, const Point& p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1648  renderDataP rd;
1649  rd.vertex[0] = static_cast<float>(p1.x);
1650  rd.vertex[1] = static_cast<float>(p1.y);
1651  rd.color[0] = r;
1652  rd.color[1] = g;
1653  rd.color[2] = b;
1654  rd.color[3] = a;
1655  m_renderPrimitiveDatas.push_back(rd);
1656 
1657  rd.vertex[0] = static_cast<float>(p2.x);
1658  rd.vertex[1] = static_cast<float>(p2.y);
1659  m_renderPrimitiveDatas.push_back(rd);
1660 
1661  rd.vertex[0] = static_cast<float>(p3.x);
1662  rd.vertex[1] = static_cast<float>(p3.y);
1663  m_renderPrimitiveDatas.push_back(rd);
1664 
1665  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1666  uint32_t indices[] = { index, index + 1, index + 2 };
1667  m_pIndices.insert(m_pIndices.end(), indices, indices + 3);
1668 
1669  RenderObject ro(GL_TRIANGLES, 3);
1670  m_renderObjects.push_back(ro);
1671  }
1672 
1674  renderDataP rd;
1675  rd.vertex[0] = static_cast<float>(p.x);
1676  rd.vertex[1] = static_cast<float>(p.y);
1677  rd.color[0] = r;
1678  rd.color[1] = g;
1679  rd.color[2] = b;
1680  rd.color[3] = a;
1681  m_renderPrimitiveDatas.push_back(rd);
1682 
1683  rd.vertex[0] = static_cast<float>(p.x+w);
1684  m_renderPrimitiveDatas.push_back(rd);
1685 
1686  rd.vertex[1] = static_cast<float>(p.y+h);
1687  m_renderPrimitiveDatas.push_back(rd);
1688 
1689  rd.vertex[0] = static_cast<float>(p.x);
1690  m_renderPrimitiveDatas.push_back(rd);
1691 
1692  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1693  uint32_t indices[] = { index, index + 1, index + 2, index + 3 };
1694  m_pIndices.insert(m_pIndices.end(), indices, indices + 4);
1695 
1696  RenderObject ro(GL_LINE_LOOP, 4);
1697  m_renderObjects.push_back(ro);
1698  }
1699 
1701  renderDataP rd;
1702  rd.vertex[0] = static_cast<float>(p.x);
1703  rd.vertex[1] = static_cast<float>(p.y);
1704  rd.color[0] = r;
1705  rd.color[1] = g;
1706  rd.color[2] = b;
1707  rd.color[3] = a;
1708  m_renderPrimitiveDatas.push_back(rd);
1709 
1710  rd.vertex[1] = static_cast<float>(p.y+h);
1711  m_renderPrimitiveDatas.push_back(rd);
1712 
1713  rd.vertex[0] = static_cast<float>(p.x+w);
1714  m_renderPrimitiveDatas.push_back(rd);
1715 
1716  rd.vertex[1] = static_cast<float>(p.y);
1717  m_renderPrimitiveDatas.push_back(rd);
1718 
1719  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1720  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
1721  m_pIndices.insert(m_pIndices.end(), indices, indices + 6);
1722 
1723  RenderObject ro(GL_TRIANGLES, 6);
1724  m_renderObjects.push_back(ro);
1725  }
1726 
1727  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) {
1728  renderDataP rd;
1729  rd.vertex[0] = static_cast<float>(p1.x);
1730  rd.vertex[1] = static_cast<float>(p1.y);
1731  rd.color[0] = r;
1732  rd.color[1] = g;
1733  rd.color[2] = b;
1734  rd.color[3] = a;
1735  m_renderPrimitiveDatas.push_back(rd);
1736 
1737  rd.vertex[0] = static_cast<float>(p2.x);
1738  rd.vertex[1] = static_cast<float>(p2.y);
1739  m_renderPrimitiveDatas.push_back(rd);
1740 
1741  rd.vertex[0] = static_cast<float>(p3.x);
1742  rd.vertex[1] = static_cast<float>(p3.y);
1743  m_renderPrimitiveDatas.push_back(rd);
1744 
1745  rd.vertex[0] = static_cast<float>(p4.x);
1746  rd.vertex[1] = static_cast<float>(p4.y);
1747  m_renderPrimitiveDatas.push_back(rd);
1748 
1749  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1750  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
1751  m_pIndices.insert(m_pIndices.end(), indices, indices + 6);
1752 
1753  RenderObject ro(GL_TRIANGLES, 6);
1754  m_renderObjects.push_back(ro);
1755  }
1756 
1758  renderDataP rd;
1759  rd.vertex[0] = static_cast<float>(p.x-size);
1760  rd.vertex[1] = static_cast<float>(p.y+size);
1761  rd.color[0] = r;
1762  rd.color[1] = g;
1763  rd.color[2] = b;
1764  rd.color[3] = a;
1765  m_renderPrimitiveDatas.push_back(rd);
1766 
1767  rd.vertex[0] = static_cast<float>(p.x+size);
1768  m_renderPrimitiveDatas.push_back(rd);
1769 
1770  rd.vertex[1] = static_cast<float>(p.y-size);
1771  m_renderPrimitiveDatas.push_back(rd);
1772 
1773  rd.vertex[0] = static_cast<float>(p.x-size);
1774  m_renderPrimitiveDatas.push_back(rd);
1775 
1776  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1777  uint32_t indices[] = { index, index + 1, index + 2, index + 3 };
1778  m_pIndices.insert(m_pIndices.end(), indices, indices + 4);
1779 
1780  RenderObject ro(GL_LINE_LOOP, 4);
1781  m_renderObjects.push_back(ro);
1782  }
1783 
1785  // set side length to 5 and calculate needed divisions
1786  int32_t subdivisions = round(Mathf::pi() / ( 5.0 / (2.0 * radius)));
1787  if (subdivisions < 12) {
1788  subdivisions = 12;
1789  }
1790  const float step = Mathf::twoPi()/subdivisions;
1791  float angle = 0;
1792 
1793  renderDataP rd;
1794  rd.color[0] = r;
1795  rd.color[1] = g;
1796  rd.color[2] = b;
1797  rd.color[3] = a;
1798  for (uint16_t i = 0; i < subdivisions-1; ++i) {
1799  rd.vertex[0] = radius * Mathf::Cos(angle) + p.x;
1800  rd.vertex[1] = radius * Mathf::Sin(angle) + p.y;
1801  m_renderPrimitiveDatas.push_back(rd);
1802  angle += step;
1803  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1804  }
1805 
1806  RenderObject ro(GL_LINE_LOOP, subdivisions-1);
1807  m_renderObjects.push_back(ro);
1808  }
1809 
1811  // set side length to 5 and calculate needed divisions
1812  int32_t subdivisions = round(Mathf::pi() / ( 5.0 / (2.0 * radius)));
1813  if (subdivisions < 12) {
1814  subdivisions = 12;
1815  }
1816  const float step = Mathf::twoPi()/subdivisions;
1817  float angle = Mathf::twoPi();
1818  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1819  uint32_t lastIndex = index;
1820 
1821  // center vertex
1822  renderDataP rd;
1823  rd.vertex[0] = static_cast<float>(p.x);
1824  rd.vertex[1] = static_cast<float>(p.y);
1825  rd.color[0] = r;
1826  rd.color[1] = g;
1827  rd.color[2] = b;
1828  rd.color[3] = a;
1829  m_renderPrimitiveDatas.push_back(rd);
1830  // reversed because of culling faces
1831  for (uint16_t i = 0; i <= subdivisions; ++i) {
1832  rd.vertex[0] = radius * Mathf::Cos(angle) + p.x;
1833  rd.vertex[1] = radius * Mathf::Sin(angle) + p.y;
1834  m_renderPrimitiveDatas.push_back(rd);
1835  angle -= step;
1836  // forms triangle with start index, the last and a new one
1837  uint32_t indices[] = { index, lastIndex, ++lastIndex };
1838  m_pIndices.insert(m_pIndices.end(), indices, indices + 3);
1839  }
1840  RenderObject ro(GL_TRIANGLES, (subdivisions+1) * 3);
1841  m_renderObjects.push_back(ro);
1842  }
1843 
1844  void RenderBackendOpenGL::drawCircleSegment(const Point& p, uint32_t radius, int32_t sangle, int32_t eangle, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1845  const float step = Mathf::twoPi()/360;
1846  int32_t elements = 0;
1847  int32_t s = (sangle + 360) % 360;
1848  int32_t e = (eangle + 360) % 360;
1849  if (e == 0) {
1850  e = 360;
1851  }
1852  if (s == e) {
1853  return;
1854  }
1855 
1856  renderDataP rd;
1857  rd.color[0] = r;
1858  rd.color[1] = g;
1859  rd.color[2] = b;
1860  rd.color[3] = a;
1861  float angle = static_cast<float>(s) * step;
1862  for (;s <= e; ++s, angle += step, ++elements) {
1863  rd.vertex[0] = radius * Mathf::Cos(angle) + p.x;
1864  rd.vertex[1] = radius * Mathf::Sin(angle) + p.y;
1865  m_renderPrimitiveDatas.push_back(rd);
1866  m_pIndices.push_back(m_pIndices.empty() ? 0 : m_pIndices.back() + 1);
1867  }
1868 
1869  RenderObject ro(GL_LINE_STRIP, elements);
1870  m_renderObjects.push_back(ro);
1871  }
1872 
1873  void RenderBackendOpenGL::drawFillCircleSegment(const Point& p, uint32_t radius, int32_t sangle, int32_t eangle, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
1874  const float step = Mathf::twoPi() / 360;
1875  int32_t s = (sangle + 360) % 360;
1876  int32_t e = (eangle + 360) % 360;
1877  if (e == 0) {
1878  e = 360;
1879  }
1880  if (s == e) {
1881  return;
1882  }
1883 
1884  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1885  uint32_t lastIndex = index;
1886  // center vertex
1887  renderDataP rd;
1888  rd.vertex[0] = static_cast<float>(p.x);
1889  rd.vertex[1] = static_cast<float>(p.y);
1890  rd.color[0] = r;
1891  rd.color[1] = g;
1892  rd.color[2] = b;
1893  rd.color[3] = a;
1894  m_renderPrimitiveDatas.push_back(rd);
1895  int32_t elements = 0;
1896  // reversed because of culling faces
1897  float angle = static_cast<float>(e) * step;
1898  for (;s <= e; ++s, angle -= step, ++elements) {
1899  rd.vertex[0] = radius * Mathf::Cos(angle) + p.x;
1900  rd.vertex[1] = radius * Mathf::Sin(angle) + p.y;
1901 
1902  m_renderPrimitiveDatas.push_back(rd);
1903  // forms triangle with start index, the last and a new one
1904  uint32_t indices[] = { index, lastIndex, ++lastIndex };
1905  m_pIndices.insert(m_pIndices.end(), indices, indices + 3);
1906  }
1907 
1908  RenderObject ro(GL_TRIANGLES, elements * 3);
1909  m_renderObjects.push_back(ro);
1910  }
1911 
1912  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) {
1913  const float step = Mathf::twoPi()/subdivisions;
1914  uint32_t elements = 0;
1915  uint32_t index = m_pIndices.empty() ? 0 : m_pIndices.back() + 1;
1916  uint32_t lastIndex = index;
1917  // center vertex
1918  renderDataP rd;
1919  rd.vertex[0] = static_cast<float>(p.x);
1920  rd.vertex[1] = static_cast<float>(p.y);
1921  rd.color[0] = red;
1922  rd.color[1] = green;
1923  rd.color[2] = blue;
1924  rd.color[3] = intensity;
1925  m_renderPrimitiveDatas.push_back(rd);
1926  for (float angle = 0; angle <= Mathf::twoPi(); angle += step, elements += 3) {
1927  rd.vertex[0] = radius*Mathf::Cos(angle+step)*xstretch + p.x;
1928  rd.vertex[1] = radius*Mathf::Sin(angle+step)*ystretch + p.y;
1929  rd.color[0] = 0;
1930  rd.color[1] = 0;
1931  rd.color[2] = 0;
1932  rd.color[3] = 255;
1933  m_renderPrimitiveDatas.push_back(rd);
1934 
1935  rd.vertex[0] = radius*Mathf::Cos(angle)*xstretch + p.x;
1936  rd.vertex[1] = radius*Mathf::Sin(angle)*ystretch + p.y;
1937  m_renderPrimitiveDatas.push_back(rd);
1938  // forms triangle with start index and two new ones
1939  uint32_t indices[] = { index, ++lastIndex, ++lastIndex };
1940  m_pIndices.insert(m_pIndices.end(), indices, indices + 3);
1941  }
1942  RenderObject ro(GL_TRIANGLES, elements);
1943  m_renderObjects.push_back(ro);
1944  }
1945 
1946  void RenderBackendOpenGL::addImageToArray(uint32_t id, const Rect& rect, float const* st, uint8_t alpha, uint8_t const* rgba) {
1947  RenderObject ro(GL_TRIANGLES, 6, id);
1948 
1949  // texture quad without alpha
1950  if (alpha == 255 && !rgba) {
1951  renderDataT rd;
1952  rd.vertex[0] = static_cast<float>(rect.x);
1953  rd.vertex[1] = static_cast<float>(rect.y);
1954  rd.texel[0] = st[0];
1955  rd.texel[1] = st[1];
1956  m_renderTextureDatas.push_back(rd);
1957 
1958  rd.vertex[0] = static_cast<float>(rect.x);
1959  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1960  rd.texel[1] = st[3];
1961  m_renderTextureDatas.push_back(rd);
1962 
1963  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1964  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1965  rd.texel[0] = st[2];
1966  m_renderTextureDatas.push_back(rd);
1967 
1968  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
1969  rd.vertex[1] = static_cast<float>(rect.y);
1970  rd.texel[1] = st[1];
1971  m_renderTextureDatas.push_back(rd);
1972 
1973  ro.color = false;
1974 
1975  uint32_t index = m_tIndices.empty() ? 0 : m_tIndices.back() + 1;
1976  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
1977  m_tIndices.insert(m_tIndices.end(), indices, indices + 6);
1978  } else {
1979  if (rgba) {
1980  renderData2TC rd;
1981  rd.vertex[0] = static_cast<float>(rect.x);
1982  rd.vertex[1] = static_cast<float>(rect.y);
1983  rd.texel[0] = st[0];
1984  rd.texel[1] = st[1];
1985  rd.texel2[0] = 0.0;
1986  rd.texel2[1] = 0.0;
1987  rd.color[0] = 255;
1988  rd.color[1] = 255;
1989  rd.color[2] = 255;
1990  rd.color[3] = alpha;
1991  m_renderMultitextureDatas.push_back(rd);
1992 
1993  rd.vertex[0] = static_cast<float>(rect.x);
1994  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
1995  rd.texel[1] = st[3];
1996  rd.texel2[1] = 1.0;
1997  m_renderMultitextureDatas.push_back(rd);
1998 
1999  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2000  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2001  rd.texel[0] = st[2];
2002  rd.texel2[0] = 1.0;
2003  m_renderMultitextureDatas.push_back(rd);
2004 
2005  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2006  rd.vertex[1] = static_cast<float>(rect.y);
2007  rd.texel[1] = st[1];
2008  rd.texel2[1] = 0.0;
2009  m_renderMultitextureDatas.push_back(rd);
2010 
2011  ro.color = true;
2013  ro.rgba[0] = rgba[0];
2014  ro.rgba[1] = rgba[1];
2015  ro.rgba[2] = rgba[2];
2016  ro.rgba[3] = rgba[3];
2017 
2018  uint32_t index = m_tc2Indices.empty() ? 0 : m_tc2Indices.back() + 1;
2019  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
2020  m_tc2Indices.insert(m_tc2Indices.end(), indices, indices + 6);
2021  // texture quad with alpha
2022  } else {
2023  renderDataTC rd;
2024  rd.vertex[0] = static_cast<float>(rect.x);
2025  rd.vertex[1] = static_cast<float>(rect.y);
2026  rd.texel[0] = st[0];
2027  rd.texel[1] = st[1];
2028  rd.color[0] = 255;
2029  rd.color[1] = 255;
2030  rd.color[2] = 255;
2031  rd.color[3] = alpha;
2032  m_renderTextureColorDatas.push_back(rd);
2033 
2034  rd.vertex[0] = static_cast<float>(rect.x);
2035  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2036  rd.texel[1] = st[3];
2037  m_renderTextureColorDatas.push_back(rd);
2038 
2039  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2040  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2041  rd.texel[0] = st[2];
2042  m_renderTextureColorDatas.push_back(rd);
2043 
2044  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2045  rd.vertex[1] = static_cast<float>(rect.y);
2046  rd.texel[1] = st[1];
2047  m_renderTextureColorDatas.push_back(rd);
2048 
2049  ro.color = true;
2050 
2051  uint32_t index = m_tcIndices.empty() ? 0 : m_tcIndices.back() + 1;
2052  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
2053  m_tcIndices.insert(m_tcIndices.end(), indices, indices + 6);
2054  }
2055  }
2056  m_renderObjects.push_back(ro);
2057  }
2058 
2059  void RenderBackendOpenGL::addImageToArray(const Rect& rect, uint32_t id1, float const* st1, uint32_t id2, float const* st2, uint8_t alpha, uint8_t const* rgba) {
2060  if (rgba) {
2061  renderData2TC rd;
2062  rd.vertex[0] = static_cast<float>(rect.x);
2063  rd.vertex[1] = static_cast<float>(rect.y);
2064  rd.texel[0] = st1[0];
2065  rd.texel[1] = st1[1];
2066  rd.texel2[0] = st2[0];
2067  rd.texel2[1] = st2[1];
2068  rd.color[0] = 255;
2069  rd.color[1] = 255;
2070  rd.color[2] = 255;
2071  rd.color[3] = alpha;
2072  m_renderMultitextureDatas.push_back(rd);
2073 
2074  rd.vertex[0] = static_cast<float>(rect.x);
2075  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2076  rd.texel[1] = st1[3];
2077  rd.texel2[1] = st2[3];
2078  m_renderMultitextureDatas.push_back(rd);
2079 
2080  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2081  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2082  rd.texel[0] = st1[2];
2083  rd.texel2[0] = st2[2];
2084  m_renderMultitextureDatas.push_back(rd);
2085 
2086  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2087  rd.vertex[1] = static_cast<float>(rect.y);
2088  rd.texel[1] = st1[1];
2089  rd.texel2[1] = st2[1];
2090  m_renderMultitextureDatas.push_back(rd);
2091 
2092  uint32_t index = m_tc2Indices.empty() ? 0 : m_tc2Indices.back() + 1;
2093  uint32_t indices[] = { index, index + 1, index + 2, index, index + 2, index + 3 };
2094  m_tc2Indices.insert(m_tc2Indices.end(), indices, indices + 6);
2095 
2096  RenderObject ro(GL_TRIANGLES, 6, id1, id2);
2098  ro.rgba[0] = rgba[0];
2099  ro.rgba[1] = rgba[1];
2100  ro.rgba[2] = rgba[2];
2101  ro.rgba[3] = rgba[3];
2102  m_renderObjects.push_back(ro);
2103  }
2104  }
2105 
2107  for (std::vector<RenderZObjectTest>::iterator it = m_renderZ_objects.begin(); it != m_renderZ_objects.end(); ++it) {
2108  if (it->texture_id == texture_id) {
2109  if (it->elements < it->max_size - 4) {
2110  return &(*it);
2111  }
2112  }
2113  }
2114  int32_t max_quads_per_texbatch = 1000;
2115  // nothing was found (or we were forced to make new batch), we need to create new one
2116  RenderZObjectTest obj;
2117  if (!m_renderZ_objects.empty()) {
2118  obj.index = m_renderZ_objects.back().index + m_renderZ_objects.back().max_size;
2119  } else {
2120  obj.index = 0;
2121  }
2122  obj.texture_id = texture_id;
2123  obj.elements = 0;
2124  obj.max_size = max_quads_per_texbatch * 4;
2125 
2126  m_renderZ_objects.push_back(obj);
2127  return &m_renderZ_objects.back();
2128  }
2129 
2130  void RenderBackendOpenGL::addImageToArrayZ(uint32_t id, const Rect& rect, float vertexZ, float const* st, uint8_t alpha, uint8_t const* rgba) {
2131  // texture quad without alpha and coloring
2132  if (alpha == 255 && !rgba) {
2133  // ToDo: Consider if this is better.
2134  /*RenderZObjectTest* renderObj = getRenderBufferObject(id);
2135  uint32_t offset = renderObj->index + renderObj->elements;
2136  renderObj->elements += 4;
2137 
2138  renderDataZ* rd = &m_renderZ_datas[offset];
2139  rd->vertex[0] = static_cast<float>(rect.x);
2140  rd->vertex[1] = static_cast<float>(rect.y);
2141  rd->vertex[2] = vertexZ;
2142  rd->texel[0] = st[0];
2143  rd->texel[1] = st[1];
2144 
2145  ++rd;
2146  rd->vertex[0] = static_cast<float>(rect.x);
2147  rd->vertex[1] = static_cast<float>(rect.y+rect.h);
2148  rd->vertex[2] = vertexZ;
2149  rd->texel[0] = st[0];
2150  rd->texel[1] = st[3];
2151 
2152  ++rd;
2153  rd->vertex[0] = static_cast<float>(rect.x+rect.w);
2154  rd->vertex[1] = static_cast<float>(rect.y+rect.h);
2155  rd->vertex[2] = vertexZ;
2156  rd->texel[0] = st[2];
2157  rd->texel[1] = st[3];
2158 
2159  ++rd;
2160  rd->vertex[0] = static_cast<float>(rect.x+rect.w);
2161  rd->vertex[1] = static_cast<float>(rect.y);
2162  rd->vertex[2] = vertexZ;
2163  rd->texel[0] = st[2];
2164  rd->texel[1] = st[1];*/
2165 
2166  renderDataZ rd;
2167  rd.vertex[0] = static_cast<float>(rect.x);
2168  rd.vertex[1] = static_cast<float>(rect.y);
2169  rd.vertex[2] = vertexZ;
2170  rd.texel[0] = st[0];
2171  rd.texel[1] = st[1];
2172  m_renderTextureDatasZ.push_back(rd);
2173 
2174  rd.vertex[0] = static_cast<float>(rect.x);
2175  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2176  rd.texel[1] = st[3];
2177  m_renderTextureDatasZ.push_back(rd);
2178 
2179  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2180  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2181  rd.texel[0] = st[2];
2182  m_renderTextureDatasZ.push_back(rd);
2183 
2184  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2185  rd.vertex[1] = static_cast<float>(rect.y);
2186  rd.texel[1] = st[1];
2187  m_renderTextureDatasZ.push_back(rd);
2188 
2189  RenderZObject ro;
2190  ro.texture_id = id;
2191  m_renderTextureObjectsZ.push_back(ro);
2192  } else {
2193  // multitexture with color, second texel is used for m_maskOverlay
2194  if (rgba) {
2195  renderData2TCZ rd;
2196  rd.vertex[0] = static_cast<float>(rect.x);
2197  rd.vertex[1] = static_cast<float>(rect.y);
2198  rd.vertex[2] = vertexZ;
2199  rd.texel[0] = st[0];
2200  rd.texel[1] = st[1];
2201  rd.texel2[0] = 0.0;
2202  rd.texel2[1] = 0.0;
2203  rd.color[0] = 255;
2204  rd.color[1] = 255;
2205  rd.color[2] = 255;
2206  rd.color[3] = alpha;
2207  m_renderMultitextureDatasZ.push_back(rd);
2208 
2209  rd.vertex[0] = static_cast<float>(rect.x);
2210  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2211  rd.texel[1] = st[3];
2212  rd.texel2[1] = 1.0;
2213  m_renderMultitextureDatasZ.push_back(rd);
2214 
2215  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2216  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2217  rd.texel[0] = st[2];
2218  rd.texel2[0] = 1.0;
2219  m_renderMultitextureDatasZ.push_back(rd);
2220 
2221  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2222  rd.vertex[1] = static_cast<float>(rect.y);
2223  rd.texel[1] = st[1];
2224  rd.texel2[1] = 0.0;
2225  m_renderMultitextureDatasZ.push_back(rd);
2226 
2227  RenderObject ro(GL_TRIANGLES, 6, id);
2228  ro.color = true;
2230  ro.rgba[0] = rgba[0];
2231  ro.rgba[1] = rgba[1];
2232  ro.rgba[2] = rgba[2];
2233  ro.rgba[3] = rgba[3];
2234  m_renderMultitextureObjectsZ.push_back(ro);
2235  // texture with alpha
2236  } else {
2237  renderDataColorZ rd;
2238  rd.vertex[0] = static_cast<float>(rect.x);
2239  rd.vertex[1] = static_cast<float>(rect.y);
2240  rd.vertex[2] = vertexZ;
2241  rd.texel[0] = st[0];
2242  rd.texel[1] = st[1];
2243  rd.color[0] = 255;
2244  rd.color[1] = 255;
2245  rd.color[2] = 255;
2246  rd.color[3] = alpha;
2247  m_renderTextureColorDatasZ.push_back(rd);
2248 
2249  rd.vertex[0] = static_cast<float>(rect.x);
2250  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2251  rd.texel[1] = st[3];
2252  m_renderTextureColorDatasZ.push_back(rd);
2253 
2254  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2255  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2256  rd.texel[0] = st[2];
2257  m_renderTextureColorDatasZ.push_back(rd);
2258 
2259  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2260  rd.vertex[1] = static_cast<float>(rect.y);
2261  rd.texel[1] = st[1];
2262  m_renderTextureColorDatasZ.push_back(rd);
2263 
2264  RenderZObject ro;
2265  ro.texture_id = id;
2266  m_renderTextureColorObjectsZ.push_back(ro);
2267  }
2268  }
2269  }
2270 
2271  void RenderBackendOpenGL::addImageToArrayZ(const Rect& rect, float vertexZ, uint32_t id1, float const* st1, uint32_t id2, float const* st2, uint8_t alpha, uint8_t const* rgba) {
2272  if (rgba) {
2273  renderData2TCZ rd;
2274  rd.vertex[0] = static_cast<float>(rect.x);
2275  rd.vertex[1] = static_cast<float>(rect.y);
2276  rd.vertex[2] = vertexZ;
2277  rd.texel[0] = st1[0];
2278  rd.texel[1] = st1[1];
2279  rd.texel2[0] = st2[0];
2280  rd.texel2[1] = st2[1];
2281  rd.color[0] = 255;
2282  rd.color[1] = 255;
2283  rd.color[2] = 255;
2284  rd.color[3] = alpha;
2285  m_renderMultitextureDatasZ.push_back(rd);
2286 
2287  rd.vertex[0] = static_cast<float>(rect.x);
2288  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2289  rd.texel[1] = st1[3];
2290  rd.texel2[1] = st2[3];
2291  m_renderMultitextureDatasZ.push_back(rd);
2292 
2293  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2294  rd.vertex[1] = static_cast<float>(rect.y+rect.h);
2295  rd.texel[0] = st1[2];
2296  rd.texel2[0] = st2[2];
2297  m_renderMultitextureDatasZ.push_back(rd);
2298 
2299  rd.vertex[0] = static_cast<float>(rect.x+rect.w);
2300  rd.vertex[1] = static_cast<float>(rect.y);
2301  rd.texel[1] = st1[1];
2302  rd.texel2[1] = st2[1];
2303  m_renderMultitextureDatasZ.push_back(rd);
2304 
2305  RenderObject ro(GL_TRIANGLES, 6, id1, id2);
2307  ro.rgba[0] = rgba[0];
2308  ro.rgba[1] = rgba[1];
2309  ro.rgba[2] = rgba[2];
2310  ro.rgba[3] = rgba[3];
2311  m_renderMultitextureObjectsZ.push_back(ro);
2312  }
2313  }
2314 
2316  glActiveTexture(GL_TEXTURE1);
2317  glEnable(GL_TEXTURE_2D);
2318 
2319  if(m_maskOverlay == 0) {
2320  // Constant texture - can be constant across every tilesets
2321  glGenTextures(1, &m_maskOverlay);
2322 
2323  uint8_t dummydata[3] = {127, 127, 127};
2324  glBindTexture(GL_TEXTURE_2D, m_maskOverlay);
2325  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2326  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2327  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2328  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
2329  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0,
2330  GL_RGB, GL_UNSIGNED_BYTE, dummydata);
2331  } else {
2332  glBindTexture(GL_TEXTURE_2D, m_maskOverlay);
2333  }
2334 
2336 
2337  // Texture Unit 1
2338  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
2339  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
2340  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
2341 
2342  // Arg0
2343  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
2344  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
2345  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
2346  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
2347 
2348  // The alpha component is taken only from 0th tex unit which is
2349  // Arg0 in our case, therefore we doesn't need to set operands
2350  // and sources for the rest of arguments
2351 
2352  // Arg1
2353  glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
2354  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
2355 
2356  // Arg2
2357  // uses alpha part of environmental color as interpolation factor
2358  glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
2359  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
2360 
2361  glDisable(GL_TEXTURE_2D);
2362 
2363  // Texture Unit 2
2364  glClientActiveTexture(GL_TEXTURE2);
2365  glActiveTexture(GL_TEXTURE2);
2366  glEnable(GL_TEXTURE_2D);
2367 
2368  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
2369  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
2370  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
2371 
2372  // Arg0
2373  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
2374  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE2);
2375  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
2376  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
2377 
2378  // The alpha component is taken only from 0th tex unit which is
2379  // Arg0 in our case, therefore we doesn't need to set operands
2380  // and sources for the rest of arguments
2381 
2382  // Arg1
2383  glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
2384  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
2385 
2386  // Arg2
2387  // uses alpha part of environmental color as interpolation factor
2388  glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
2389  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
2390 
2391  glDisable(GL_TEXTURE_2D);
2392 
2393  // Texture Unit 3
2394  glClientActiveTexture(GL_TEXTURE3);
2395  glActiveTexture(GL_TEXTURE3);
2396  glEnable(GL_TEXTURE_2D);
2397 
2398  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
2399  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
2400  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
2401 
2402  // Arg0
2403  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
2404  glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE3);
2405  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
2406  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
2407 
2408  // The alpha component is taken only from 3th tex unit which is
2409  // Arg0 in our case, therefore we doesn't need to set operands
2410  // and sources for the rest of arguments
2411 
2412  // Arg1
2413  glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE3);
2414  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
2415 
2416  // Arg2
2417  // uses alpha part of environmental color as interpolation factor
2418  glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT);
2419  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
2420 
2421  // Return to normal sampling mode
2422  glDisable(GL_TEXTURE_2D);
2423  glActiveTexture(GL_TEXTURE0);
2424  m_state.active_tex = 0;
2425  glClientActiveTexture(GL_TEXTURE0);
2427 
2428  // For now it's unneecessary - Only needed if we intend to use the next texture unit in different case
2429  //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2430  }
2431 
2432  void RenderBackendOpenGL::captureScreen(const std::string& filename) {
2433  const uint32_t swidth = getWidth();
2434  const uint32_t sheight = getHeight();
2435 
2436  uint8_t *pixels;
2437  SDL_Surface *surface = SDL_CreateRGBSurface(0, swidth, sheight, 24,
2438  RMASK, GMASK, BMASK, NULLMASK);
2439 
2440  if (!surface) {
2441  return;
2442  }
2443 
2444  SDL_LockSurface(surface);
2445  pixels = new uint8_t[swidth * sheight * 3];
2446  glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
2447  uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
2448  // Copy the "reversed_image" memory to the "image" memory
2449  for (int32_t y = (sheight - 1); y >= 0; --y) {
2450  uint8_t *rowbegin = pixels + y * swidth * 3;
2451  uint8_t *rowend = rowbegin + swidth * 3;
2452 
2453  std::copy(rowbegin, rowend, imagepixels);
2454 
2455  // Advance a row in the output surface.
2456  imagepixels += surface->pitch;
2457  }
2458 
2459  SDL_UnlockSurface(surface);
2460  Image::saveAsPng(filename, *surface);
2461 
2462  SDL_FreeSurface(surface);
2463  delete[] pixels;
2464  }
2465 
2466  void RenderBackendOpenGL::captureScreen(const std::string& filename, uint32_t width, uint32_t height) {
2467  const uint32_t swidth = getWidth();
2468  const uint32_t sheight = getHeight();
2469  const bool same_size = (width == swidth && height == sheight);
2470 
2471  if (width < 1 || height < 1) {
2472  return;
2473  }
2474 
2475  if (same_size) {
2476  captureScreen(filename);
2477  return;
2478  }
2479 
2480  uint8_t *pixels;
2481  // create source surface
2482  SDL_Surface* src = SDL_CreateRGBSurface(0, swidth, sheight, 32,
2483  RMASK, GMASK, BMASK, AMASK);
2484 
2485  if (!src) {
2486  return;
2487  }
2488 
2489  if (SDL_MUSTLOCK(src)) {
2490  SDL_LockSurface(src);
2491  }
2492  pixels = new uint8_t[swidth * sheight * 4];
2493  glReadPixels(0, 0, swidth, sheight, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
2494 
2495  uint8_t* imagepixels = reinterpret_cast<uint8_t*>(src->pixels);
2496  // Copy the "reversed_image" memory to the "image" memory
2497  for (int32_t y = (sheight - 1); y >= 0; --y) {
2498  uint8_t *rowbegin = pixels + y * swidth * 4;
2499  uint8_t *rowend = rowbegin + swidth * 4;
2500 
2501  std::copy(rowbegin, rowend, imagepixels);
2502 
2503  // Advance a row in the output surface.
2504  imagepixels += src->pitch;
2505  }
2506 
2507  // create destination surface
2508  SDL_Surface* dst = SDL_CreateRGBSurface(0, width, height, 32,
2509  RMASK, GMASK, BMASK, AMASK);
2510 
2511  uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
2512  uint32_t* src_help_pointer = src_pointer;
2513  uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
2514 
2515  int32_t x, y, *sx_ca, *sy_ca;
2516  int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
2517  int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
2518  int32_t sx_c = 0;
2519  int32_t sy_c = 0;
2520 
2521  // Allocates memory and calculates row wide&height
2522  int32_t* sx_a = new int32_t[dst->w + 1];
2523  sx_ca = sx_a;
2524  for (x = 0; x <= dst->w; x++) {
2525  *sx_ca = sx_c;
2526  sx_ca++;
2527  sx_c &= 0xffff;
2528  sx_c += sx;
2529  }
2530 
2531  int32_t* sy_a = new int32_t[dst->h + 1];
2532  sy_ca = sy_a;
2533  for (y = 0; y <= dst->h; y++) {
2534  *sy_ca = sy_c;
2535  sy_ca++;
2536  sy_c &= 0xffff;
2537  sy_c += sy;
2538  }
2539  sy_ca = sy_a;
2540 
2541  // Transfers the image data
2542 
2543  if (SDL_MUSTLOCK(dst)) {
2544  SDL_LockSurface(dst);
2545  }
2546 
2547  for (y = 0; y < dst->h; y++) {
2548  src_pointer = src_help_pointer;
2549  sx_ca = sx_a;
2550  for (x = 0; x < dst->w; x++) {
2551  *dst_pointer = *src_pointer;
2552  sx_ca++;
2553  src_pointer += (*sx_ca >> 16);
2554  dst_pointer++;
2555  }
2556  sy_ca++;
2557  src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
2558  }
2559 
2560  if (SDL_MUSTLOCK(dst)) {
2561  SDL_UnlockSurface(dst);
2562  }
2563  if (SDL_MUSTLOCK(src)) {
2564  SDL_UnlockSurface(src);
2565  }
2566 
2567  Image::saveAsPng(filename, *dst);
2568 
2569  // Free memory
2570  SDL_FreeSurface(src);
2571  SDL_FreeSurface(dst);
2572  delete[] sx_a;
2573  delete[] sy_a;
2574  delete[] pixels;
2575  }
2576 
2577  void RenderBackendOpenGL::setClipArea(const Rect& cliparea, bool clear) {
2578  glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
2579  if (clear) {
2580  if (m_isbackgroundcolor) {
2581  float red = float(m_backgroundcolor.r/255.0);
2582  float green = float(m_backgroundcolor.g/255.0);
2583  float blue = float(m_backgroundcolor.b/255.0);
2584  glClearColor(red, green, blue, 0.0);
2585  m_isbackgroundcolor = false;
2586  }
2587  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2588  }
2589  }
2590 
2592  // flush down what we batched for the old target
2594 
2595  m_img_target = img;
2596  m_target_discard = discard;
2597 
2598  // to render on something, we need to make sure its loaded already in gpu memory
2601 
2602  GLImage* glimage = static_cast<GLImage*>(m_img_target.get());
2603 
2604  GLuint targetid = glimage->getTexId();
2607 
2608  // quick & dirty hack for attaching compressed texture
2609  if(glimage->isCompressed()) {
2610  bindTexture(targetid);
2611  GLubyte* pixels = new GLubyte[w*h*4];
2612  // here we get decompressed pixels
2613  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
2614  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
2615  delete [] pixels;
2616  glimage->setCompressed(false);
2617  }
2618 
2619  // can we use fbo?
2620  if (GLEW_EXT_framebuffer_object && m_useframebuffer) {
2621  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo_id);
2622  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
2623  GL_TEXTURE_2D, targetid, 0);
2624 
2625  // currenty unused, is needed in case the static layers should be rendered with depth buffer (instead of sorting)
2626  // see LayerCache
2627  //glBindRenderbuffer(GL_RENDERBUFFER, m_depthbuffer_id);
2628  //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
2629  //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer_id);
2630  }
2631 
2632  glViewport(0, 0, w, h);
2633  glMatrixMode(GL_PROJECTION);
2634  glLoadIdentity();
2635  // invert top with bottom
2636  glOrtho(0, w, 0, h, -100, 100);
2637  glMatrixMode(GL_MODELVIEW);
2638  // because of inversion 2 lines above we need to also invert culling faces
2639  glCullFace(GL_FRONT);
2640 
2641  if (m_target_discard) {
2642  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2643  } else if (!m_target_discard && (!GLEW_EXT_framebuffer_object || !m_useframebuffer)) {
2644  // if we wanna just add something to render target, we need to first render previous contents
2645  addImageToArray(targetid, m_img_target->getArea(),
2646  static_cast<GLImage*>(m_img_target.get())->getTexCoords(), 255, 0);
2647  }
2648  }
2649 
2651  assert(m_target != m_screen);
2652 
2653  // flush down what we batched
2655 
2656  if (GLEW_EXT_framebuffer_object && m_useframebuffer) {
2657  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2658  } else {
2659  bindTexture(0, static_cast<GLImage*>(m_img_target.get())->getTexId());
2660  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0,
2662  }
2663 
2664  m_target = m_screen;
2665  glViewport(0, 0, m_screen->w, m_screen->h);
2666  glMatrixMode(GL_PROJECTION);
2667  glLoadIdentity();
2668  glOrtho(0, m_screen->w, m_screen->h, 0, -100, 100);
2669  glMatrixMode(GL_MODELVIEW);
2670  glCullFace(GL_BACK);
2671  }
2672 
2673  void RenderBackendOpenGL::renderGuiGeometry(const std::vector<GuiVertex>& vertices, const std::vector<int>& indices, const DoublePoint& translation, ImagePtr texture) {
2674 
2675  glPushMatrix();
2676  glTranslatef(translation.x, translation.y, 0);
2677 
2678  glVertexPointer(2, GL_DOUBLE, sizeof(GuiVertex), &vertices[0].position);
2679  glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(GuiVertex), &vertices[0].color);
2680 
2681  GLuint texId = 0;
2682 
2683  GLImage* glImage = dynamic_cast<GLImage*>(texture.get());
2684  if(glImage) {
2685  glImage->forceLoadInternal();
2686  texId = glImage->getTexId();
2687  }
2688 
2689  if(texId == 0) {
2690  glDisable(GL_TEXTURE_2D);
2691  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2692  } else {
2693  glEnable(GL_TEXTURE_2D);
2694  glBindTexture(GL_TEXTURE_2D, texId);
2695  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2696  glTexCoordPointer(2, GL_DOUBLE, sizeof(GuiVertex), &vertices[0].texCoords);
2697  }
2698 
2699  glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, &indices[0]);
2700 
2701  glPopMatrix();
2702  }
2703 }
static T ATan2(T _x, T _y)
Definition: fife_math.h:207
Abstract interface for all the renderbackends.
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
virtual void setScreenMode(const ScreenMode &mode)
Sets the mainscreen display mode.
std::vector< RenderZObjectTest > m_renderZ_objects
static T Cos(T _val)
Definition: fife_math.h:217
virtual void setLighting(float red, float green, float blue)
Set colors for lighting.
Base Class for Images.
Definition: image.h:48
virtual void drawFillCircleSegment(const Point &p, uint32_t radius, int32_t sangle, int32_t eangle, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a filled circle segment.
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.
virtual uint32_t getLightingModel() const
Gets the current light model.
T h
Height of the rectangle.
Definition: rect.h:93
Helper class to create log strings out from separate parts Usage: LMsg("some text") << variable << "...
Definition: logger.h:82
uint32_t next(octet_iterator &it, octet_iterator end)
Definition: checked.h:137
SDL_PixelFormat m_rgba_format
SDL_Window * m_window
T x
The X Coordinate.
Definition: rect.h:84
virtual void renderGuiGeometry(const std::vector< GuiVertex > &vertices, const std::vector< int > &indices, const DoublePoint &translation, ImagePtr texture)
Renders geometry required by gui.
uint8_t getDisplay() const
Returns the display index.
Definition: devicecaps.h:108
uint32_t getHeight() const
void setCompressed(bool compressed)
Definition: glimage.h:82
uint32_t getSDLFlags() const
Returns the SDL flags used when testing this mode.
Definition: devicecaps.h:80
virtual void drawFillCircle(const Point &p, uint32_t radius, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a filled circle.
std::vector< renderDataP > m_renderPrimitiveDatas
virtual void renderVertexArrays()
Render the Vertex Arrays, only for primitives (points, lines,...)
std::vector< RenderObject > m_renderMultitextureObjectsZ
std::vector< renderDataColorZ > m_renderTextureColorDatasZ
void disableTextures(uint32_t texUnit)
Rect getArea() const
Definition: image.cpp:176
static void saveAsPng(const std::string &filename, const SDL_Surface &surface)
Saves the SDL_Surface to png format.
Definition: image.cpp:231
virtual void init(const std::string &driver)
Initializes the backend.
uint16_t getBPP() const
Returns the number of bits per pixel this mode uses.
Definition: devicecaps.h:72
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.
std::vector< renderData2TC > m_renderMultitextureDatas
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.
std::vector< uint32_t > m_tc2Indices
const uint32_t RMASK
Definition: fife_stdint.h:53
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.
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.
virtual void setClipArea(const Rect &cliparea, bool clear)
Sets given clip area into image.
GLuint getTexId() const
Definition: glimage.cpp:579
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.
RenderObject(GLenum m, uint16_t s, uint32_t t1=0, uint32_t t2=0)
const uint32_t AMASK
Definition: fife_stdint.h:56
void setStencilTest(uint8_t stencil_ref, GLenum stencil_op, GLenum stencil_func)
void enableTextures(uint32_t texUnit)
std::vector< uint32_t > m_indices
static indices for vertex data with z
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.
void setVertexPointer(GLint size, GLsizei stride, const GLvoid *ptr)
virtual void drawCircleSegment(const Point &p, uint32_t radius, int32_t sangle, int32_t eangle, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a circle segment.
virtual void setLightingModel(uint32_t lighting)
Initializes the light.
virtual Image * createImage(IResourceLoader *loader=0)
uint32_t getHeight() const
Definition: image.cpp:160
std::vector< uint32_t > m_pIndices
bool isFullScreen() const
True if this is a fullscreen mode.
Definition: devicecaps.h:84
unsigned char uint8_t
Definition: core.h:38
virtual void resetLighting()
Reset lighting with default values.
virtual void disableScissorTest()
Disables scissor test on the render backend.
virtual void drawCircle(const Point &p, uint32_t radius, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws a circle.
const uint32_t GMASK
Definition: fife_stdint.h:54
uint32_t getFormat() const
Returns the pixel format enum.
Definition: devicecaps.h:100
virtual void captureScreen(const std::string &filename)
Creates a Screenshot and saves it to a file.
SDL_Surface * getSurface()
Definition: image.h:96
static bool Equal(T _val1, T _val2)
Definition: fife_math.h:287
std::vector< renderDataT > m_renderTextureDatas
virtual void startFrame()
Called when a new frame starts.
static T Sin(T _val)
Definition: fife_math.h:267
virtual void drawThickLine(const Point &p1, const Point &p2, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws line between given points with given RGBA and width.
virtual void clearBackBuffer()
Forces a clear of the backbuffer.
uint16_t getRefreshRate() const
Returns the refresh rate in Hz of this mode.
Definition: devicecaps.h:76
virtual void changeBlending(int32_t scr, int32_t dst)
Change the Blendingmodel.
bool isCompressed() const
Definition: glimage.h:81
virtual void drawBezier(const std::vector< Point > &points, int32_t steps, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws bezier curve between given points with given RGBA and width.
uint16_t getHeight() const
Returns the height of the screen mode.
Definition: devicecaps.h:68
const uint32_t BMASK
Definition: fife_stdint.h:55
struct FIFE::RenderBackendOpenGL::currentState m_state
uint32_t getWidth() const
Definition: image.cpp:151
virtual void changeRenderInfos(RenderDataType type, uint16_t elements, int32_t src, int32_t dst, bool light, bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc, OverlayType otype=OVERLAY_TYPE_NONE)
Dirty helper function to change the render infos.
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:62
SDL_Surface * m_screen
static num_type twoPi()
Definition: fife_math.h:135
virtual void drawPolyLine(const std::vector< Point > &points, uint8_t width, uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
Draws lines between given points with given RGBA and width.
virtual void detachRenderTarget()
Detaches current render surface.
SDL_Color m_backgroundcolor
#define FL_LOG(logger, msg)
Definition: logger.h:71
void setTexCoordPointer(uint32_t texUnit, GLsizei stride, const GLvoid *ptr)
uint32_t getWidth() const
std::vector< renderDataZ > m_renderZ_datas
virtual void endFrame()
Called when a frame is finished and ready to be displayed.
virtual void forceLoadInternal()
Forces to load the image into internal memory of GPU.
Definition: glimage.cpp:506
std::vector< renderDataTC > m_renderTextureColorDatas
std::vector< renderData2TCZ > m_renderMultitextureDatasZ
TextureFiltering m_textureFilter
void setAlphaTest(float ref_alpha)
virtual void createMainScreen(const ScreenMode &mode, const std::string &title, const std::string &icon)
Creates the mainscreen (the display window).
std::vector< renderDataZ > m_renderTextureDatasZ
static num_type pi()
Definition: fife_math.h:134
virtual void forceLoadInternal()=0
Forces to load the image into internal memory of GPU.
std::vector< RenderObject > m_renderObjects
Implements an Image using OpenGL.
Definition: glimage.h:55
RenderZObjectTest * getRenderBufferObject(GLuint texture_id)
Point getBezierPoint(const std::vector< Point > &points, int32_t elements, float t)
Helper that returns an interpolated Point.
RenderBackendOpenGL(const SDL_Color &colorkey)
void setEnvironmentalColor(uint32_t texUnit, const uint8_t *rgba)
void setColorPointer(GLsizei stride, const GLvoid *ptr)
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.
std::vector< RenderZObject > m_renderTextureColorObjectsZ
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 addImageToArrayZ(uint32_t id, const Rect &rect, float vertexZ, float const *st, uint8_t alpha, uint8_t const *rgba)
ScreenMode m_screenMode
virtual void attachRenderTarget(ImagePtr &img, bool discard)
Attaches given image as a new render surface.
RenderDataType
void deinit()
Performs cleanup actions.
unsigned int uint32_t
Definition: core.h:40
std::vector< RenderZObject > m_renderTextureObjectsZ
virtual void startFrame()
Called when a new frame starts.
std::vector< uint32_t > m_tcIndices
T w
Width of the rectangle.
Definition: rect.h:90
std::vector< uint32_t > m_tIndices
virtual void enableScissorTest()
Enables scissor test on the render backend.
void bindTexture(uint32_t texUnit, GLuint texId)
virtual void endFrame()
Called when a frame is finished and ready to be displayed.
virtual void resetStencilBuffer(uint8_t buffer)
Reset stencil buffer with given value.
virtual const std::string & getName() const
The name of the renderbackend.