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