renderbackendopengle.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 by the FIFE team                              *
00003  *   http://www.fifengine.net                                              *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 
00024 // Platform specific includes
00025 
00026 // 3rd party library includes
00027 #include <SDL.h>
00028 
00029 // FIFE includes
00030 #include "util/base/exception.h"
00031 #include "util/log/logger.h"
00032 #include "video/devicecaps.h"
00033 
00034 #include "gleimage.h"
00035 #include "renderbackendopengle.h"
00036 #include "SDL_image.h"
00037 
00038 #define ALPHA_REF 0.3f
00039 
00040 
00041 namespace FIFE {
00042     static Logger _log(LM_VIDEO);
00043 
00044     class RenderBackendOpenGLe::RenderObject {
00045     public:
00046         RenderObject(GLenum m, uint16_t s, uint32_t t=0):
00047             mode(m),
00048             size(s),
00049             texture_id(t),
00050             src(4),
00051             dst(5),
00052             light(true),
00053             stencil_test(false),
00054             stencil_ref(0),
00055             stencil_op(0),
00056             stencil_func(0)
00057             {}
00058 
00059     public:
00060         GLenum mode;
00061         uint16_t size;
00062         uint32_t texture_id;
00063         int32_t src;
00064         int32_t dst;
00065         bool light;
00066         bool stencil_test;
00067         uint8_t stencil_ref;
00068         GLenum stencil_op;
00069         GLenum stencil_func;
00070         uint8_t rgb[3];
00071     };
00072 
00073     const float RenderBackendOpenGLe::zfar =   100.0f;
00074     const float RenderBackendOpenGLe::znear = -100.0f;
00075 
00076     static const int max_quads_per_texbatch = 600;
00077     static const int max_tex = 400; // TODO: could do this expandable
00078     static const int buffer_default_size = 4 * max_quads_per_texbatch * max_tex;    
00079 
00080     RenderBackendOpenGLe::RenderBackendOpenGLe(const SDL_Color& colorkey)
00081         : RenderBackend(colorkey), m_mask_overlays(0){
00082 
00083         m_state.tex_enabled[0] = false;
00084         m_state.tex_enabled[1] = false;
00085         m_state.texture[0] = 0;
00086         m_state.texture[1] = 0;
00087         m_state.active_tex = 0;
00088 
00089         m_state.lightmodel = 0;
00090         m_state.light_enabled = false;
00091 
00092         m_state.sten_enabled = false;
00093         m_state.sten_ref = 0;
00094         m_state.sten_buf = 0;
00095         m_state.sten_op = 0;
00096         m_state.sten_func = 0;
00097 
00098         m_state.env_color[0] = 0;
00099         m_state.env_color[1] = 0;
00100         m_state.env_color[2] = 0;
00101         m_state.blend_src = GL_SRC_ALPHA;
00102         m_state.blend_dst = GL_ONE_MINUS_SRC_ALPHA;
00103         m_state.alpha_enabled = true;
00104         m_state.depth_enabled = true;
00105         m_state.scissor_test = true;
00106     }
00107 
00108     RenderBackendOpenGLe::~RenderBackendOpenGLe() {
00109         glDeleteTextures(1, &m_mask_overlays);
00110         if(GLEE_EXT_framebuffer_object && m_useframebuffer) {
00111             glDeleteFramebuffers(1, &m_fbo_id);
00112         }
00113         deinit();
00114     }
00115 
00116     const std::string& RenderBackendOpenGLe::getName() const {
00117         static std::string backend_name = "OpenGLe";
00118         return backend_name;
00119     }
00120 
00121     void RenderBackendOpenGLe::init(const std::string& driver) {
00122         // note: driver has no affect on the opengl renderer so do nothing with it here.
00123         Uint32 flags = SDL_INIT_VIDEO;
00124         if (SDL_InitSubSystem(flags) < 0)
00125             throw SDLException(SDL_GetError());
00126         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00127         SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
00128 
00129         SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); // temporary hack
00130     }
00131 
00132     void RenderBackendOpenGLe::clearBackBuffer() {
00133         disableScissorTest();
00134         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00135         enableScissorTest();
00136     }
00137 
00138     void RenderBackendOpenGLe::createMainScreen(const ScreenMode& mode, const std::string& title, const std::string& icon){
00139         if(icon != "") {
00140             SDL_Surface *img = IMG_Load(icon.c_str());
00141             if(img != NULL) {
00142                 SDL_WM_SetIcon(img, 0);
00143                 SDL_FreeSurface(img);
00144             }
00145         }
00146         
00147         setScreenMode(mode);
00148         SDL_WM_SetCaption(title.c_str(), 0);
00149     }
00150 
00151     void RenderBackendOpenGLe::setScreenMode(const ScreenMode& mode) {
00152         uint16_t width = mode.getWidth();
00153         uint16_t height = mode.getHeight();
00154         uint16_t bitsPerPixel = mode.getBPP();
00155         bool fs = mode.isFullScreen();
00156         uint32_t flags = mode.getSDLFlags();
00157 
00158         if (bitsPerPixel != 0) {
00159             uint16_t bpp = SDL_VideoModeOK(width, height, bitsPerPixel, flags);
00160             if (!bpp){
00161                 throw SDLException("Selected video mode not supported!");
00162             }
00163         }
00164 
00165         if(m_screen) {
00166             SDL_FreeSurface(m_screen);
00167         }
00168         m_screen = SDL_SetVideoMode(width, height, bitsPerPixel, flags);
00169         if( !m_screen ) {
00170             throw SDLException("Unable to set video mode selected!");
00171         }
00172         m_target = m_screen;
00173 
00174         FL_LOG(_log, LMsg("RenderBackendOpenGLe")
00175             << "Videomode " << width << "x" << height
00176             << " at " << int32_t(bitsPerPixel) << " bpp");
00177 
00178         m_rgba_format = *(m_screen->format);
00179         m_rgba_format.Rmask = RMASK;
00180         m_rgba_format.Gmask = GMASK;
00181         m_rgba_format.Bmask = BMASK;
00182         m_rgba_format.Amask = AMASK;
00183 
00184         //update the screen mode with the actual flags used
00185         m_screenMode = ScreenMode(width,
00186                                   height,
00187                                   bitsPerPixel,
00188                                   m_screen->flags);
00189 
00190         if (!m_screen) {
00191             throw SDLException(SDL_GetError());
00192         }
00193 
00194         glViewport(0, 0, width, height);
00195         glMatrixMode(GL_PROJECTION);
00196         glLoadIdentity();
00197         glOrtho(0, width, height, 0, znear, zfar);
00198         glMatrixMode(GL_MODELVIEW);
00199         glLoadIdentity();
00200 
00201         glEnable(GL_CULL_FACE);
00202         glFrontFace(GL_CCW);
00203         glCullFace(GL_BACK);
00204 
00205         glPixelStorei(GL_PACK_ALIGNMENT, 1);
00206         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00207 
00208         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00209         glClearDepth(1.0f);
00210         glClearStencil(0);
00211 
00212         glEnable(GL_BLEND);
00213         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00214         glEnable(GL_ALPHA_TEST);
00215         glAlphaFunc(GL_GREATER, ALPHA_REF);
00216         glEnable(GL_DEPTH_TEST);
00217         glDepthFunc(GL_LEQUAL);
00218 
00219         glEnable(GL_SCISSOR_TEST);
00220 
00221         glEnableClientState(GL_VERTEX_ARRAY);
00222 
00223         prepareForOverlays();
00224 
00225         glPointSize(1.0);
00226         glLineWidth(1.0);
00227 
00228         if(GLEE_EXT_framebuffer_object && m_useframebuffer) {
00229             glGenFramebuffers(1, &m_fbo_id);
00230         }
00231 
00232         m_renderZ_datas.resize(buffer_default_size);
00233     }
00234 
00235     void RenderBackendOpenGLe::startFrame() {
00236         RenderBackend::startFrame();
00237     }
00238 
00239     void RenderBackendOpenGLe::endFrame() {
00240         SDL_GL_SwapBuffers();
00241         RenderBackend::endFrame();
00242     }
00243 
00244     Image* RenderBackendOpenGLe::createImage(IResourceLoader* loader) {
00245         return new GLeImage(loader);
00246     }
00247 
00248     Image* RenderBackendOpenGLe::createImage(const std::string& name, IResourceLoader* loader) {
00249         return new GLeImage(name, loader);
00250     }
00251 
00252     Image* RenderBackendOpenGLe::createImage(SDL_Surface* surface) {
00253         // Given an abritary surface, we must convert it to the format GLeImage will understand.
00254         // It's easiest to let SDL do this for us.
00255 
00256         // Uh. Gotta love this :-)
00257         // Check for colorkey too?
00258         // Leave out the loss/shift checks?
00259         if (32 == surface->format->BitsPerPixel
00260             && m_rgba_format.Rmask == surface->format->Rmask
00261             && m_rgba_format.Gmask == surface->format->Gmask
00262             && m_rgba_format.Bmask == surface->format->Bmask
00263             && m_rgba_format.Amask == surface->format->Amask
00264             && m_rgba_format.Rshift == surface->format->Rshift
00265             && m_rgba_format.Gshift == surface->format->Gshift
00266             && m_rgba_format.Bshift == surface->format->Bshift
00267             && m_rgba_format.Ashift == surface->format->Ashift
00268             && m_rgba_format.Rloss == surface->format->Rloss
00269             && m_rgba_format.Gloss == surface->format->Gloss
00270             && m_rgba_format.Bloss == surface->format->Bloss
00271             && m_rgba_format.Aloss == surface->format->Aloss
00272             && surface->flags & SDL_SRCALPHA   ) {
00273 
00274             return new GLeImage(surface);
00275         }
00276 
00277         uint8_t bpp = m_rgba_format.BitsPerPixel;
00278         m_rgba_format.BitsPerPixel = 32;
00279         SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
00280         m_rgba_format.BitsPerPixel = bpp;
00281         GLeImage* image = new GLeImage(conv);
00282         SDL_FreeSurface( surface );
00283         return image;
00284     }
00285 
00286     Image* RenderBackendOpenGLe::createImage(const std::string& name, SDL_Surface* surface) {
00287         // Given an abritary surface, we must convert it to the format GLeImage will understand.
00288         // It's easiest to let SDL do this for us.
00289 
00290         // Uh. Gotta love this :-)
00291         // Check for colorkey too?
00292         // Leave out the loss/shift checks?
00293         if (32 == surface->format->BitsPerPixel
00294             && m_rgba_format.Rmask == surface->format->Rmask
00295             && m_rgba_format.Gmask == surface->format->Gmask
00296             && m_rgba_format.Bmask == surface->format->Bmask
00297             && m_rgba_format.Amask == surface->format->Amask
00298             && m_rgba_format.Rshift == surface->format->Rshift
00299             && m_rgba_format.Gshift == surface->format->Gshift
00300             && m_rgba_format.Bshift == surface->format->Bshift
00301             && m_rgba_format.Ashift == surface->format->Ashift
00302             && m_rgba_format.Rloss == surface->format->Rloss
00303             && m_rgba_format.Gloss == surface->format->Gloss
00304             && m_rgba_format.Bloss == surface->format->Bloss
00305             && m_rgba_format.Aloss == surface->format->Aloss
00306             && surface->flags & SDL_SRCALPHA   ) {
00307 
00308             return new GLeImage(name, surface);
00309         }
00310 
00311         uint8_t bpp = m_rgba_format.BitsPerPixel;
00312         m_rgba_format.BitsPerPixel = 32;
00313         SDL_Surface* conv = SDL_ConvertSurface(surface, &m_rgba_format, SDL_SWSURFACE | SDL_SRCALPHA);
00314         m_rgba_format.BitsPerPixel = bpp;
00315         GLeImage* image = new GLeImage(name, conv);
00316         SDL_FreeSurface( surface );
00317         return image;
00318     }
00319 
00320     Image* RenderBackendOpenGLe::createImage(const uint8_t* data, uint32_t width, uint32_t height) {
00321         return new GLeImage(data, width, height);
00322     }
00323 
00324     Image* RenderBackendOpenGLe::createImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height) {
00325         return new GLeImage(name, data, width, height);
00326     }
00327 
00328     void RenderBackendOpenGLe::setLightingModel(uint32_t lighting) {
00329         if (m_state.lightmodel != lighting) {
00330             if (m_state.lightmodel != 0) {
00331                 disableLighting();
00332                 glDisable(GL_COLOR_MATERIAL);
00333             } else if (lighting != 0) {
00334                 m_state.lightmodel = lighting;  
00335                 enableLighting();
00336                 glEnable(GL_LIGHT0);
00337                 glColorMaterial(GL_FRONT, GL_DIFFUSE);
00338                 glEnable(GL_COLOR_MATERIAL);
00339             }
00340             m_state.lightmodel = lighting;          
00341         }
00342     }
00343 
00344     uint32_t RenderBackendOpenGLe::getLightingModel() const {
00345         return m_state.lightmodel;
00346     }
00347 
00348     void RenderBackendOpenGLe::enableTextures(uint32_t texUnit) {
00349         if(m_state.tex_enabled[texUnit] == false) {
00350             if(m_state.active_tex != texUnit) {
00351                 m_state.active_tex = texUnit;
00352                 glActiveTexture(GL_TEXTURE0 + texUnit);
00353             }
00354             m_state.tex_enabled[texUnit] = true;
00355 
00356             glEnable(GL_TEXTURE_2D);
00357             if(texUnit == 0) {
00358                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
00359             }
00360         }
00361     }
00362 
00363     void RenderBackendOpenGLe::disableTextures(uint32_t texUnit)
00364     {
00365         if(m_state.tex_enabled[texUnit] == true) {
00366             if(m_state.active_tex != texUnit) {
00367                 m_state.active_tex = texUnit;
00368                 glActiveTexture(GL_TEXTURE0 + texUnit);
00369             }
00370             m_state.tex_enabled[texUnit] = false;
00371 
00372             glDisable(GL_TEXTURE_2D);
00373             if(texUnit == 0) {
00374                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
00375             }
00376         }
00377     }
00378 
00379     void RenderBackendOpenGLe::bindTexture(uint32_t texUnit, GLuint texId) {
00380         enableTextures(texUnit);
00381 
00382         if(m_state.texture[texUnit] != texId) {
00383             if(m_state.active_tex != texUnit) {
00384                 m_state.active_tex = texUnit;
00385                 glActiveTexture(GL_TEXTURE0 + texUnit);
00386             }
00387             m_state.texture[texUnit] = texId;
00388             glBindTexture(GL_TEXTURE_2D, texId);
00389         }
00390     }
00391 
00392     void RenderBackendOpenGLe::bindTexture(GLuint texId) {
00393         if(m_state.texture[m_state.active_tex] != texId) {
00394             m_state.texture[m_state.active_tex] = texId;
00395             glBindTexture(GL_TEXTURE_2D, texId);
00396         }
00397     }
00398 
00399     void RenderBackendOpenGLe::enableLighting() {
00400         if (m_state.lightmodel != 0 && !m_state.light_enabled) {
00401             glEnable(GL_LIGHTING);
00402             m_state.light_enabled = true;
00403         }
00404     }
00405 
00406     void RenderBackendOpenGLe::disableLighting() {
00407         if (m_state.lightmodel != 0 && m_state.light_enabled) {
00408             glDisable(GL_LIGHTING);
00409             m_state.light_enabled = false;
00410         }
00411     }
00412 
00413     void RenderBackendOpenGLe::setLighting(float red, float green, float blue) {
00414         if (m_state.lightmodel != 0) {
00415             GLfloat lightDiffuse[] = {red, green, blue, 1.0f};
00416             glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
00417         }
00418     }
00419 
00420     void RenderBackendOpenGLe::resetLighting() {
00421         m_state.light_enabled = false;
00422     }
00423 
00424     void RenderBackendOpenGLe::enableStencilTest() {
00425         if (!m_state.sten_enabled) {
00426             glEnable(GL_STENCIL_TEST);
00427             m_state.sten_enabled = true;
00428         }
00429     }
00430 
00431     void RenderBackendOpenGLe::disableStencilTest() {
00432         if (m_state.sten_enabled) {
00433             glDisable(GL_STENCIL_TEST);
00434             m_state.sten_enabled = false;
00435         }
00436     }
00437 
00438     void RenderBackendOpenGLe::setStencilTest(uint8_t stencil_ref, GLenum stencil_op, GLenum stencil_func) {
00439         enableStencilTest();
00440         if(m_state.sten_op != stencil_op) {
00441             m_state.sten_op = stencil_op;
00442             glStencilOp(GL_KEEP, GL_KEEP, m_state.sten_op);
00443         }
00444 
00445         if(m_state.sten_ref != stencil_ref || m_state.sten_func != stencil_func) {
00446             m_state.sten_ref = stencil_ref;
00447             m_state.sten_func = stencil_func;
00448             glStencilFunc(m_state.sten_func, stencil_ref, 0xff);
00449         }
00450     }
00451 
00452     void RenderBackendOpenGLe::resetStencilBuffer(uint8_t buffer) {
00453         if (buffer != m_state.sten_buf) {
00454             m_state.sten_buf = buffer;
00455             glClearStencil(buffer);
00456         }
00457         disableScissorTest();
00458         glClear(GL_STENCIL_BUFFER_BIT);
00459         enableScissorTest();
00460     }
00461 
00462     void RenderBackendOpenGLe::enableAlphaTest() {
00463         if (!m_state.alpha_enabled) {
00464             glEnable(GL_ALPHA_TEST);
00465             m_state.alpha_enabled = true;
00466         }
00467     }
00468 
00469     void RenderBackendOpenGLe::disableAlphaTest() {
00470         if (m_state.alpha_enabled) {
00471             glDisable(GL_ALPHA_TEST);
00472             m_state.alpha_enabled = false;
00473         }
00474     }
00475 
00476     void RenderBackendOpenGLe::setAlphaTest(float ref_alpha) {
00477         enableAlphaTest();
00478         glAlphaFunc(GL_GREATER, ref_alpha);
00479     }
00480 
00481     void RenderBackendOpenGLe::enableDepthTest() {
00482         if (!m_state.depth_enabled) {
00483             glEnable(GL_DEPTH_TEST);
00484             m_state.depth_enabled = true;
00485         }
00486     }
00487 
00488     void RenderBackendOpenGLe::disableDepthTest() {
00489         if (m_state.depth_enabled) {
00490             glDisable(GL_DEPTH_TEST);
00491             m_state.depth_enabled = false;
00492         }
00493     }
00494 
00495     void RenderBackendOpenGLe::setEnvironmentalColor(const uint8_t* rgb) {
00496         if (memcmp(m_state.env_color, rgb, sizeof(uint8_t) * 3)) {
00497             memcpy(m_state.env_color, rgb, sizeof(uint8_t) * 3);
00498             GLfloat rgbf[4] = {
00499                 static_cast<float>(m_state.env_color[0]) / 255.0f,
00500                 static_cast<float>(m_state.env_color[1]) / 255.0f,
00501                 static_cast<float>(m_state.env_color[2]) / 255.0f, 0.0f};
00502             glActiveTexture(GL_TEXTURE1);
00503             glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgbf);
00504             glActiveTexture(GL_TEXTURE0);
00505         }
00506     }
00507 
00508     void RenderBackendOpenGLe::enableScissorTest() {
00509         if(m_state.scissor_test == false) {
00510             m_state.scissor_test = true;
00511             glEnable(GL_SCISSOR_TEST);
00512         }
00513     }
00514 
00515     void RenderBackendOpenGLe::disableScissorTest() {
00516         if(m_state.scissor_test == true)    {
00517             m_state.scissor_test = false;
00518             glDisable(GL_SCISSOR_TEST);
00519         }
00520     }
00521 
00522     void RenderBackendOpenGLe::changeBlending(int32_t src, int32_t dst) {
00523         GLenum src_fact;
00524         GLenum dst_fact;
00525 
00526         switch(src) {
00527             case 0  : src_fact = GL_ZERO; break;
00528             case 1  : src_fact = GL_ONE; break;
00529             case 2  : src_fact = GL_DST_COLOR; break;
00530             case 3  : src_fact = GL_ONE_MINUS_DST_COLOR; break;
00531             case 4  : src_fact = GL_SRC_ALPHA; break;
00532             case 5  : src_fact = GL_ONE_MINUS_SRC_ALPHA; break;
00533             case 6  : src_fact = GL_DST_ALPHA; break;
00534             case 7  : src_fact = GL_ONE_MINUS_DST_ALPHA; break;
00535 
00536             default : src_fact = GL_DST_COLOR; break;
00537         }
00538 
00539         switch(dst) {
00540             case 0  : dst_fact = GL_ZERO; break;
00541             case 1  : dst_fact = GL_ONE; break;
00542             case 2  : dst_fact = GL_SRC_COLOR; break;
00543             case 3  : dst_fact = GL_ONE_MINUS_SRC_COLOR; break;
00544             case 4  : dst_fact = GL_SRC_ALPHA; break;
00545             case 5  : dst_fact = GL_ONE_MINUS_SRC_ALPHA; break;
00546             case 6  : dst_fact = GL_DST_ALPHA; break;
00547             case 7  : dst_fact = GL_ONE_MINUS_DST_ALPHA; break;
00548 
00549             default : dst_fact = GL_SRC_ALPHA; break;
00550         }
00551 
00552         if (m_state.blend_src != src_fact || m_state.blend_dst != dst_fact) {
00553             m_state.blend_src = src_fact;
00554             m_state.blend_dst = dst_fact;
00555             glBlendFunc(src_fact, dst_fact);
00556         }
00557     }
00558 
00559     void RenderBackendOpenGLe::changeRenderInfos(uint16_t elements, int32_t src, int32_t dst, bool light,
00560         bool stentest, uint8_t stenref, GLConstants stenop, GLConstants stenfunc) {
00561         
00562         uint16_t count = 0;
00563         uint32_t size = m_render_objects.size();
00564         while (count != elements) {
00565             ++count;
00566             RenderObject& r = m_render_objects.at(size-count);
00567 
00568             r.src = src;
00569             r.dst = dst;
00570             r.light = light;
00571             if (stentest) {
00572                 r.stencil_test = stentest;
00573                 r.stencil_ref = stenref;
00574                 r.stencil_op = stenop;
00575                 r.stencil_func = stenfunc;
00576             }
00577         }
00578     }
00579 
00580     void RenderBackendOpenGLe::renderVertexArrays() {
00581         // Rendering order:
00582         // * batched ordinary, full opacity textured quads
00583         // * outlines and unlit with optional stencil test on (write on) if light is enabled
00584         // * colored overlays - full opacity and (semi)transparent 
00585         // * semi transparent textured quads (sorted by instancerenderer)
00586         if(!m_renderZ_objects.empty() || !m_renderZ_objects_forced.empty()) {
00587             renderWithZ();
00588         }
00589 
00590         // * everything else that doesn't use Z value or features like
00591         //   stencil test/alpha test/colored overlays/semi transparency:
00592         //    - different renderers (aside from instance one)
00593         //    - gui
00594         if(!m_render_objects.empty()) {
00595             renderWithoutZ();
00596         }
00597     }
00598 
00599     void RenderBackendOpenGLe::renderWithZ() {
00600         enableAlphaTest();
00601         enableDepthTest();
00602         enableTextures(0);
00603         enableLighting();
00604         glDisableClientState(GL_COLOR_ARRAY);
00605         
00606         /* 1) ordinary z-valued quads */ {
00607             static const uint32_t stride = sizeof(RenderZData);
00608 
00609             glVertexPointer(3, GL_FLOAT, stride, &m_renderZ_datas[0].vertex);
00610             glTexCoordPointer(2, GL_FLOAT, stride, &m_renderZ_datas[0].texel);
00611 
00612             std::vector<RenderZObject>::iterator iter = m_renderZ_objects.begin();
00613             for ( ; iter != m_renderZ_objects.end(); ++iter) {
00614                 bindTexture(iter->texture_id);
00615                 glDrawArrays(GL_QUADS, iter->index, iter->elements);
00616             }
00617             m_renderZ_objects.clear();
00618         }
00619 
00620         // 2) forced batches (for unlit quads like outlines and unlit demanded instances)
00621         if (!m_renderZ_objects_forced.empty()) {
00622             static const uint32_t stride = sizeof(RenderZData);
00623 
00624             
00625             glVertexPointer(3, GL_FLOAT, stride, &m_renderZ_datas[0].vertex);
00626             glTexCoordPointer(2, GL_FLOAT, stride, &m_renderZ_datas[0].texel);
00627             setStencilTest(255, GL_REPLACE, GL_ALWAYS);
00628             disableLighting();
00629 
00630             std::vector<RenderZObject>::iterator iter = m_renderZ_objects_forced.begin();
00631             for ( ; iter != m_renderZ_objects_forced.end(); ++iter) {
00632                 bindTexture(iter->texture_id);
00633                 glDrawArrays(GL_QUADS, iter->index, iter->elements);
00634             }
00635             disableStencilTest();
00636             enableLighting();
00637             m_renderZ_objects_forced.clear();
00638         }
00639 
00640         // now we gonna need color values
00641         glEnableClientState(GL_COLOR_ARRAY);
00642 
00643         // 3) full opacity and (semi)transparent colored overlays
00644         if (!m_render_objects2T.empty()) {
00645             static const uint32_t stride = sizeof(RenderZData2T);
00646 
00647             glActiveTexture(GL_TEXTURE1);
00648             glEnable(GL_TEXTURE_2D);
00649             glActiveTexture(GL_TEXTURE0);
00650 
00651             glVertexPointer(3, GL_FLOAT, stride, &m_render_datas2T[0].vertex);
00652             glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_datas2T[0].color);
00653 
00654             glClientActiveTexture(GL_TEXTURE1);
00655             glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas2T[0].texel2);
00656             glClientActiveTexture(GL_TEXTURE0);
00657             glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas2T[0].texel);
00658 
00659             // array index
00660             GLint index = 0;
00661             // elements to render
00662             GLsizei elements = 0;
00663             // texture id
00664             uint32_t texture_id = 0;
00665             // color of overlay
00666             uint8_t rgb[3] = {0};
00667 
00668             std::vector<RenderObject>::iterator iter = m_render_objects2T.begin();
00669             for (; iter != m_render_objects2T.end(); ++iter) {
00670                 if (iter->texture_id != texture_id || memcmp(rgb, iter->rgb, sizeof(uint8_t)*3)) {
00671                     if (elements > 0) {
00672                         glDrawArrays(GL_QUADS, index, elements);
00673                         index += elements;
00674                     }
00675 
00676                     setEnvironmentalColor(iter->rgb);
00677                     bindTexture(iter->texture_id);
00678                     texture_id = iter->texture_id;
00679                     elements = iter->size;;
00680                     memcpy(rgb, iter->rgb, sizeof(uint8_t)*3);
00681                 } else {
00682                     elements += iter->size;
00683                 }
00684             }
00685             glDrawArrays(GL_QUADS, index, elements);
00686 
00687             glActiveTexture(GL_TEXTURE1);
00688             glDisable(GL_TEXTURE_2D);
00689             glActiveTexture(GL_TEXTURE0);
00690 
00691             m_render_objects2T.clear();
00692             m_render_datas2T.clear();
00693         }
00694 
00695         // we should stop using alpha test now
00696         disableAlphaTest();
00697 
00698         // 4) now render (semi)transparent data (they are already sorted by instancerenderer)
00699         if (!m_render_trans_objects.empty()) {
00700             static const uint32_t stride = sizeof(RenderZData2T);
00701 
00702             glVertexPointer(3, GL_FLOAT, stride, &m_render_trans_datas[0].vertex);
00703             glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_trans_datas[0].color);
00704             glClientActiveTexture(GL_TEXTURE0);
00705             glTexCoordPointer(2, GL_FLOAT, stride, &m_render_trans_datas[0].texel);
00706             
00707             // array index
00708             GLint index = 0;
00709             // elements to render
00710             GLsizei elements = 0;
00711             // texture id
00712             uint32_t texture_id = 0;
00713             // color of overlay
00714             GLfloat rgb[3] = {0};
00715 
00716             std::vector<RenderObject>::iterator iter = m_render_trans_objects.begin();
00717             for( ; iter != m_render_trans_objects.end(); ++iter) {
00718                 if (iter->texture_id != texture_id) {
00719                     if (elements > 0) {
00720                         glDrawArrays(GL_QUADS, index, elements);
00721                         index += elements;
00722                     }
00723 
00724                     bindTexture(iter->texture_id);
00725                     texture_id = iter->texture_id;
00726                     elements = iter->size;;
00727                 } else {
00728                     elements += iter->size;
00729                 }
00730             }
00731             glDrawArrays(GL_QUADS, index, elements);
00732 
00733             m_render_trans_datas.clear();
00734             m_render_trans_objects.clear();
00735         }
00736 
00737         disableTextures(0);
00738         disableDepthTest();
00739         disableLighting();
00740     }
00741 
00742     void RenderBackendOpenGLe::renderWithoutZ() {
00743         //bools to indicate changes
00744         bool type = false;
00745         bool texture = false;
00746         bool render = false;
00747         bool blending = false;
00748         bool stencil = false;
00749 
00750         static const uint32_t stride = sizeof(RenderData);
00751 
00752         glEnableClientState(GL_COLOR_ARRAY);
00753         glVertexPointer(2, GL_FLOAT, stride, &m_render_datas[0].vertex);
00754         glTexCoordPointer(2, GL_FLOAT, stride, &m_render_datas[0].texel);
00755         glColorPointer(4, GL_UNSIGNED_BYTE, stride, &m_render_datas[0].color);
00756 
00757         disableAlphaTest();
00758         disableDepthTest();
00759         disableTextures(0); 
00760 
00761         // array index
00762         int32_t index = 0;
00763         // elements to render
00764         uint32_t elements = 0;
00765         // render mode
00766         GLenum mode = GL_QUADS;
00767         // texture id
00768         uint32_t texture_id = 0;
00769         // src blending mode
00770         int32_t src = 4;
00771         // dst blending mode
00772         int32_t dst = 5;
00773 
00774         for(std::vector<RenderObject>::iterator iter = m_render_objects.begin(); iter != m_render_objects.end(); ++iter) {
00775             //first we look for changes
00776             if (iter->mode != mode) {
00777                 type = true;
00778                 render = true;
00779             }
00780             if (iter->texture_id != texture_id) {
00781                 texture = true;
00782                 render = true;
00783             }
00784             if (m_state.lightmodel != 0) {
00785                 if (iter->src != src || iter->dst != dst) {
00786                     blending = true;
00787                     render = true;
00788                 }
00789                 // Note that we don't need to check iter->light_enabled since only Instances can be lightened
00790                 if (iter->stencil_test != m_state.sten_enabled) {
00791                     stencil = true;
00792                     render = true;
00793                 }
00794                 if (iter->stencil_ref != m_state.sten_ref || 
00795                     iter->stencil_op != m_state.sten_op || 
00796                     iter->stencil_func != m_state.sten_func) {
00797                     stencil = true;
00798                     render = true;
00799                 }
00800             }
00801 
00802             // if no changes then we iterate to next element
00803             if (!render) {
00804                 elements += iter->size;
00805             // else we render everything so far
00806             } else {
00807                 if (elements > 0) {
00808                     //render
00809                     glDrawArrays(mode, index, elements);
00810                     index += elements;
00811                 }
00812                 // set element to current size
00813                 elements = iter->size;
00814 
00815                 // switch mode
00816                 if (type) {
00817                     mode = iter->mode;
00818                     type = false;
00819                 }
00820                 // switch texturing
00821                 if (texture) {
00822                     if (iter->texture_id != 0) {
00823                         enableTextures(0);
00824                         bindTexture(iter->texture_id);
00825                         texture_id = iter->texture_id;
00826                     } else {
00827                         disableTextures(0);
00828                         texture_id = 0;
00829                     }
00830                     texture = false;
00831                 }
00832                 // if lighting is enabled we have to consider a few more values
00833                 if (m_state.lightmodel != 0) {
00834                     // change blending
00835                     if (blending) {
00836                         src = iter->src;
00837                         dst = iter->dst;
00838                         changeBlending(src, dst);
00839                         blending = false;
00840                     }
00841                     // change stencil
00842                     if (stencil) {
00843                         if (iter->stencil_test) {
00844                             setStencilTest(iter->stencil_ref, iter->stencil_op, iter->stencil_func);
00845                             enableAlphaTest();
00846                         } else {
00847                             disableStencilTest();
00848                             disableAlphaTest();
00849                         }
00850                         stencil = false;
00851                     }
00852                 }
00853 
00854                 render = false;
00855             }
00856         }
00857         // render
00858         glDrawArrays(mode, index, elements);
00859 
00860         changeBlending(4, 5);
00861         disableStencilTest();
00862         disableTextures(0);
00863 
00864         //reset all states
00865         glDisableClientState(GL_COLOR_ARRAY);
00866 
00867         m_render_objects.clear();
00868         m_render_datas.clear();
00869     }
00870 
00871     bool RenderBackendOpenGLe::putPixel(int32_t x, int32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00872         if ((x < 0) || (x >= (int32_t)m_target->w) ||
00873             (y < 0) || (y >= (int32_t)m_target->h)) {
00874             return false;
00875         }
00876         RenderData rd;
00877         rd.vertex[0] = static_cast<float>(x);
00878         rd.vertex[1] = static_cast<float>(y);
00879         rd.color[0] = r;
00880         rd.color[1] = g;
00881         rd.color[2] = b;
00882         rd.color[3] = a;
00883         m_render_datas.push_back(rd);
00884 
00885         RenderObject ro(GL_POINTS, 1);
00886         m_render_objects.push_back(ro);
00887 
00888         return true;
00889     }
00890 
00891     void RenderBackendOpenGLe::drawLine(const Point& p1, const Point& p2, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00892         RenderData rd;
00893         rd.vertex[0] = static_cast<float>(p1.x);
00894         rd.vertex[1] = static_cast<float>(p1.y);
00895         rd.color[0] = r;
00896         rd.color[1] = g;
00897         rd.color[2] = b;
00898         rd.color[3] = a;
00899         m_render_datas.push_back(rd);
00900         
00901         rd.vertex[0] = static_cast<float>(p2.x);
00902         rd.vertex[1] = static_cast<float>(p2.y);
00903         m_render_datas.push_back(rd);
00904 
00905         RenderObject ro(GL_LINES, 2);
00906         m_render_objects.push_back(ro);
00907     }
00908 
00909     void RenderBackendOpenGLe::drawTriangle(const Point& p1, const Point& p2, const Point& p3, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00910         RenderData rd;
00911         rd.vertex[0] = static_cast<float>(p1.x);
00912         rd.vertex[1] = static_cast<float>(p1.y);
00913         rd.color[0] = r;
00914         rd.color[1] = g;
00915         rd.color[2] = b;
00916         rd.color[3] = a;
00917         m_render_datas.push_back(rd);
00918 
00919         rd.vertex[0] = static_cast<float>(p2.x);
00920         rd.vertex[1] = static_cast<float>(p2.y);
00921         m_render_datas.push_back(rd);
00922 
00923         rd.vertex[0] = static_cast<float>(p3.x);
00924         rd.vertex[1] = static_cast<float>(p3.y);
00925         m_render_datas.push_back(rd);
00926 
00927         RenderObject ro(GL_TRIANGLES, 3);
00928         m_render_objects.push_back(ro);
00929     }
00930 
00931     void RenderBackendOpenGLe::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00932         RenderData rd;
00933         rd.vertex[0] = static_cast<float>(p.x);
00934         rd.vertex[1] = static_cast<float>(p.y);
00935         rd.color[0] = r;
00936         rd.color[1] = g;
00937         rd.color[2] = b;
00938         rd.color[3] = a;
00939         m_render_datas.push_back(rd);
00940         rd.vertex[0] = static_cast<float>(p.x+w);
00941         
00942         m_render_datas.push_back(rd);
00943         rd.vertex[1] = static_cast<float>(p.y+h);
00944         
00945         m_render_datas.push_back(rd);
00946         rd.vertex[0] = static_cast<float>(p.x);
00947         m_render_datas.push_back(rd);
00948 
00949         RenderObject ro(GL_LINE_LOOP, 4);
00950         m_render_objects.push_back(ro);
00951     }
00952 
00953     void RenderBackendOpenGLe::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00954         RenderData rd;
00955         rd.vertex[0] = static_cast<float>(p.x);
00956         rd.vertex[1] = static_cast<float>(p.y);
00957         rd.color[0] = r;
00958         rd.color[1] = g;
00959         rd.color[2] = b;
00960         rd.color[3] = a;
00961         m_render_datas.push_back(rd);
00962 
00963         rd.vertex[1] = static_cast<float>(p.y+h);
00964         m_render_datas.push_back(rd);
00965 
00966         rd.vertex[0] = static_cast<float>(p.x+w);
00967         m_render_datas.push_back(rd);
00968 
00969         rd.vertex[1] = static_cast<float>(p.y);
00970         m_render_datas.push_back(rd);
00971 
00972         RenderObject ro(GL_QUADS, 4);
00973         m_render_objects.push_back(ro);
00974     }
00975 
00976     void RenderBackendOpenGLe::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4,  uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00977         RenderData rd;
00978         rd.vertex[0] = static_cast<float>(p1.x);
00979         rd.vertex[1] = static_cast<float>(p1.y);
00980         rd.color[0] = r;
00981         rd.color[1] = g;
00982         rd.color[2] = b;
00983         rd.color[3] = a;
00984         m_render_datas.push_back(rd);
00985 
00986         rd.vertex[0] = static_cast<float>(p2.x);
00987         rd.vertex[1] = static_cast<float>(p2.y);
00988         m_render_datas.push_back(rd);
00989 
00990         rd.vertex[0] = static_cast<float>(p3.x);
00991         rd.vertex[1] = static_cast<float>(p3.y);
00992         m_render_datas.push_back(rd);
00993 
00994         rd.vertex[0] = static_cast<float>(p4.x);
00995         rd.vertex[1] = static_cast<float>(p4.y);
00996         m_render_datas.push_back(rd);
00997 
00998         RenderObject ro(GL_QUADS, 4);
00999         m_render_objects.push_back(ro);
01000     }
01001 
01002     void RenderBackendOpenGLe::drawVertex(const Point& p, const uint8_t size, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
01003         RenderData rd;
01004         rd.vertex[0] = static_cast<float>(p.x-size);
01005         rd.vertex[1] = static_cast<float>(p.y+size);
01006         rd.color[0] = r;
01007         rd.color[1] = g;
01008         rd.color[2] = b;
01009         rd.color[3] = a;
01010         m_render_datas.push_back(rd);
01011 
01012         rd.vertex[0] = static_cast<float>(p.x+size);
01013         m_render_datas.push_back(rd);
01014 
01015         rd.vertex[1] = static_cast<float>(p.y-size);
01016         m_render_datas.push_back(rd);
01017 
01018         rd.vertex[0] = static_cast<float>(p.x-size);
01019         m_render_datas.push_back(rd);
01020 
01021         RenderObject ro(GL_LINE_LOOP, 4);
01022         m_render_objects.push_back(ro);
01023     }
01024 
01025     void RenderBackendOpenGLe::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int32_t subdivisions,
01026         float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
01027         const float step = Mathf::twoPi()/subdivisions;
01028         RenderData rd;;
01029         for(float angle=0; angle<=Mathf::twoPi(); angle+=step){
01030             rd.vertex[0] = static_cast<float>(p.x);
01031             rd.vertex[1] = static_cast<float>(p.y);
01032             rd.color[0] = red;
01033             rd.color[1] = green;
01034             rd.color[2] = blue;
01035             rd.color[3] = intensity;
01036             m_render_datas.push_back(rd);
01037 
01038             rd.vertex[0] = radius*Mathf::Cos(angle+step)*xstretch + p.x;
01039             rd.vertex[1] = radius*Mathf::Sin(angle+step)*ystretch + p.y;
01040             rd.color[0] = 0;
01041             rd.color[1] = 0;
01042             rd.color[2] = 0;
01043             rd.color[3] = 255;
01044             m_render_datas.push_back(rd);
01045 
01046             rd.vertex[0] = radius*Mathf::Cos(angle)*xstretch + p.x;
01047             rd.vertex[1] = radius*Mathf::Sin(angle)*ystretch + p.y;
01048             m_render_datas.push_back(rd);
01049 
01050             RenderObject ro(GL_TRIANGLES, 3);
01051             m_render_objects.push_back(ro);
01052         }
01053     }
01054 
01055     void RenderBackendOpenGLe::addImageToArray(uint32_t id, const Rect& rect, float const* st, uint8_t alpha, uint8_t const* rgb) {
01056         RenderData rd;
01057         rd.vertex[0] = static_cast<float>(rect.x);
01058         rd.vertex[1] = static_cast<float>(rect.y);
01059         rd.texel[0] = st[0];
01060         rd.texel[1] = st[1];
01061         rd.color[0] = 255;
01062         rd.color[1] = 255;
01063         rd.color[2] = 255;
01064         rd.color[3] = alpha;
01065         m_render_datas.push_back(rd);
01066 
01067         rd.vertex[0] = static_cast<float>(rect.x);
01068         rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01069         rd.texel[1] = st[3];
01070         m_render_datas.push_back(rd);
01071 
01072         rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01073         rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01074         rd.texel[0] = st[2];
01075         m_render_datas.push_back(rd);
01076 
01077         rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01078         rd.vertex[1] = static_cast<float>(rect.y);
01079         rd.texel[1] = st[1];
01080         m_render_datas.push_back(rd);
01081 
01082         RenderObject ro(GL_QUADS, 4, id);
01083         m_render_objects.push_back(ro); 
01084     }
01085 
01086     RenderBackendOpenGLe::RenderZObject* RenderBackendOpenGLe::getRenderBufferObject(GLuint texture_id, bool forceNewBatch) {
01087         if (!forceNewBatch) {
01088             for (std::vector<RenderZObject>::iterator it = m_renderZ_objects.begin(); it != m_renderZ_objects.end(); ++it) {        
01089                 if (it->texture_id == texture_id) {
01090                     if (it->elements < it->max_size - 4) {
01091                         return &(*it);  
01092                     }
01093                 }
01094             }
01095         }
01096         static int last_forced = 0;
01097 
01098         // nothing was found (or we were forced to make new batch), we need to create new one
01099         RenderZObject obj;
01100         if (!m_renderZ_objects.empty()) {
01101             obj.index = m_renderZ_objects.back().index + m_renderZ_objects.back().max_size;
01102             obj.index += last_forced * 4;
01103         } else {
01104             obj.index = 0;
01105         }
01106         obj.texture_id = texture_id;
01107         obj.elements = 0;
01108         obj.max_size = forceNewBatch ? 4 : max_quads_per_texbatch * 4;
01109 
01110         if (!forceNewBatch) {
01111             last_forced = 0;
01112             m_renderZ_objects.push_back(obj);
01113             return &m_renderZ_objects.back();
01114         } else {
01115             ++last_forced;
01116             m_renderZ_objects_forced.push_back(obj);
01117             return &m_renderZ_objects_forced.back();
01118         }
01119     }
01120 
01121     void RenderBackendOpenGLe::addImageToArrayZ(uint32_t id, const Rect& rect, float vertexZ, float const* st, uint8_t alpha, bool forceNewBatch, uint8_t const* rgb) {
01122         if (alpha == 255) {
01123             if (rgb == NULL) {
01124                 // ordinary z-valued quad
01125                 RenderZObject* renderObj = getRenderBufferObject(id, forceNewBatch);
01126                 uint32_t offset = renderObj->index + renderObj->elements;
01127                 renderObj->elements += 4;
01128                 RenderZData* rd;
01129 
01130                 rd = &m_renderZ_datas[offset];
01131                 rd->vertex[0] = static_cast<float>(rect.x);
01132                 rd->vertex[1] = static_cast<float>(rect.y);
01133                 rd->vertex[2] = vertexZ;
01134                 rd->texel[0] = st[0];
01135                 rd->texel[1] = st[1];
01136 
01137                 ++rd;
01138                 rd->vertex[0] = static_cast<float>(rect.x);
01139                 rd->vertex[1] = static_cast<float>(rect.y+rect.h);
01140                 rd->vertex[2] = vertexZ;
01141                 rd->texel[0] = st[0];
01142                 rd->texel[1] = st[3];
01143 
01144                 ++rd;
01145                 rd->vertex[0] = static_cast<float>(rect.x+rect.w);
01146                 rd->vertex[1] = static_cast<float>(rect.y+rect.h);
01147                 rd->vertex[2] = vertexZ;
01148                 rd->texel[0] = st[2];
01149                 rd->texel[1] = st[3];
01150 
01151                 ++rd;
01152                 rd->vertex[0] = static_cast<float>(rect.x+rect.w);
01153                 rd->vertex[1] = static_cast<float>(rect.y);
01154                 rd->vertex[2] = vertexZ;
01155                 rd->texel[0] = st[2];
01156                 rd->texel[1] = st[1];
01157             } else {
01158                 // full opacity colored overlay
01159                 RenderZData2T rd;
01160                 rd.vertex[0] = static_cast<float>(rect.x);
01161                 rd.vertex[1] = static_cast<float>(rect.y);
01162                 rd.vertex[2] = vertexZ;
01163                 rd.texel[0] = st[0];
01164                 rd.texel[1] = st[1];
01165                 rd.texel2[0] = 0.0;
01166                 rd.texel2[1] = 0.0;
01167                 rd.color[0] = 255;
01168                 rd.color[1] = 255;
01169                 rd.color[2] = 255;
01170                 rd.color[3] = 255;
01171                 m_render_datas2T.push_back(rd);
01172 
01173                 rd.vertex[0] = static_cast<float>(rect.x);
01174                 rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01175                 rd.texel[1] = st[3];
01176                 rd.texel2[1] = 1.0;
01177                 m_render_datas2T.push_back(rd);
01178 
01179                 rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01180                 rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01181                 rd.texel[0] = st[2];
01182                 rd.texel2[0] = 1.0;
01183                 m_render_datas2T.push_back(rd);
01184 
01185                 rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01186                 rd.vertex[1] = static_cast<float>(rect.y);
01187                 rd.texel[1] = st[1];
01188                 rd.texel2[1] = 0.0;
01189                 m_render_datas2T.push_back(rd);
01190 
01191                 RenderObject ro(GL_QUADS, 4, id);
01192                 ro.rgb[0] = rgb[0];
01193                 ro.rgb[1] = rgb[1];
01194                 ro.rgb[2] = rgb[2];
01195                 m_render_objects2T.push_back(ro);
01196             }
01197         } else {
01198             RenderZData2T rd;
01199             rd.vertex[0] = static_cast<float>(rect.x);
01200             rd.vertex[1] = static_cast<float>(rect.y);
01201             rd.vertex[2] = vertexZ;
01202             rd.texel[0] = st[0];
01203             rd.texel[1] = st[1];
01204             rd.color[0] = 255;
01205             rd.color[1] = 255;
01206             rd.color[2] = 255;
01207             rd.color[3] = alpha;
01208             m_render_trans_datas.push_back(rd);
01209 
01210             rd.vertex[0] = static_cast<float>(rect.x);
01211             rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01212             rd.texel[1] = st[3];
01213             m_render_trans_datas.push_back(rd);
01214 
01215             rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01216             rd.vertex[1] = static_cast<float>(rect.y+rect.h);
01217             rd.texel[0] = st[2];
01218             m_render_trans_datas.push_back(rd);
01219 
01220             rd.vertex[0] = static_cast<float>(rect.x+rect.w);
01221             rd.vertex[1] = static_cast<float>(rect.y);
01222             rd.texel[1] = st[1];
01223             m_render_trans_datas.push_back(rd);
01224 
01225             RenderObject ro(GL_QUADS, 4, id);
01226             if (rgb != NULL) {
01227                 RenderObject ro(GL_QUADS, 4, id);
01228                 ro.rgb[0] = rgb[0];
01229                 ro.rgb[1] = rgb[1];
01230                 ro.rgb[2] = rgb[2];
01231             }
01232             m_render_trans_objects.push_back(ro);
01233 
01234         }
01235     }
01236 
01237     void RenderBackendOpenGLe::prepareForOverlays() {
01238         glActiveTexture(GL_TEXTURE1);
01239         glEnable(GL_TEXTURE_2D);
01240 
01241         if(m_mask_overlays == 0) {
01242             // Constant texture - can be constant across every tilesets
01243             glGenTextures(1, &m_mask_overlays);
01244 
01245             uint8_t dummydata[3] = {127, 127, 127};
01246             glBindTexture(GL_TEXTURE_2D, m_mask_overlays);
01247             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01248             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01249             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
01250             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
01251             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0,
01252                 GL_RGB, GL_UNSIGNED_BYTE, dummydata);
01253         } else {
01254             glBindTexture(GL_TEXTURE_2D, m_mask_overlays);
01255         }
01256 
01257         m_state.texture[1] = m_mask_overlays;
01258 
01259         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
01260         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
01261         glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); 
01262 
01263         // Arg0
01264         glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
01265         glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
01266         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
01267         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); 
01268 
01269         // The alpha component is taken only from 0th tex unit which is 
01270         // Arg0 in our case, therefore we doesn't need to set operands
01271         // and sources for the rest of arguments
01272 
01273         // Arg1
01274         glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
01275         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
01276 
01277         // Arg2
01278         glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE1);
01279         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
01280 
01281         // Return to normal sampling mode
01282         glActiveTexture(GL_TEXTURE1);
01283         glDisable(GL_TEXTURE_2D);
01284         glActiveTexture(GL_TEXTURE0);
01285 
01286         // For now it's unneecessary - Only needed if we intend to use the 2nd texture unit in different case
01287         //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
01288     }
01289 
01290     void RenderBackendOpenGLe::captureScreen(const std::string& filename) {
01291         const uint32_t swidth = getWidth();
01292         const uint32_t sheight = getHeight();
01293 
01294         uint8_t *pixels;
01295         SDL_Surface *surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24,
01296             RMASK, GMASK, BMASK, NULLMASK);
01297 
01298         if (!surface) {
01299             return;
01300         }
01301 
01302         SDL_LockSurface(surface);
01303         pixels = new uint8_t[swidth * sheight * 3];
01304         glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
01305         uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
01306         // Copy the "reversed_image" memory to the "image" memory
01307         for (int32_t y = (sheight - 1); y >= 0; --y) {
01308             uint8_t *rowbegin = pixels + y * swidth * 3;
01309             uint8_t *rowend = rowbegin + swidth * 3;
01310 
01311             std::copy(rowbegin, rowend, imagepixels);
01312 
01313             // Advance a row in the output surface.
01314             imagepixels += surface->pitch;
01315         }
01316 
01317         SDL_UnlockSurface(surface);
01318         Image::saveAsPng(filename, *surface);
01319         
01320         SDL_FreeSurface(surface);
01321         delete[] pixels;
01322     }
01323 
01324     void RenderBackendOpenGLe::captureScreen(const std::string& filename, uint32_t width, uint32_t height) {
01325         const uint32_t swidth = getWidth();
01326         const uint32_t sheight = getHeight();
01327         const bool same_size = (width == swidth && height == sheight);
01328 
01329         if (width < 1 || height < 1) {
01330             return;
01331         }
01332 
01333         if (same_size) {
01334             captureScreen(filename);
01335             return;
01336         }
01337 
01338         uint8_t *pixels;
01339         // create source surface
01340         SDL_Surface* src = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 32,
01341             RMASK, GMASK, BMASK, AMASK);
01342 
01343         if (!src) {
01344             return;
01345         }
01346 
01347         if (SDL_MUSTLOCK(src)) {
01348             SDL_LockSurface(src);
01349         }
01350         pixels = new uint8_t[swidth * sheight * 4];
01351         glReadPixels(0, 0, swidth, sheight, GL_RGBA, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
01352 
01353         uint8_t* imagepixels = reinterpret_cast<uint8_t*>(src->pixels);
01354         // Copy the "reversed_image" memory to the "image" memory
01355         for (int32_t y = (sheight - 1); y >= 0; --y) {
01356             uint8_t *rowbegin = pixels + y * swidth * 4;
01357             uint8_t *rowend = rowbegin + swidth * 4;
01358 
01359             std::copy(rowbegin, rowend, imagepixels);
01360 
01361             // Advance a row in the output surface.
01362             imagepixels += src->pitch;
01363         }
01364 
01365         // create destination surface
01366         SDL_Surface* dst = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,
01367             RMASK, GMASK, BMASK, AMASK);
01368 
01369         uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
01370         uint32_t* src_help_pointer = src_pointer;
01371         uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
01372 
01373         int32_t x, y, *sx_ca, *sy_ca;
01374         int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
01375         int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
01376         int32_t sx_c = 0;
01377         int32_t sy_c = 0;
01378 
01379         // Allocates memory and calculates row wide&height
01380         int32_t* sx_a = new int32_t[dst->w + 1];
01381         sx_ca = sx_a;
01382         for (x = 0; x <= dst->w; x++) {
01383             *sx_ca = sx_c;
01384             sx_ca++;
01385             sx_c &= 0xffff;
01386             sx_c += sx;
01387         }
01388 
01389         int32_t* sy_a = new int32_t[dst->h + 1];
01390         sy_ca = sy_a;
01391         for (y = 0; y <= dst->h; y++) {
01392             *sy_ca = sy_c;
01393             sy_ca++;
01394             sy_c &= 0xffff;
01395             sy_c += sy;
01396         }
01397         sy_ca = sy_a;
01398 
01399         // Transfers the image data
01400 
01401         if (SDL_MUSTLOCK(dst)) {
01402             SDL_LockSurface(dst);
01403         }
01404 
01405         for (y = 0; y < dst->h; y++) {
01406             src_pointer = src_help_pointer;
01407             sx_ca = sx_a;
01408             for (x = 0; x < dst->w; x++) {
01409                 *dst_pointer = *src_pointer;
01410                 sx_ca++;
01411                 src_pointer += (*sx_ca >> 16);
01412                 dst_pointer++;
01413             }
01414             sy_ca++;
01415             src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
01416         }
01417 
01418         if (SDL_MUSTLOCK(dst)) {
01419             SDL_UnlockSurface(dst);
01420         }
01421         if (SDL_MUSTLOCK(src)) {
01422             SDL_UnlockSurface(src);
01423         }
01424 
01425         Image::saveAsPng(filename, *dst);
01426 
01427         // Free memory
01428         SDL_FreeSurface(src);
01429         SDL_FreeSurface(dst);
01430         delete[] sx_a;
01431         delete[] sy_a;
01432         delete[] pixels;
01433     }
01434 
01435     void RenderBackendOpenGLe::setClipArea(const Rect& cliparea, bool clear) {
01436         glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
01437         if (clear) {
01438             if (m_isbackgroundcolor) {
01439                 float red = float(m_backgroundcolor.r/255.0);
01440                 float green = float(m_backgroundcolor.g/255.0);
01441                 float blue = float(m_backgroundcolor.b/255.0);
01442                 glClearColor(red, green, blue, 0.0);
01443                 m_isbackgroundcolor = false;
01444             }
01445             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01446         }
01447     }
01448 
01449     void RenderBackendOpenGLe::attachRenderTarget(ImagePtr& img, bool discard) {
01450         m_img_target = img;
01451         m_target_discard = discard;
01452 
01453         // to render on something, we need to make sure its loaded already in gpu memory
01454         m_img_target->forceLoadInternal();
01455         m_target = m_img_target->getSurface();
01456 
01457         GLeImage* glimage = static_cast<GLeImage*>(m_img_target.get());
01458 
01459         GLuint targetid = glimage->getTexId();
01460         uint32_t w = m_img_target->getWidth();
01461         uint32_t h = m_img_target->getHeight();
01462 
01463         // quick & dirty hack for attaching compressed texture
01464         if(glimage->isCompressed()) {
01465             bindTexture(targetid);
01466             GLubyte* pixels = new GLubyte[w*h*4];
01467             // here we get decompressed pixels
01468             glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
01469             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
01470             delete [] pixels;
01471             glimage->setCompressed(false);
01472         }
01473 
01474         // can we use fbo?
01475         if (GLEE_EXT_framebuffer_object && m_useframebuffer) {
01476             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo_id);
01477             glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
01478                 GL_TEXTURE_2D, targetid, 0);
01479         }
01480 
01481         glViewport(0, 0, w, h);
01482         glMatrixMode(GL_PROJECTION);
01483         glLoadIdentity();
01484         // invert top with bottom
01485         glOrtho(0, w, 0, h, -1, 1); 
01486         glMatrixMode(GL_MODELVIEW);
01487         // because of inversion 2 lines above we need to also invert culling faces
01488         glCullFace(GL_FRONT);
01489 
01490         if (m_target_discard) {
01491             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01492         } else if (!m_target_discard && (!GLEE_EXT_framebuffer_object || !m_useframebuffer)) {
01493             // if we wanna just add something to render target, we need to first render previous contents
01494             addImageToArray(targetid, m_img_target->getArea(), 
01495                 static_cast<GLeImage*>(m_img_target.get())->getTexCoords(), 255, 0);
01496             // flush it down
01497             renderWithoutZ();
01498         }
01499     }
01500 
01501     void RenderBackendOpenGLe::detachRenderTarget() {
01502         assert(m_target != m_screen);
01503 
01504         // flush down what we batched
01505         renderVertexArrays();
01506 
01507         if (GLEE_EXT_framebuffer_object && m_useframebuffer) {
01508             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
01509         } else {
01510             bindTexture(0, static_cast<GLeImage*>(m_img_target.get())->getTexId());
01511             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 
01512                 m_img_target->getWidth(), m_img_target->getHeight(), 0);
01513             glClear(GL_DEPTH_BUFFER_BIT);
01514         }
01515 
01516         m_target = m_screen;
01517         glViewport(0, 0, m_screen->w, m_screen->h);
01518         glMatrixMode(GL_PROJECTION);
01519         glLoadIdentity();
01520         glOrtho(0, m_screen->w, m_screen->h, 0, znear, zfar);
01521         glMatrixMode(GL_MODELVIEW);
01522         glCullFace(GL_BACK); 
01523     }
01524 }