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