00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <cassert>
00024
00025
00026
00027
00028
00029
00030
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 resetGlimage();
00042 }
00043
00044 GLImage::GLImage(const uint8_t* data, unsigned int width, unsigned int height):
00045 Image(data, width, height) {
00046 resetGlimage();
00047 }
00048
00049 GLImage::~GLImage() {
00050
00051 m_sdlimage->detachSurface();
00052 delete m_sdlimage;
00053 cleanup();
00054 }
00055
00056 void GLImage::resetGlimage() {
00057 m_last_col_fill_ratio = 0;
00058 m_last_row_fill_ratio = 0;
00059 m_textureids = NULL;
00060 m_rows = 0;
00061 m_cols = 0;
00062 m_last_col_width = 0;
00063 m_last_row_height = 0;
00064 m_chunk_size = RenderBackend::instance()->getChunkingSize();
00065 m_colorkey = RenderBackend::instance()->getColorKey();
00066 }
00067
00068 void GLImage::cleanup() {
00069 for (unsigned int i = 0; i < m_rows*m_cols; ++i) {
00070 glDeleteTextures(1, &m_textureids[i]);
00071 }
00072 delete[] m_textureids;
00073 m_textureids = NULL;
00074 resetGlimage();
00075 }
00076
00077 void GLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
00078 if (!m_textureids) {
00079 generateTextureChunks();
00080 }
00081
00082 if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
00083 return;
00084 }
00085
00086 if (0 == alpha) {
00087 return;
00088 }
00089
00090
00091 float col_fill_ratio;
00092 float row_fill_ratio;
00093
00094
00095 float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
00096 float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
00097
00098
00099 Rect target;
00100
00101
00102
00103 Rect prev;
00104
00106 glColor4ub( 255, 255, 255, alpha );
00107
00108 glEnable(GL_TEXTURE_2D);
00109 for (unsigned int i = 0; i < m_cols; ++i) {
00110 if (i == m_cols-1) {
00111 col_fill_ratio = m_last_col_fill_ratio;
00112 target.w = static_cast<int>(round(scale_y*m_last_col_width*m_last_col_fill_ratio));
00113 } else {
00114 col_fill_ratio = 1.0;
00115 target.w = static_cast<int>(round(scale_y*m_chunk_size));
00116 }
00117 if (i > 0) {
00118 target.x = prev.x + prev.w;
00119 } else {
00120 target.x = rect.x;
00121 }
00122
00123 for (unsigned int j = 0; j < m_rows; ++j) {
00124 if (j == m_rows-1) {
00125 row_fill_ratio = m_last_row_fill_ratio;
00126 target.h = static_cast<int>(round(scale_y*m_last_row_height*m_last_row_fill_ratio));
00127 } else {
00128 row_fill_ratio = 1.0;
00129 target.h = static_cast<int>(round(scale_y*m_chunk_size));
00130 }
00131 if (j > 0) {
00132 target.y = prev.y + prev.h;
00133 } else {
00134 target.y = rect.y;
00135 }
00136 prev = target;
00137
00138 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
00139 glBegin(GL_QUADS);
00140 glTexCoord2f(0.0f, 0.0f);
00141 glVertex2i(target.x, target.y);
00142
00143 glTexCoord2f(0.0f, row_fill_ratio);
00144 glVertex2i(target.x, target.y + target.h);
00145
00146 glTexCoord2f(col_fill_ratio, row_fill_ratio);
00147 glVertex2i(target.x + target.w, target.y + target.h);
00148
00149 glTexCoord2f(col_fill_ratio, 0.0f);
00150 glVertex2i(target.x + target.w, target.y);
00151 glEnd();
00152 }
00153 }
00154 glDisable(GL_TEXTURE_2D);
00155 }
00156
00157 void GLImage::generateTextureChunks() {
00158 const unsigned int width = m_surface->w;
00159 const unsigned int height = m_surface->h;
00160 uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
00161 int pitch = m_surface->pitch;
00162
00163 m_last_col_width = 1;
00164 m_cols = static_cast<int>(width/m_chunk_size);
00165 if (width%m_chunk_size) {
00166 ++m_cols;
00167 while(m_last_col_width < width%m_chunk_size) {
00168 m_last_col_width <<= 1;
00169 }
00170 } else {
00171 m_last_col_width = m_chunk_size;
00172 }
00173
00174 m_last_row_height = 1;
00175 m_rows = static_cast<int>(height/m_chunk_size);
00176 if (height%m_chunk_size) {
00177 ++m_rows;
00178 while(m_last_row_height < height%m_chunk_size) {
00179 m_last_row_height <<= 1;
00180 }
00181 } else {
00182 m_last_row_height = m_chunk_size;
00183 }
00184
00185 m_textureids = new GLuint[m_rows*m_cols];
00186 memset(m_textureids, 0x00, m_rows*m_cols*sizeof(GLuint));
00187
00188 if(width%m_chunk_size) {
00189 m_last_col_fill_ratio = static_cast<float>(width%m_chunk_size) / static_cast<float>(m_last_col_width);
00190 } else {
00191 m_last_col_fill_ratio = 1.0f;
00192 }
00193
00194 if (height%m_chunk_size) {
00195 m_last_row_fill_ratio = static_cast<float>(height%m_chunk_size) / static_cast<float>(m_last_row_height);
00196 } else {
00197 m_last_row_fill_ratio = 1.0f;
00198 }
00199
00200 unsigned int chunk_width;
00201 unsigned int chunk_height;
00202 unsigned int data_chunk_height;
00203 unsigned int data_chunk_width;
00204
00205 for (unsigned int i = 0; i < m_cols; ++i) {
00206 for (unsigned int j = 0; j < m_rows; ++j) {
00207 if (i==m_cols-1) {
00208 chunk_width = m_last_col_width;
00209 data_chunk_width = width%m_chunk_size;
00210 if(data_chunk_width == 0) {
00211 data_chunk_width = m_chunk_size;
00212 }
00213 } else {
00214 chunk_width = m_chunk_size;
00215 data_chunk_width = m_chunk_size;
00216 }
00217 if (j==m_rows-1) {
00218 chunk_height = m_last_row_height;
00219 data_chunk_height = height%m_chunk_size;
00220 if(data_chunk_height == 0) {
00221 data_chunk_height = m_chunk_size;
00222 }
00223 } else {
00224 chunk_height = m_chunk_size;
00225 data_chunk_height = m_chunk_size;
00226 }
00227
00228 uint32_t* oglbuffer = new uint32_t[chunk_width * chunk_height];
00229 memset(oglbuffer, 0x00, chunk_width*chunk_height*4);
00230
00231 for (unsigned int y = 0; y < data_chunk_height; ++y) {
00232 for (unsigned int x = 0; x < data_chunk_width; ++x) {
00233 unsigned int pos = (y + j*m_chunk_size)*pitch + (x + i*m_chunk_size) * 4;
00234
00235 uint8_t r = data[pos + 3];
00236 uint8_t g = data[pos + 2];
00237 uint8_t b = data[pos + 1];
00238 uint8_t a = data[pos + 0];
00239
00240 if (RenderBackend::instance()->isColorKeyEnabled()) {
00241
00242 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
00243 a = 0;
00244 }
00245 }
00246
00247 oglbuffer[(y*chunk_width) + x] = r | (g << 8) | (b << 16) | (a<<24);
00248 }
00249 }
00250
00251
00252 glGenTextures(1, &m_textureids[j*m_cols + i]);
00253
00254 glBindTexture(GL_TEXTURE_2D, m_textureids[j*m_cols + i]);
00255
00256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00258
00259 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, chunk_width, chunk_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
00260
00261 delete[] oglbuffer;
00262 }
00263 }
00264 }
00265
00266 void GLImage::saveImage(const std::string& filename) {
00267 const unsigned int swidth = getWidth();
00268 const unsigned int sheight = getHeight();
00269 Uint32 rmask, gmask, bmask, amask;
00270 SDL_Surface *surface = NULL;
00271 uint8_t *pixels;
00272
00273 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00274 rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff;
00275 #else
00276 rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000;
00277 #endif
00278
00279 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
00280 sheight, 24,
00281 rmask, gmask, bmask, 0);
00282
00283 if(surface == NULL) {
00284 return;
00285 }
00286
00287 SDL_LockSurface(surface);
00288 pixels = new uint8_t[swidth * sheight * 3];
00289 glReadPixels(0, 0, swidth, sheight, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
00290
00291 uint8_t *imagepixels = reinterpret_cast<uint8_t*>(surface->pixels);
00292
00293 for (int y = (sheight - 1); y >= 0; --y) {
00294 uint8_t *rowbegin = pixels + y * swidth * 3;
00295 uint8_t *rowend = rowbegin + swidth * 3;
00296
00297 std::copy(rowbegin, rowend, imagepixels);
00298
00299
00300 imagepixels += surface->pitch;
00301 }
00302
00303 SDL_UnlockSurface(surface);
00304 saveAsPng(filename, *surface);
00305 SDL_FreeSurface(surface);
00306 delete [] pixels;
00307
00308
00309 }
00310
00311 void GLImage::setClipArea(const Rect& cliparea, bool clear) {
00312 glScissor(cliparea.x, getHeight() - cliparea.y - cliparea.h, cliparea.w, cliparea.h);
00313 if (clear) {
00314 glClear(GL_COLOR_BUFFER_BIT);
00315 }
00316 }
00317
00318 bool GLImage::putPixel(int x, int y, int r, int g, int b) {
00319 cleanup();
00320 return m_sdlimage->putPixel(x, y, r, g, b);
00321 }
00322
00323 void GLImage::drawLine(const Point& p1, const Point& p2, int r, int g, int b) {
00324 cleanup();
00325 m_sdlimage->drawLine(p1, p2, r, g, b);
00326 }
00327
00328 void GLImage::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b) {
00329 cleanup();
00330 m_sdlimage->drawQuad(p1, p2, p3, p4, r, g, b);
00331 }
00332
00333 void GLImage::drawVertex(const Point& p, const uint8_t size, int r, int g, int b) {
00334 cleanup();
00335 m_sdlimage->drawVertex(p, size, r, g, b);
00336 }
00337 }