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 #include <iostream>
00025
00026
00027
00028
00029
00030
00031 #include "util/structures/rect.h"
00032 #include "video/imagemanager.h"
00033 #include "video/sdl/sdlimage.h"
00034 #include "video/renderbackend.h"
00035 #include "video/opengl/renderbackendopengl.h"
00036
00037 #include "glimage.h"
00038
00039 namespace FIFE {
00040 GLImage::GLImage(IResourceLoader* loader):
00041 Image(loader),
00042 m_compressed(false),
00043 m_texId(0) {
00044
00045 resetGlimage();
00046 }
00047
00048 GLImage::GLImage(const std::string& name, IResourceLoader* loader):
00049 Image(name, loader),
00050 m_compressed(false),
00051 m_texId(0) {
00052
00053 resetGlimage();
00054 }
00055
00056 GLImage::GLImage(SDL_Surface* surface):
00057 Image(surface),
00058 m_compressed(false),
00059 m_texId(0) {
00060
00061 resetGlimage();
00062 }
00063
00064 GLImage::GLImage(const std::string& name, SDL_Surface* surface):
00065 Image(name, surface),
00066 m_compressed(false),
00067 m_texId(0) {
00068
00069 resetGlimage();
00070 }
00071
00072 GLImage::GLImage(const uint8_t* data, uint32_t width, uint32_t height):
00073 Image(data, width, height),
00074 m_compressed(false),
00075 m_texId(0) {
00076
00077 assert(m_surface);
00078 resetGlimage();
00079 }
00080
00081 GLImage::GLImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
00082 Image(name, data, width, height),
00083 m_compressed(false),
00084 m_texId(0) {
00085
00086 assert(m_surface);
00087 resetGlimage();
00088 }
00089
00090 GLImage::~GLImage() {
00091 cleanup();
00092 }
00093
00094 void GLImage::invalidate() {
00095 resetGlimage();
00096 }
00097
00098 void GLImage::setSurface(SDL_Surface* surface) {
00099 reset(surface);
00100 resetGlimage();
00101 }
00102
00103 void GLImage::resetGlimage() {
00104 cleanup();
00105
00106 m_chunk_size_w = 0;
00107 m_chunk_size_h = 0;
00108
00109 m_colorkey = RenderBackend::instance()->getColorKey();
00110 }
00111
00112 void GLImage::cleanup() {
00113 if (m_texId) {
00114 if(!m_shared) {
00115 glDeleteTextures(1, &m_texId);
00116 }
00117 m_texId = 0;
00118 m_compressed = false;
00119 }
00120
00121 m_tex_coords[0] = m_tex_coords[1] =
00122 m_tex_coords[2] = m_tex_coords[3] = 0.0f;
00123 }
00124
00125 void GLImage::render(const Rect& rect, uint8_t alpha, uint8_t const* rgb) {
00126
00127 if (0 == alpha) {
00128 return;
00129 }
00130 RenderBackend* rb = RenderBackend::instance();
00131 SDL_Surface* target = rb->getRenderTargetSurface();
00132 assert(target != m_surface);
00133
00134
00135 if (rect.right() < 0 || rect.x > static_cast<int32_t>(target->w) ||
00136 rect.bottom() < 0 || rect.y > static_cast<int32_t>(target->h)) {
00137 return;
00138 }
00139
00140 if (!m_texId) {
00141 generateGLTexture();
00142 } else if (m_shared) {
00143 validateShared();
00144 }
00145
00146 rb->addImageToArray(m_texId, rect, m_tex_coords, alpha, rgb);
00147 }
00148
00149 void GLImage::generateGLTexture() {
00150 if (m_shared) {
00151
00152 validateShared();
00153 return;
00154 }
00155
00156 const uint32_t width = m_surface->w;
00157 const uint32_t height = m_surface->h;
00158
00159
00160
00161 if(GLEE_ARB_texture_non_power_of_two && RenderBackend::instance()->isNPOTEnabled()) {
00162 m_chunk_size_w = width;
00163 m_chunk_size_h = height;
00164 }
00165 else {
00166
00167 m_chunk_size_w = nextPow2(width);
00168 m_chunk_size_h = nextPow2(height);
00169 }
00170
00171
00172 m_tex_coords[0] = m_tex_coords[1] = 0.0f;
00173 m_tex_coords[2] = static_cast<float>(m_surface->w%m_chunk_size_w) / static_cast<float>(m_chunk_size_w);
00174 m_tex_coords[3] = static_cast<float>(m_surface->h%m_chunk_size_h) / static_cast<float>(m_chunk_size_h);
00175
00176 if (m_tex_coords[2] == 0.0f){
00177 m_tex_coords[2] = 1.0f;
00178 }
00179
00180 if (m_tex_coords[3] == 0.0f){
00181 m_tex_coords[3] = 1.0f;
00182 }
00183
00184 uint8_t* data = static_cast<uint8_t*>(m_surface->pixels);
00185 int32_t pitch = m_surface->pitch;
00186
00187 assert(!m_texId);
00188
00189
00190 glGenTextures(1, &m_texId);
00191
00192 static_cast<RenderBackendOpenGL*>(RenderBackend::instance())->bindTexture(m_texId);
00193
00194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00196
00197 GLint internalFormat = GL_RGBA8;
00198 if(GLEE_ARB_texture_compression && RenderBackend::instance()->isImageCompressingEnabled()) {
00199 internalFormat = GL_COMPRESSED_RGBA;
00200 m_compressed = true;
00201 } else {
00202 m_compressed = false;
00203 }
00204
00205 SDL_Surface* target = RenderBackend::instance()->getRenderTargetSurface();
00206 int32_t bpp_target = target->format->BitsPerPixel;
00207 int32_t bpp_source = m_surface->format->BitsPerPixel;
00208
00209 if (bpp_target == 16 && bpp_source == 32) {
00210 uint16_t* oglbuffer = new uint16_t[m_chunk_size_w * m_chunk_size_h];
00211 memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint16_t));
00212
00213 for (uint32_t y = 0; y < height; ++y) {
00214 for (uint32_t x = 0; x < width; ++x) {
00215 uint32_t pos = (y * pitch) + (x * 4);
00216
00217 uint8_t r = data[pos + 0];
00218 uint8_t g = data[pos + 1];
00219 uint8_t b = data[pos + 2];
00220 uint8_t a = data[pos + 3];
00221
00222 if (RenderBackend::instance()->isColorKeyEnabled()) {
00223
00224 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
00225 a = 0;
00226 }
00227 }
00228
00229 oglbuffer[(y*m_chunk_size_w) + x] = ((r >> 4) << 12) |
00230 ((g >> 4) << 8) |
00231 ((b >> 4) << 4) |
00232 ((a >> 4) << 0);
00233 }
00234 }
00235
00236 if (!m_compressed) {
00237 internalFormat = GL_RGBA4;
00238 }
00239
00240
00241 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
00242 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, oglbuffer);
00243
00244 delete[] oglbuffer;
00245 return;
00246 }
00247
00248 if(GLEE_ARB_texture_non_power_of_two && RenderBackend::instance()->isNPOTEnabled()) {
00249 if(RenderBackend::instance()->isColorKeyEnabled()) {
00250 uint8_t* oglbuffer = new uint8_t[width * height * 4];
00251 memcpy(oglbuffer, data, width * height * 4 * sizeof(uint8_t));
00252
00253 for (uint32_t y = 0; y < height; ++y) {
00254 for (uint32_t x = 0; x < width * 4; x += 4) {
00255 uint32_t gid = x + y * width;
00256
00257 uint8_t r = oglbuffer[gid + 0];
00258 uint8_t g = oglbuffer[gid + 1];
00259 uint8_t b = oglbuffer[gid + 2];
00260 uint8_t a = oglbuffer[gid + 3];
00261
00262
00263 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
00264 oglbuffer[gid + 3] = 0;
00265 }
00266 }
00267 }
00268
00269
00270 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
00271 0, GL_RGBA, GL_UNSIGNED_BYTE, oglbuffer);
00272
00273 delete [] oglbuffer;
00274 } else {
00275
00276 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
00277 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
00278 }
00279
00280 } else {
00281 uint32_t* oglbuffer = new uint32_t[m_chunk_size_w * m_chunk_size_h];
00282 memset(oglbuffer, 0x00, m_chunk_size_w*m_chunk_size_h*sizeof(uint32_t));
00283
00284 for (uint32_t y = 0; y < height; ++y) {
00285 for (uint32_t x = 0; x < width; ++x) {
00286 uint32_t pos = (y * pitch) + (x * 4);
00287
00288 uint8_t a = data[pos + 3];
00289 uint8_t b = data[pos + 2];
00290 uint8_t g = data[pos + 1];
00291 uint8_t r = data[pos + 0];
00292
00293 if (RenderBackend::instance()->isColorKeyEnabled()) {
00294
00295 if (r == m_colorkey.r && g == m_colorkey.g && b == m_colorkey.b) {
00296 a = 0;
00297 }
00298 }
00299
00300 oglbuffer[(y*m_chunk_size_w) + x] = r | (g << 8) | (b << 16) | (a<<24);
00301 }
00302 }
00303
00304
00305 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_chunk_size_w, m_chunk_size_h,
00306 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(oglbuffer));
00307
00308 delete[] oglbuffer;
00309 }
00310 }
00311
00312 void GLImage::generateGLSharedTexture(const GLImage* shared, const Rect& region) {
00313 uint32_t width = shared->getWidth();
00314 uint32_t height = shared->getHeight();
00315
00316 if(!GLEE_ARB_texture_non_power_of_two || !RenderBackend::instance()->isNPOTEnabled()) {
00317 width = nextPow2(width);
00318 height = nextPow2(height);
00319 }
00320
00321 m_tex_coords[0] = static_cast<GLfloat>(region.x) / static_cast<GLfloat>(width);
00322 m_tex_coords[1] = static_cast<GLfloat>(region.y) / static_cast<GLfloat>(height);
00323 m_tex_coords[2] = static_cast<GLfloat>(region.x + region.w) / static_cast<GLfloat>(width);
00324 m_tex_coords[3] = static_cast<GLfloat>(region.y + region.h) / static_cast<GLfloat>(height);
00325 }
00326
00327 void GLImage::useSharedImage(const ImagePtr& shared, const Rect& region) {
00328 GLImage* img = static_cast<GLImage*>(shared.get());
00329
00330 m_shared_img = img;
00331 m_texId = img->m_texId;
00332 m_shared = true;
00333 m_subimagerect = region;
00334 m_atlas_img = shared;
00335 m_surface = m_shared_img->m_surface;
00336 m_compressed = m_shared_img->m_compressed;
00337 m_atlas_name = m_shared_img->getName();
00338
00339 if(m_texId) {
00340 generateGLSharedTexture(img, region);
00341 }
00342
00343 setState(IResource::RES_LOADED);
00344 }
00345
00346 void GLImage::forceLoadInternal() {
00347 if (m_texId == 0) {
00348 generateGLTexture();
00349 } else if (m_shared) {
00350 validateShared();
00351 }
00352 }
00353
00354 void GLImage::validateShared() {
00355
00356 if (m_shared_img->m_texId && m_shared_img->m_texId == m_texId) {
00357 return;
00358 }
00359
00360 if (m_shared_img->getState() == IResource::RES_NOT_LOADED) {
00361 m_shared_img->load();
00362 m_shared_img->generateGLTexture();
00363 }
00364
00365 m_texId = m_shared_img->m_texId;
00366 m_surface = m_shared_img->m_surface;
00367 m_compressed = m_shared_img->m_compressed;
00368 generateGLSharedTexture(m_shared_img, m_subimagerect);
00369 }
00370
00371 void GLImage::copySubimage(uint32_t xoffset, uint32_t yoffset, const ImagePtr& img) {
00372 Image::copySubimage(xoffset, yoffset, img);
00373
00374 if(m_texId) {
00375 static_cast<RenderBackendOpenGL*>(RenderBackend::instance())->bindTexture(m_texId);
00376 glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, img->getWidth(), img->getHeight(),
00377 GL_RGBA, GL_UNSIGNED_BYTE, img->getSurface()->pixels);
00378 }
00379 }
00380
00381 void GLImage::load() {
00382 if (m_shared) {
00383
00384
00385 if (!ImageManager::instance()->exists(m_atlas_name)) {
00386 ImagePtr newAtlas = ImageManager::instance()->create(m_atlas_name);
00387 GLImage* img = static_cast<GLImage*>(newAtlas.get());
00388 m_atlas_img = newAtlas;
00389 m_shared_img = img;
00390 }
00391
00392
00393 if (m_shared_img->m_surface != m_surface || m_texId != m_shared_img->m_texId) {
00394 m_texId = m_shared_img->m_texId;
00395 m_surface = m_shared_img->m_surface;
00396 m_compressed = m_shared_img->m_compressed;
00397 if (m_texId) {
00398 generateGLSharedTexture(m_shared_img, m_subimagerect);
00399 }
00400 }
00401 m_state = IResource::RES_LOADED;
00402 } else {
00403 Image::load();
00404 }
00405 }
00406
00407 void GLImage::free() {
00408 setSurface(NULL);
00409 m_state = IResource::RES_NOT_LOADED;
00410 }
00411
00412 GLuint GLImage::getTexId() const {
00413 return m_texId;
00414 }
00415
00416 const GLfloat* GLImage::getTexCoords() const {
00417 return m_tex_coords;
00418 }
00419 }