scummvm/graphics/tinygl/texture.cpp

245 lines
5.4 KiB
C++
Raw Normal View History

2006-05-16 14:52:36 +00:00
// Texture Manager
2009-05-08 07:32:33 +00:00
#include "graphics/tinygl/zgl.h"
namespace TinyGL {
2006-05-16 14:52:36 +00:00
static GLTexture *find_texture(GLContext *c, int h) {
GLTexture *t;
2006-05-16 14:52:36 +00:00
t = c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
2008-09-10 11:16:57 +00:00
while (t) {
2006-05-16 14:52:36 +00:00
if (t->handle == h)
return t;
t = t->next;
}
return NULL;
}
2006-05-16 14:52:36 +00:00
static void free_texture(GLContext *c, int h) {
GLTexture *t, **ht;
GLImage *im;
int i;
t = find_texture(c, h);
2008-07-29 19:28:19 +00:00
if (!t->prev) {
2006-05-16 14:52:36 +00:00
ht = &c->shared_state.texture_hash_table[t->handle % TEXTURE_HASH_TABLE_SIZE];
*ht = t->next;
} else {
t->prev->next = t->next;
}
2008-07-29 19:28:19 +00:00
if (t->next)
2006-05-16 14:52:36 +00:00
t->next->prev = t->prev;
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
im = &t->images[i];
2008-09-10 11:16:57 +00:00
if (im->pixmap)
2006-05-16 14:52:36 +00:00
gl_free(im->pixmap);
}
gl_free(t);
}
2008-07-29 19:28:19 +00:00
GLTexture *alloc_texture(GLContext *c, int h) {
GLTexture *t, **ht;
2008-07-29 19:28:19 +00:00
t = (GLTexture *)gl_zalloc(sizeof(GLTexture));
2008-07-29 19:28:19 +00:00
ht = &c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
2008-07-29 19:28:19 +00:00
t->next = *ht;
t->prev = NULL;
if (t->next)
t->next->prev = t;
*ht = t;
2008-07-29 19:28:19 +00:00
t->handle = h;
2008-07-29 19:28:19 +00:00
return t;
}
2008-07-29 19:28:19 +00:00
void glInitTextures(GLContext *c) {
// textures
c->texture_2d_enabled = 0;
c->current_texture = find_texture(c, 0);
}
void glopBindTexture(GLContext *c, GLParam *p) {
2008-07-29 19:28:19 +00:00
int target = p[1].i;
int texture = p[2].i;
GLTexture *t;
2008-07-29 19:28:19 +00:00
assert(target == TGL_TEXTURE_2D && texture >= 0);
2008-07-29 19:28:19 +00:00
t = find_texture(c, texture);
if (!t) {
t = alloc_texture(c, texture);
}
c->current_texture = t;
}
void glopTexImage2D(GLContext *c, GLParam *p) {
int target = p[1].i;
int level = p[2].i;
int components = p[3].i;
int width = p[4].i;
int height = p[5].i;
int border = p[6].i;
int format = p[7].i;
int type = p[8].i;
void *pixels = p[9].p;
GLImage *im;
unsigned char *pixels1;
int do_free;
bool do_free_after_rgb2rgba = false;
// Simply unpack RGB into RGBA with 0 for Alpha.
// FIXME: This will need additional checks when we get around to adding 24/32-bit backend.
if (target == TGL_TEXTURE_2D && level == 0 && components == 3 && border == 0) {
if (format == TGL_RGB) {
unsigned char *temp = (unsigned char *)gl_malloc(width * height * 4);
unsigned char *pixPtr = (unsigned char*)pixels;
for (int i = 0; i < width * height * 4; i += 4) {
temp[i] = pixPtr[0];
temp[i + 1] = pixPtr[1];
temp[i + 2] = pixPtr[2];
temp[i + 3] = 255;
pixPtr += 3;
}
format = TGL_RGBA;
pixels = temp;
do_free_after_rgb2rgba = true;
} else if (format == TGL_BGR) {
unsigned char *temp = (unsigned char *)gl_malloc(width * height * 4);
unsigned char *pixPtr = (unsigned char*)pixels;
for (int i = 0; i < width * height * 4; i += 4) {
temp[i] = pixPtr[2];
temp[i + 1] = pixPtr[1];
temp[i + 2] = pixPtr[0];
temp[i + 3] = 255;
pixPtr += 3;
}
format = TGL_RGBA;
pixels = temp;
do_free_after_rgb2rgba = true;
}
} else if (!(target == TGL_TEXTURE_2D && level == 0 && components == 3 && border == 0
2008-07-29 19:28:19 +00:00
&& format == TGL_RGBA && type == TGL_UNSIGNED_BYTE)) {
error("glTexImage2D: combination of parameters not handled");
}
2008-07-29 19:28:19 +00:00
do_free = 0;
if (width != 256 || height != 256) {
pixels1 = (unsigned char *)gl_malloc(256 * 256 * 4);
// no interpolation is done here to respect the original image aliasing !
//gl_resizeImageNoInterpolate(pixels1, 256, 256, (unsigned char *)pixels, width, height);
// used interpolation anyway, it look much better :) --- aquadran
gl_resizeImage(pixels1, 256, 256, (unsigned char *)pixels, width, height);
do_free = 1;
width = 256;
height = 256;
2008-07-29 19:28:19 +00:00
} else {
pixels1 = (unsigned char *)pixels;
2008-07-29 19:28:19 +00:00
}
im = &c->current_texture->images[level];
im->xsize = width;
im->ysize = height;
if (im->pixmap)
gl_free(im->pixmap);
im->pixmap = gl_malloc(width * height * 3);
if (im->pixmap)
gl_convertRGB_to_5R6G5B8A((unsigned short *)im->pixmap, pixels1, width, height);
2008-07-29 19:28:19 +00:00
if (do_free)
gl_free(pixels1);
if (do_free_after_rgb2rgba)
gl_free(pixels);
}
2008-07-29 19:28:19 +00:00
// TODO: not all tests are done
void glopTexEnv(GLContext *, GLParam *p) {
2008-07-29 19:28:19 +00:00
int target = p[1].i;
int pname = p[2].i;
int param = p[3].i;
2008-07-29 19:28:19 +00:00
if (target != TGL_TEXTURE_ENV) {
error:
error("glTexParameter: unsupported option");
2008-07-29 19:28:19 +00:00
}
2008-07-29 19:28:19 +00:00
if (pname != TGL_TEXTURE_ENV_MODE)
goto error;
2008-07-29 19:28:19 +00:00
if (param != TGL_DECAL)
goto error;
}
2008-07-29 19:28:19 +00:00
// TODO: not all tests are done
void glopTexParameter(GLContext *, GLParam *p) {
2008-07-29 19:28:19 +00:00
int target = p[1].i;
int pname = p[2].i;
int param = p[3].i;
if (target != TGL_TEXTURE_2D) {
error:
error("glTexParameter: unsupported option");
2008-07-29 19:28:19 +00:00
}
switch (pname) {
case TGL_TEXTURE_WRAP_S:
case TGL_TEXTURE_WRAP_T:
if (param != TGL_REPEAT)
goto error;
break;
default:
;
}
}
void glopPixelStore(GLContext *, GLParam *p) {
2008-07-29 19:28:19 +00:00
int pname = p[1].i;
int param = p[2].i;
2008-07-29 19:28:19 +00:00
if (pname != TGL_UNPACK_ALIGNMENT || param != 1) {
error("glPixelStore: unsupported option");
2008-07-29 19:28:19 +00:00
}
}
} // end of namespace TinyGL
void tglGenTextures(int n, unsigned int *textures) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
int max, i;
TinyGL::GLTexture *t;
max = 0;
for (i = 0; i < TEXTURE_HASH_TABLE_SIZE; i++) {
t = c->shared_state.texture_hash_table[i];
while (t) {
if (t->handle > max)
max = t->handle;
t = t->next;
}
}
for (i = 0; i < n; i++) {
textures[i] = max + i + 1;
}
}
void tglDeleteTextures(int n, const unsigned int *textures) {
TinyGL::GLContext *c = TinyGL::gl_get_context();
int i;
TinyGL::GLTexture *t;
for (i = 0; i < n; i++) {
t = TinyGL::find_texture(c, textures[i]);
if (t) {
if (t == c->current_texture) {
tglBindTexture(TGL_TEXTURE_2D, 0);
}
TinyGL::free_texture(c, textures[i]);
}
}
}