# HG changeset patch # User prock@33b003aa-7bff-0310-803a-e67f0ece8222 # Date 1285881895 0 # Node ID 853d252346719777eea9d4d7e79785cdbfcb6b89 # Parent f648bfbae5fea3ee56cbe15a23529a322b331170 * Moved the GLEnable and GLDisable structures from opengl_gui_graphics.cpp to fife_opengl.h as they may prove to be useful elsewhere. * Fixed the color mask definitions in fife_stdint.h * Added the nextPow2() function to calculate the nearest (greater) power of 2 * Removed a bunch of re-definitions of RGB masks * Modified GLImage to only generate one "texture chunk". I hope this makes better use of memory and speeds things up a hair * Made use of the GLEnable structure when clearing the screen diff -r f648bfbae5fe -r 853d25234671 engine/core/gui/base/opengl/opengl_gui_graphics.cpp --- a/engine/core/gui/base/opengl/opengl_gui_graphics.cpp Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/gui/base/opengl/opengl_gui_graphics.cpp Thu Sep 30 21:24:55 2010 +0000 @@ -33,47 +33,16 @@ #include "video/image.h" #include "gui/base/gui_image.h" #include "util/structures/rect.h" +#include "video/opengl/fife_opengl.h" #include "opengl_gui_graphics.h" namespace FIFE { - struct GLEnable { - GLenum m_flag; - GLboolean m_oldval; - GLEnable(GLenum flag) : m_flag(flag) { - glGetBooleanv(flag, &m_oldval); - if (!m_oldval) { - glEnable(flag); - } - } - ~GLEnable() { - if (!m_oldval) { - glDisable(m_flag); - } - } - }; - - struct GLDisable { - GLenum m_flag; - GLboolean m_oldval; - GLDisable(GLenum flag) : m_flag(flag) { - glGetBooleanv(flag, &m_oldval); - if (m_oldval) { - glDisable(flag); - } - } - ~GLDisable() { - if (m_oldval) { - glEnable(m_flag); - } - } - }; - OpenGLGuiGraphics::OpenGLGuiGraphics(ImagePool& pool): m_pool(pool) { mTarget = SDL_GetVideoSurface(); assert(mTarget); setTargetPlane(mTarget->w, mTarget->h); - + } void OpenGLGuiGraphics::drawImage(const gcn::Image* image, int srcX, int srcY, int dstX, int dstY, int width, int height) { diff -r f648bfbae5fe -r 853d25234671 engine/core/util/base/fife_stdint.h --- a/engine/core/util/base/fife_stdint.h Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/util/base/fife_stdint.h Thu Sep 30 21:24:55 2010 +0000 @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2005-2008 by the FIFE team * - * http://www.fifengine.de * + * Copyright (C) 2005-2010 by the FIFE team * + * http://www.fifengine.net * * This file is part of FIFE. * * * * FIFE is free software; you can redistribute it and/or * @@ -24,7 +24,7 @@ // Standard C++ library includes -// Platform specific includes +// Platform specific includes #if defined( WIN32 ) && defined( _MSC_VER ) #ifndef _SDL_H typedef signed __int8 int8_t; @@ -41,6 +41,7 @@ #endif // 3rd party library includes +#include // FIFE includes // These includes are split up in two parts, separated by one empty line @@ -49,7 +50,7 @@ // SDL masks for SDL_CreateRGBSurface namespace FIFE { -#if 1 // tried "SDL_BYTEORDER != SDL_BIG_ENDIAN" with SDL.h inclusion, however this doesn't seem not work +#if SDL_BYTEORDER == SDL_LIL_ENDIAN const int RMASK = 0xff000000; const int GMASK = 0x00ff0000; const int BMASK = 0x0000ff00; @@ -59,8 +60,8 @@ const int GMASK = 0x0000ff00; const int BMASK = 0x00ff0000; const int AMASK = 0xff000000; -#endif +#endif const int NULLMASK = 0x00000000; -} +} //FIFE #endif // FIFEINT_H diff -r f648bfbae5fe -r 853d25234671 engine/core/util/math/fife_math.h --- a/engine/core/util/math/fife_math.h Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/util/math/fife_math.h Thu Sep 30 21:24:55 2010 +0000 @@ -25,7 +25,7 @@ // Standard C++ library includes #include -// Platform specific includes +// Platform specific includes // 3rd party library includes @@ -38,7 +38,7 @@ // Sort out the missing round function in MSVC: #if defined( WIN32 ) && defined( _MSC_VER ) inline double round(const double x) { - return x < 0.0 ? ceil(x - 0.5) : floor(x + 0.5); + return x < 0.0 ? ceil(x - 0.5) : floor(x + 0.5); } #endif @@ -52,4 +52,16 @@ #endif +inline unsigned nextPow2(unsigned x) +{ + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} + + #endif // FIFE_UTIL_FIFE_MATH_H diff -r f648bfbae5fe -r 853d25234671 engine/core/video/image.cpp --- a/engine/core/video/image.cpp Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/image.cpp Thu Sep 30 21:24:55 2010 +0000 @@ -178,13 +178,6 @@ png_infop infoptr; int colortype; png_bytep *rowpointers = NULL; - Uint32 rmask, gmask, bmask, amask; - //get endian - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; - #else - rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; - #endif fp = fopen(filename.c_str(), "wb"); diff -r f648bfbae5fe -r 853d25234671 engine/core/video/opengl/fife_opengl.h --- a/engine/core/video/opengl/fife_opengl.h Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/opengl/fife_opengl.h Thu Sep 30 21:24:55 2010 +0000 @@ -59,4 +59,41 @@ // First block: files included from the FIFE root src directory // Second block: files included from the same folder +namespace FIFE { + + struct GLEnable { + GLenum m_flag; + GLboolean m_oldval; + GLEnable(GLenum flag) : m_flag(flag) { + glGetBooleanv(flag, &m_oldval); + if (!m_oldval) { + glEnable(flag); + } + } + ~GLEnable() { + if (!m_oldval) { + glDisable(m_flag); + } + } + }; + + struct GLDisable { + GLenum m_flag; + GLboolean m_oldval; + GLDisable(GLenum flag) : m_flag(flag) { + glGetBooleanv(flag, &m_oldval); + if (m_oldval) { + glDisable(flag); + } + } + ~GLDisable() { + if (m_oldval) { + glEnable(m_flag); + } + } + }; + + +} //FIFE + #endif diff -r f648bfbae5fe -r 853d25234671 engine/core/video/opengl/glimage.cpp --- a/engine/core/video/opengl/glimage.cpp Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/opengl/glimage.cpp Thu Sep 30 21:24:55 2010 +0000 @@ -21,7 +21,7 @@ // Standard C++ library includes #include - +#include // 3rd party library includes // FIFE includes @@ -38,11 +38,17 @@ GLImage::GLImage(SDL_Surface* surface): Image(surface) { m_sdlimage = new SDLImage(surface); + + m_textureids = NULL; + resetGlimage(); } GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height): Image(data, width, height) { + + m_textureids = NULL; + resetGlimage(); } @@ -50,235 +56,157 @@ // remove surface so that deletion happens correctly (by base class destructor) m_sdlimage->detachSurface(); delete m_sdlimage; + cleanup(); } void GLImage::resetGlimage() { - m_last_col_fill_ratio = 0; - m_last_row_fill_ratio = 0; - m_textureids = NULL; - m_rows = 0; - m_cols = 0; - m_last_col_width = 0; - m_last_row_height = 0; - m_chunk_size = RenderBackend::instance()->getChunkingSize(); + cleanup(); + + m_chunk_size = 0; m_colorkey = RenderBackend::instance()->getColorKey(); } void GLImage::cleanup() { - for (unsigned int i = 0; i < m_rows*m_cols; ++i) { - glDeleteTextures(1, &m_textureids[i]); + if (m_textureids) { + glDeleteTextures(1, &m_textureids[0]); + + delete[] m_textureids; + m_textureids = NULL; } - delete[] m_textureids; - m_textureids = NULL; - resetGlimage(); + + m_col_tex_coord = 0; + m_row_tex_coord = 0; } void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) { if (!m_textureids) { - generateTextureChunks(); + generateGLTexture(); } + //not on the screen. dont render if (rect.right() < 0 || rect.x > static_cast(screen->w) || rect.bottom() < 0 || rect.y > static_cast(screen->h)) { return; } + //completely transparent so dont bother rendering if (0 == alpha) { return; } - // used to calculate the fill ratio for given chunk - float col_fill_ratio; - float row_fill_ratio; - // the amount of "zooming" for the image float scale_x = static_cast(rect.w) / static_cast(m_surface->w); float scale_y = static_cast(rect.h) / static_cast(m_surface->h); - // rectangle used for drawing - Rect target; - // zooming causes scaling sometimes to round pixels incorrectly. Instead of - // recalculating it all, store the values from previous round and calculate - // new x & y - Rect prev; + // apply the scale to the width and height of the image + uint16_t w = static_cast(round(scale_x*m_surface->w)); + uint16_t h = static_cast(round(scale_y*m_surface->h)); /// setting transparency for the whole primitive: glColor4ub( 255, 255, 255, alpha ); - glEnable(GL_TEXTURE_2D); - for (unsigned int i = 0; i < m_cols; ++i) { - if (i == m_cols-1) { - col_fill_ratio = m_last_col_fill_ratio; - target.w = static_cast(round(scale_x*m_last_col_width*m_last_col_fill_ratio)); - } else { - col_fill_ratio = 1.0; - target.w = static_cast(round(scale_x*m_chunk_size)); - } - if (i > 0) { - target.x = prev.x + prev.w; - } else { - target.x = rect.x; - } + GLEnable flag(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_textureids[0]); + + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); + glVertex2i(rect.x, rect.y); - for (unsigned int j = 0; j < m_rows; ++j) { - if (j == m_rows-1) { - row_fill_ratio = m_last_row_fill_ratio; - target.h = static_cast(round(scale_y*m_last_row_height*m_last_row_fill_ratio)); - } else { - row_fill_ratio = 1.0; - target.h = static_cast(round(scale_y*m_chunk_size)); - } - if (j > 0) { - target.y = prev.y + prev.h; - } else { - target.y = rect.y; - } - prev = target; + glTexCoord2f(0.0f, m_row_tex_coord); + glVertex2i(rect.x, rect.y + h); - glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]); - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); - glVertex2i(target.x, target.y); - - glTexCoord2f(0.0f, row_fill_ratio); - glVertex2i(target.x, target.y + target.h); + glTexCoord2f(m_col_tex_coord, m_row_tex_coord); + glVertex2i(rect.x + w, rect.y + h); - glTexCoord2f(col_fill_ratio, row_fill_ratio); - glVertex2i(target.x + target.w, target.y + target.h); + glTexCoord2f(m_col_tex_coord, 0.0f); + glVertex2i(rect.x + w, rect.y); + glEnd(); - glTexCoord2f(col_fill_ratio, 0.0f); - glVertex2i(target.x + target.w, target.y); - glEnd(); - } - } - glDisable(GL_TEXTURE_2D); } - void GLImage::generateTextureChunks() { + void GLImage::generateGLTexture() { const unsigned int width = m_surface->w; const unsigned int height = m_surface->h; + + uint32_t size; + + if (width > height){ + size = width; + } + else { + size = height; + } + + //calculate the nearest larger power of 2 + m_chunk_size = nextPow2(size); + + // used to calculate the fill ratio for given chunk + m_col_tex_coord = static_cast(m_surface->w%m_chunk_size) / static_cast(m_chunk_size); + m_row_tex_coord = static_cast(m_surface->h%m_chunk_size) / static_cast(m_chunk_size); + + if (m_col_tex_coord == 0.0f){ + m_col_tex_coord = 1.0f; + } + + if (m_row_tex_coord == 0.0f){ + m_row_tex_coord = 1.0f; + } + uint8_t* data = static_cast(m_surface->pixels); int pitch = m_surface->pitch; - m_last_col_width = 1; - m_cols = static_cast(width/m_chunk_size); - if (width%m_chunk_size) { - ++m_cols; - while(m_last_col_width < width%m_chunk_size) { - m_last_col_width <<= 1; - } - } else { - m_last_col_width = m_chunk_size; - } + + assert(!m_textureids); - m_last_row_height = 1; - m_rows = static_cast(height/m_chunk_size); - if (height%m_chunk_size) { - ++m_rows; - while(m_last_row_height < height%m_chunk_size) { - m_last_row_height <<= 1; - } - } else { - m_last_row_height = m_chunk_size; - } - - m_textureids = new GLuint[m_rows*m_cols]; - memset(m_textureids, 0x00, m_rows*m_cols*sizeof(GLuint)); + m_textureids = new GLuint[1]; + memset(m_textureids, 0x00, 1*sizeof(GLuint)); - if(width%m_chunk_size) { - m_last_col_fill_ratio = static_cast(width%m_chunk_size) / static_cast(m_last_col_width); - } else { // (width%m_chunk_size) / m_last_col_width == 0 == m_chunk_size (mod m_chunk_size) - m_last_col_fill_ratio = 1.0f; - } - if (height%m_chunk_size) { - m_last_row_fill_ratio = static_cast(height%m_chunk_size) / static_cast(m_last_row_height); - } else { - m_last_row_fill_ratio = 1.0f; - } - - unsigned int chunk_width; - unsigned int chunk_height; - unsigned int data_chunk_height; - unsigned int data_chunk_width; + uint32_t* oglbuffer = new uint32_t[m_chunk_size * m_chunk_size]; + memset(oglbuffer, 0x00, m_chunk_size*m_chunk_size*sizeof(uint32_t)); - for (unsigned int i = 0; i < m_cols; ++i) { - for (unsigned int j = 0; j < m_rows; ++j) { - if (i==m_cols-1) { - chunk_width = m_last_col_width; - data_chunk_width = width%m_chunk_size; - if(data_chunk_width == 0) { // 0 == m_chunk_size (mod m_chunk_size) - data_chunk_width = m_chunk_size; - } - } else { - chunk_width = m_chunk_size; - data_chunk_width = m_chunk_size; - } - if (j==m_rows-1) { - chunk_height = m_last_row_height; - data_chunk_height = height%m_chunk_size; - if(data_chunk_height == 0) { // 0 = m_chunk_size (mod m_chunk_size) - data_chunk_height = m_chunk_size; - } - } else { - chunk_height = m_chunk_size; - data_chunk_height = m_chunk_size; - } + for (unsigned int y = 0; y < height; ++y) { + for (unsigned int x = 0; x < width; ++x) { + unsigned int pos = (y * pitch) + (x * 4); - uint32_t* oglbuffer = new uint32_t[chunk_width * chunk_height]; - memset(oglbuffer, 0x00, chunk_width*chunk_height*4); - - for (unsigned int y = 0; y < data_chunk_height; ++y) { - for (unsigned int x = 0; x < data_chunk_width; ++x) { - unsigned int pos = (y + j*m_chunk_size)*pitch + (x + i*m_chunk_size) * 4; + uint8_t r = data[pos + 3]; + uint8_t g = data[pos + 2]; + uint8_t b = data[pos + 1]; + uint8_t a = data[pos + 0]; - uint8_t r = data[pos + 3]; - uint8_t g = data[pos + 2]; - uint8_t b = data[pos + 1]; - uint8_t a = data[pos + 0]; - - if (RenderBackend::instance()->isColorKeyEnabled()) { - // only set alpha to zero if colorkey feature is enabled - if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) { - a = 0; - } - } - - oglbuffer[(y*chunk_width) + x] = r | (g << 8) | (b << 16) | (a<<24); + if (RenderBackend::instance()->isColorKeyEnabled()) { + // only set alpha to zero if colorkey feature is enabled + if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) { + a = 0; } } - // get texture id from opengl - glGenTextures(1, &m_textureids[j*m_cols + i]); - // set focus on that texture - glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]); - // set filters for texture - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // transfer data from sdl buffer - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, chunk_width, chunk_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast(oglbuffer)); - - delete[] oglbuffer; + oglbuffer[(y*m_chunk_size) + x] = r | (g << 8) | (b << 16) | (a<<24); } } + + // get texture id from opengl + glGenTextures(1, &m_textureids[0]); + // set focus on that texture + glBindTexture(GL_TEXTURE_2D, m_textureids[0]); + // set filters for texture + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + // transfer data from sdl buffer + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_chunk_size, m_chunk_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast(oglbuffer)); + + delete[] oglbuffer; } void GLImage::saveImage(const std::string& filename) { const unsigned int swidth = getWidth(); const unsigned int sheight = getHeight(); - Uint32 rmask, gmask, bmask, amask; SDL_Surface *surface = NULL; uint8_t *pixels; - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; - #else - rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; - #endif - surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24, - rmask, gmask, bmask, 0); + RMASK,GMASK,BMASK, NULLMASK); if(surface == NULL) { return; @@ -304,12 +232,11 @@ saveAsPng(filename, *surface); SDL_FreeSurface(surface); delete [] pixels; - - } void GLImage::setClipArea(const Rect& cliparea, bool clear) { - glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h); + glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h); + if (clear) { glClear(GL_COLOR_BUFFER_BIT); } diff -r f648bfbae5fe -r 853d25234671 engine/core/video/opengl/glimage.h --- a/engine/core/video/opengl/glimage.h Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/opengl/glimage.h Thu Sep 30 21:24:55 2010 +0000 @@ -72,24 +72,10 @@ void setClipArea(const Rect& cliparea, bool clear); private: - // number of rows into which this image is sliced, so that it "becomes power of 2 compatible" - unsigned int m_rows; - // see m_rows - unsigned int m_cols; - - // ratio of texture fill in last column. E.g. in case image width = 300, chunk = 256x256, - // last column chunk width = 64 -> ratio is (300-256) / 64 = 0.6875 - // this means that texture fills 68.75% the last column - float m_last_col_fill_ratio; - // @see m_last_col_fill_ratio - float m_last_row_fill_ratio; - - /** the width of last column to render. This is also power of two - * (e.g. if chunks are 256x256 and image width = 300, last column = 64 - */ - unsigned int m_last_col_width; - // see m_last_col_width - unsigned int m_last_row_height; + // texture coords to use + float m_col_tex_coord; + // @see m_col_tex_coord + float m_row_tex_coord; /** Holds texture ids that are used to access textures in GL rendering context */ @@ -105,10 +91,9 @@ //void saveAsPng(const std::string& filename, SDL_Surface& surface); - /** Generates chunks for render. For reference, see - * http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_4.html + /** Generates the GL Texture for use when rendering. */ - void generateTextureChunks(); + void generateGLTexture(); /** Original SDLImage where GLImage is created from * FIXME: at the moment SDLImage is used to draw graphics (e.g. line) on screen diff -r f648bfbae5fe -r 853d25234671 engine/core/video/opengl/renderbackendopengl.cpp --- a/engine/core/video/opengl/renderbackendopengl.cpp Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/opengl/renderbackendopengl.cpp Thu Sep 30 21:24:55 2010 +0000 @@ -134,9 +134,8 @@ void RenderBackendOpenGL::startFrame() { if(m_clear) { - glDisable(GL_SCISSOR_TEST); + GLDisable flag(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_SCISSOR_TEST); } } @@ -211,7 +210,7 @@ void RenderBackendOpenGL::drawTriangle(const Point& p1, const Point& p2, const Point& p3, int r, int g, int b, int a) { glColor4ub(r, g, b, a); - + glBegin(GL_TRIANGLES); glVertex2f(p1.x, p1.y); glVertex2f(p2.x, p2.y); @@ -221,7 +220,7 @@ void RenderBackendOpenGL::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b, int a) { glColor4ub(r, g, b, a); - + glBegin(GL_QUADS); glVertex2f(p1.x, p1.y); glVertex2f(p2.x, p2.y); diff -r f648bfbae5fe -r 853d25234671 engine/core/video/sdl/sdlimage.cpp --- a/engine/core/video/sdl/sdlimage.cpp Wed Sep 29 15:15:45 2010 +0000 +++ b/engine/core/video/sdl/sdlimage.cpp Thu Sep 30 21:24:55 2010 +0000 @@ -284,16 +284,9 @@ // If source surface has no alpha channel then convert it if (src->format->Amask == 0) { - Uint32 rmask, gmask, bmask, amask; - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; - #else - rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; - #endif - zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, - rmask, gmask, - bmask, amask); + RMASK, GMASK, + BMASK, AMASK); SDL_BlitSurface(src, NULL, zoom_src, NULL); } else { zoom_src = src; @@ -789,18 +782,11 @@ if(m_surface) { const unsigned int swidth = getWidth(); const unsigned int sheight = getHeight(); - Uint32 rmask, gmask, bmask, amask; SDL_Surface *surface = NULL; - #if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; - #else - rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; - #endif - surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth, sheight, 24, - rmask, gmask, bmask, 0); + RMASK, GMASK, BMASK, 0); if(surface == NULL) { return;