FIFE 2008.0
glimage.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
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 #include <cassert>
00024 #include <iostream>
00025 // 3rd party library includes
00026 
00027 // FIFE includes
00028 // These includes are split up in two parts, separated by one empty line
00029 // First block: files included from the FIFE root src directory
00030 // Second block: files included from the same folder
00031 #include "util/structures/rect.h"
00032 #include "video/sdl/sdlimage.h"
00033 #include "video/renderbackend.h"
00034 
00035 #include "glimage.h"
00036 
00037 namespace FIFE {
00038     GLImage::GLImage(SDL_Surface* surface):
00039         Image(surface) {
00040         m_sdlimage = new SDLImage(surface);
00041 
00042         m_textureids = NULL;
00043 
00044         resetGlimage();
00045     }
00046 
00047     GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height):
00048         Image(data, width, height) {
00049         assert(m_surface);
00050         m_sdlimage = new SDLImage(m_surface);
00051 
00052         m_textureids = NULL;
00053 
00054         resetGlimage();
00055     }
00056 
00057     GLImage::~GLImage() {
00058         // remove surface so that deletion happens correctly (by base class destructor)
00059         m_sdlimage->detachSurface();
00060         delete m_sdlimage;
00061 
00062         cleanup();
00063     }
00064 
00065     void GLImage::invalidate() {
00066         resetGlimage();
00067     }
00068 
00069     void GLImage::resetGlimage() {
00070         cleanup();
00071 
00072         m_chunk_size_w = 0;
00073         m_chunk_size_h = 0;
00074 
00075         m_colorkey = RenderBackend::instance()->getColorKey();
00076     }
00077 
00078     void GLImage::cleanup() {
00079         if (m_textureids) {
00080             glDeleteTextures(1, &m_textureids[0]);
00081 
00082             delete[] m_textureids;
00083             m_textureids = NULL;
00084         }
00085 
00086         m_col_tex_coord = 0;
00087         m_row_tex_coord = 0;
00088     }
00089 
00090     void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
00091         if (!m_textureids) {
00092             generateGLTexture();
00093         }
00094 
00095         //not on the screen.  dont render
00096         if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
00097             return;
00098         }
00099 
00100         //completely transparent so dont bother rendering
00101         if (0 == alpha) {
00102             return;
00103         }
00104 
00105         // the amount of "zooming" for the image
00106         float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
00107         float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
00108 
00109         // apply the scale to the width and height of the image
00110         uint16_t w = static_cast<int>(round(scale_x*m_surface->w));
00111         uint16_t h = static_cast<int>(round(scale_y*m_surface->h));
00112 
00113         // setting transparency for the whole primitive:
00114         glColor4ub( 255, 255, 255, alpha );
00115 
00116         glEnable(GL_TEXTURE_2D);
00117         glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
00118 
00119         glBegin(GL_QUADS);
00120             glTexCoord2f(0.0f, 0.0f);
00121             glVertex2i(rect.x, rect.y);
00122 
00123             glTexCoord2f(0.0f, m_row_tex_coord);
00124             glVertex2i(rect.x, rect.y + h);
00125 
00126             glTexCoord2f(m_col_tex_coord, m_row_tex_coord);
00127             glVertex2i(rect.x + w, rect.y + h);
00128 
00129             glTexCoord2f(m_col_tex_coord, 0.0f);
00130             glVertex2i(rect.x + w, rect.y);
00131         glEnd();
00132         glDisable(GL_TEXTURE_2D);
00133 
00134     }
00135 
00136     void GLImage::generateGLTexture() {
00137         const unsigned int width = m_surface->w;
00138         const unsigned int height = m_surface->h;
00139 
00140         //calculate the nearest larger power of 2
00141         m_chunk_size_w = nextPow2(width);
00142         m_chunk_size_h = nextPow2(height);
00143 
00144         // used to calculate the fill ratio for given chunk
00145         m_col_tex_coord = static_cast<float>(m_surface->w%m_chunk_size_w) / static_cast<float>(m_chunk_size_w);
00146         m_row_tex_coord = static_cast<float>(m_surface->h%m_chunk_size_h) / static_cast<float>(m_chunk_size_h);
00147 
00148         if (m_col_tex_coord == 0.0f){
00149             m_col_tex_coord = 1.0f;
00150         }
00151 
00152         if (m_row_tex_coord == 0.0f){
00153             m_row_tex_coord = 1.0f;
00154         }
00155 
00156         uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
00157         int pitch = m_surface->pitch;
00158 
00159 
00160         assert(!m_textureids);
00161 
00162         m_textureids = new GLuint[1];
00163         memset(m_textureids, 0x00, 1*sizeof(GLuint));
00164 
00165 
00166         uint32_t* oglbuffer = new uint32_t[m_chunk_size_w * m_chunk_size_h];
00167         memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint32_t));
00168 
00169         for (unsigned int y = 0;  y < height; ++y) {
00170             for (unsigned int x = 0; x < width; ++x) {
00171                 unsigned int pos = (y * pitch) + (x * 4);
00172 
00173                 uint8_t r = data[pos + 3];
00174                 uint8_t g = data[pos + 2];
00175                 uint8_t b = data[pos + 1];
00176                 uint8_t a = data[pos + 0];
00177 
00178                 if (RenderBackend::instance()->isColorKeyEnabled()) {
00179                     // only set alpha to zero if colorkey feature is enabled
00180                     if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
00181                         a = 0;
00182                     }
00183                 }
00184 
00185                 oglbuffer[(y*m_chunk_size_w) + x] = r | (g << 8) | (b << 16) | (a<<24);
00186             }
00187         }
00188 
00189         // get texture id from opengl
00190         glGenTextures(1, &m_textureids[0]);
00191         // set focus on that texture
00192         glBindTexture(GL_TEXTURE_2D, m_textureids[0]);
00193         // set filters for texture
00194         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00195         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00196         // transfer data from sdl buffer
00197         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_chunk_size_w, m_chunk_size_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
00198 
00199         delete[] oglbuffer;
00200     }
00201 
00202     void GLImage::saveImage(const std::string& filename) {
00203         const unsigned int swidth = getWidth();
00204         const unsigned int sheight = getHeight();
00205         SDL_Surface *surface = NULL;
00206         uint8_t *pixels;
00207 
00208         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
00209             sheight, 24,
00210             RMASK,GMASK,BMASK, NULLMASK);
00211 
00212         if(surface == NULL) {
00213             return;
00214         }
00215 
00216         SDL_LockSurface(surface);
00217         pixels = new uint8_t[swidth * sheight * 3];
00218         glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
00219 
00220         uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
00221         // Copy the "reversed_image" memory to the "image" memory
00222         for (int y = (sheight - 1); y >= 0; --y) {
00223             uint8_t *rowbegin = pixels + y * swidth * 3;
00224             uint8_t *rowend = rowbegin + swidth * 3;
00225 
00226             std::copy(rowbegin, rowend, imagepixels);
00227 
00228             // Advance a row in the output surface.
00229             imagepixels += surface->pitch;
00230         }
00231 
00232         SDL_UnlockSurface(surface);
00233         saveAsPng(filename, *surface);
00234         SDL_FreeSurface(surface);
00235         delete [] pixels;
00236     }
00237 
00238     void GLImage::setClipArea(const Rect& cliparea, bool clear) {
00239         glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
00240 
00241         if (clear) {
00242             glClear(GL_COLOR_BUFFER_BIT);
00243         }
00244     }
00245 
00246     bool GLImage::putPixel(int x, int y, int r, int g, int b, int a) {
00247         cleanup();
00248         return m_sdlimage->putPixel(x, y, r, g, b, a);
00249     }
00250 
00251     void GLImage::drawLine(const Point& p1, const Point& p2, int r, int g, int b, int a) {
00252         cleanup();
00253         m_sdlimage->drawLine(p1, p2, r, g, b, a);
00254     }
00255 
00256     void GLImage::drawTriangle(const Point& p1, const Point& p2, const Point& p3, int r, int g, int b, int a) {
00257         cleanup();
00258         m_sdlimage->drawTriangle(p1, p2, p3, r, g, b, a);
00259     }
00260 
00261     void GLImage::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00262         cleanup();
00263         m_sdlimage->drawRectangle(p, w, h, r, g, b, a);
00264     }
00265 
00266     void GLImage::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00267         cleanup();
00268         m_sdlimage->fillRectangle(p, w, h, r, g, b, a);
00269     }
00270 
00271     void GLImage::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4,  int r, int g, int b, int a) {
00272         cleanup();
00273         m_sdlimage->drawQuad(p1, p2, p3, p4, r, g, b, a);
00274     }
00275 
00276     void GLImage::drawVertex(const Point& p, const uint8_t size, int r, int g, int b, int a) {
00277         cleanup();
00278         m_sdlimage->drawVertex(p, size, r, g, b, a);
00279     }
00280 
00281     void GLImage::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
00282         cleanup();
00283         m_sdlimage->drawLightPrimitive(p, intensity, radius, subdivisions, xstretch, ystretch, red, green, blue);
00284     }
00285 }
 All Classes Namespaces Functions Variables Enumerations Enumerator