2014-08-13 18:52:52 +02:00
|
|
|
/* ResidualVM - A 3D game interpreter
|
|
|
|
*
|
|
|
|
* ResidualVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
|
|
|
|
* which is licensed under the zlib-license (see LICENSE).
|
|
|
|
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
|
|
|
*/
|
2006-05-16 14:52:36 +00:00
|
|
|
|
|
|
|
// Texture Manager
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2014-12-23 20:39:38 +01:00
|
|
|
#include "common/endian.h"
|
|
|
|
|
2009-05-08 07:32:33 +00:00
|
|
|
#include "graphics/tinygl/zgl.h"
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2017-04-29 16:42:01 +00:00
|
|
|
struct tglColorAssociation {
|
|
|
|
Graphics::PixelFormat pf;
|
|
|
|
TGLuint format;
|
|
|
|
TGLuint type;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct tglColorAssociation colorAssociationList[] = {
|
|
|
|
/*
|
|
|
|
* TGL_UNSIGNED_BYTE before other variants to provide OpenGLES-friendly formats
|
|
|
|
* when this table is used to look these up.
|
|
|
|
* Note: this does not matter at all for TinyGL, but this is to be consistent
|
|
|
|
* with future OpenGL equivalent for this code.
|
|
|
|
*/
|
|
|
|
// TODO: remove pixel endianness conversions from tinygl callers and enable
|
|
|
|
//#if defined(SCUMM_LITTLE_ENDIAN)
|
|
|
|
#if 1
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), TGL_RGBA, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), TGL_BGRA, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), TGL_RGB, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), TGL_BGR, TGL_UNSIGNED_BYTE},
|
|
|
|
#else
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), TGL_RGBA, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), TGL_BGRA, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), TGL_RGB, TGL_UNSIGNED_BYTE},
|
|
|
|
{Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), TGL_BGR, TGL_UNSIGNED_BYTE},
|
|
|
|
#endif
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), TGL_RGBA, TGL_UNSIGNED_INT_8_8_8_8_REV},
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), TGL_RGBA, TGL_UNSIGNED_INT_8_8_8_8},
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), TGL_BGRA, TGL_UNSIGNED_INT_8_8_8_8_REV},
|
|
|
|
{Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), TGL_BGRA, TGL_UNSIGNED_INT_8_8_8_8},
|
|
|
|
{Graphics::PixelFormat(2, 5, 5, 5, 1, 0, 5, 10, 15), TGL_RGBA, TGL_UNSIGNED_SHORT_1_5_5_5_REV},
|
|
|
|
{Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), TGL_RGBA, TGL_UNSIGNED_SHORT_5_5_5_1},
|
|
|
|
{Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15), TGL_BGRA, TGL_UNSIGNED_SHORT_1_5_5_5_REV},
|
|
|
|
{Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0), TGL_BGRA, TGL_UNSIGNED_SHORT_5_5_5_1},
|
|
|
|
{Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0), TGL_RGB, TGL_UNSIGNED_SHORT_5_6_5_REV},
|
|
|
|
{Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), TGL_BGR, TGL_UNSIGNED_SHORT_5_6_5},
|
|
|
|
{Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), TGL_BGR, TGL_UNSIGNED_SHORT_5_6_5_REV},
|
|
|
|
{Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0), TGL_RGB, TGL_UNSIGNED_SHORT_5_6_5}
|
|
|
|
};
|
|
|
|
#define COLOR_ASSOCIATION_LIST_LENGTH (sizeof(colorAssociationList) / sizeof(*colorAssociationList))
|
|
|
|
|
2009-05-25 13:19:29 +00:00
|
|
|
namespace TinyGL {
|
|
|
|
|
2016-07-17 13:25:23 +00:00
|
|
|
static GLTexture *find_texture(GLContext *c, unsigned int h) {
|
2006-05-16 14:52:36 +00:00
|
|
|
GLTexture *t;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
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;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2012-04-21 12:18:42 +02:00
|
|
|
void free_texture(GLContext *c, int h) {
|
2016-07-18 04:34:09 +02:00
|
|
|
free_texture(c, find_texture(c, h));
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_texture(GLContext *c, GLTexture *t) {
|
|
|
|
GLTexture **ht;
|
2006-05-16 14:52:36 +00:00
|
|
|
GLImage *im;
|
|
|
|
|
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;
|
|
|
|
|
2014-02-20 17:56:55 +01:00
|
|
|
for (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
|
2006-05-16 14:52:36 +00:00
|
|
|
im = &t->images[i];
|
2017-05-06 14:17:35 +00:00
|
|
|
if (im->pixmap) {
|
|
|
|
delete im->pixmap;
|
|
|
|
im->pixmap = nullptr;
|
|
|
|
}
|
2006-05-16 14:52:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gl_free(t);
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
GLTexture *alloc_texture(GLContext *c, int h) {
|
|
|
|
GLTexture *t, **ht;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
t = (GLTexture *)gl_zalloc(sizeof(GLTexture));
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
ht = &c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
t->next = *ht;
|
|
|
|
t->prev = NULL;
|
|
|
|
if (t->next)
|
|
|
|
t->next->prev = t;
|
|
|
|
*ht = t;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
t->handle = h;
|
2014-07-25 12:59:51 +02:00
|
|
|
t->disposed = false;
|
2014-08-02 21:42:25 +02:00
|
|
|
t->versionNumber = 0;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
return t;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2017-05-06 14:17:35 +00:00
|
|
|
c->texture_mag_filter = TGL_LINEAR;
|
|
|
|
c->texture_min_filter = TGL_NEAREST_MIPMAP_LINEAR;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2009-05-25 13:19:29 +00:00
|
|
|
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;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
assert(target == TGL_TEXTURE_2D && texture >= 0);
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
t = find_texture(c, texture);
|
|
|
|
if (!t) {
|
|
|
|
t = alloc_texture(c, texture);
|
|
|
|
}
|
|
|
|
c->current_texture = t;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2017-04-29 16:42:01 +00:00
|
|
|
static inline const Graphics::PixelFormat formatType2PixelFormat(TGLuint format, TGLuint type) {
|
|
|
|
for (unsigned int i = 0; i < COLOR_ASSOCIATION_LIST_LENGTH; i++) {
|
|
|
|
if (colorAssociationList[i].format == format &&
|
|
|
|
colorAssociationList[i].type == type)
|
|
|
|
return colorAssociationList[i].pf;
|
|
|
|
}
|
|
|
|
error("TinyGL texture: format 0x%04x and type 0x%04x combination not supported", format, type);
|
|
|
|
}
|
|
|
|
|
2009-05-25 13:19:29 +00:00
|
|
|
void glopTexImage2D(GLContext *c, GLParam *p) {
|
2008-07-13 21:03:12 +00:00
|
|
|
int target = p[1].i;
|
|
|
|
int level = p[2].i;
|
2017-04-29 10:09:10 +00:00
|
|
|
// "components" is guessed from "format".
|
|
|
|
// int components = p[3].i;
|
2008-07-13 21:03:12 +00:00
|
|
|
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;
|
2014-02-02 19:13:50 +01:00
|
|
|
byte *pixels = (byte *)p[9].p;
|
2008-07-13 21:03:12 +00:00
|
|
|
GLImage *im;
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2017-04-29 10:09:10 +00:00
|
|
|
if (target != TGL_TEXTURE_2D)
|
|
|
|
error("tglTexImage2D: target not handled");
|
|
|
|
if (level < 0 || level >= MAX_TEXTURE_LEVELS)
|
|
|
|
error("tglTexImage2D: invalid level");
|
|
|
|
if (border != 0)
|
|
|
|
error("tglTexImage2D: invalid border");
|
2012-01-16 17:12:14 +01:00
|
|
|
|
2017-05-06 14:17:35 +00:00
|
|
|
c->current_texture->versionNumber++;
|
|
|
|
im = &c->current_texture->images[level];
|
|
|
|
im->xsize = c->_textureSize;
|
|
|
|
im->ysize = c->_textureSize;
|
|
|
|
if (im->pixmap) {
|
|
|
|
delete im->pixmap;
|
|
|
|
im->pixmap = nullptr;
|
2012-01-16 17:12:14 +01:00
|
|
|
}
|
2014-06-21 14:48:24 +02:00
|
|
|
if (pixels != NULL) {
|
2017-05-06 14:17:35 +00:00
|
|
|
unsigned int filter;
|
2017-04-29 16:42:01 +00:00
|
|
|
Graphics::PixelBuffer src(formatType2PixelFormat(format, type), pixels);
|
2017-05-06 14:17:35 +00:00
|
|
|
if (width > c->_textureSize || height > c->_textureSize)
|
|
|
|
filter = c->texture_mag_filter;
|
|
|
|
else
|
|
|
|
filter = c->texture_min_filter;
|
|
|
|
switch (filter) {
|
|
|
|
case TGL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
case TGL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
case TGL_LINEAR:
|
|
|
|
im->pixmap = new Graphics::BilinearTexelBuffer(
|
|
|
|
src,
|
|
|
|
width, height,
|
|
|
|
c->_textureSize
|
2017-04-29 10:09:10 +00:00
|
|
|
);
|
2017-05-06 14:17:35 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
im->pixmap = new Graphics::NearestTexelBuffer(
|
|
|
|
src,
|
|
|
|
width, height,
|
|
|
|
c->_textureSize
|
2017-04-29 10:09:10 +00:00
|
|
|
);
|
2017-05-06 14:17:35 +00:00
|
|
|
break;
|
2014-12-23 20:39:38 +01:00
|
|
|
}
|
2008-07-29 19:28:19 +00:00
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
// TODO: not all tests are done
|
2009-05-25 13:19:29 +00:00
|
|
|
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;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
if (target != TGL_TEXTURE_ENV) {
|
|
|
|
error:
|
2014-09-21 15:05:17 +02:00
|
|
|
error("tglTexParameter: unsupported option");
|
2008-07-29 19:28:19 +00:00
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
if (pname != TGL_TEXTURE_ENV_MODE)
|
|
|
|
goto error;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
if (param != TGL_DECAL)
|
|
|
|
goto error;
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
// TODO: not all tests are done
|
2017-05-06 14:17:35 +00:00
|
|
|
void glopTexParameter(GLContext *c, 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:
|
2014-09-21 15:05:17 +02:00
|
|
|
error("tglTexParameter: unsupported option");
|
2008-07-29 19:28:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (pname) {
|
|
|
|
case TGL_TEXTURE_WRAP_S:
|
2017-05-06 14:17:35 +00:00
|
|
|
c->texture_wrap_s = param;
|
|
|
|
break;
|
2008-07-29 19:28:19 +00:00
|
|
|
case TGL_TEXTURE_WRAP_T:
|
2017-05-06 14:17:35 +00:00
|
|
|
c->texture_wrap_t = param;
|
|
|
|
break;
|
|
|
|
case TGL_TEXTURE_MAG_FILTER:
|
|
|
|
switch (param) {
|
|
|
|
case TGL_NEAREST:
|
|
|
|
case TGL_LINEAR:
|
|
|
|
c->texture_mag_filter = param;
|
|
|
|
break;
|
|
|
|
default:
|
2008-07-29 19:28:19 +00:00
|
|
|
goto error;
|
2017-05-06 14:17:35 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TGL_TEXTURE_MIN_FILTER:
|
|
|
|
switch (param) {
|
|
|
|
case TGL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
case TGL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
case TGL_NEAREST_MIPMAP_NEAREST:
|
|
|
|
case TGL_NEAREST_MIPMAP_LINEAR:
|
|
|
|
case TGL_NEAREST:
|
|
|
|
case TGL_LINEAR:
|
|
|
|
c->texture_min_filter = param;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto error;
|
|
|
|
}
|
2008-07-29 19:28:19 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
|
|
|
|
2009-05-25 13:19:29 +00:00
|
|
|
void glopPixelStore(GLContext *, GLParam *p) {
|
2008-07-29 19:28:19 +00:00
|
|
|
int pname = p[1].i;
|
|
|
|
int param = p[2].i;
|
2005-01-12 15:20:02 +00:00
|
|
|
|
2008-07-29 19:28:19 +00:00
|
|
|
if (pname != TGL_UNPACK_ALIGNMENT || param != 1) {
|
2014-09-21 15:05:17 +02:00
|
|
|
error("tglPixelStore: unsupported option");
|
2008-07-29 19:28:19 +00:00
|
|
|
}
|
2005-01-12 15:20:02 +00:00
|
|
|
}
|
2009-05-25 13:19:29 +00:00
|
|
|
|
|
|
|
} // end of namespace TinyGL
|
|
|
|
|
|
|
|
void tglGenTextures(int n, unsigned int *textures) {
|
|
|
|
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
2016-07-17 13:25:23 +00:00
|
|
|
unsigned int max;
|
2009-05-25 13:19:29 +00:00
|
|
|
TinyGL::GLTexture *t;
|
|
|
|
|
|
|
|
max = 0;
|
2014-02-20 17:56:55 +01:00
|
|
|
for (int i = 0; i < TEXTURE_HASH_TABLE_SIZE; i++) {
|
2009-05-25 13:19:29 +00:00
|
|
|
t = c->shared_state.texture_hash_table[i];
|
|
|
|
while (t) {
|
|
|
|
if (t->handle > max)
|
|
|
|
max = t->handle;
|
|
|
|
t = t->next;
|
|
|
|
}
|
|
|
|
}
|
2014-02-20 17:56:55 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
2009-05-25 13:19:29 +00:00
|
|
|
textures[i] = max + i + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tglDeleteTextures(int n, const unsigned int *textures) {
|
|
|
|
TinyGL::GLContext *c = TinyGL::gl_get_context();
|
|
|
|
TinyGL::GLTexture *t;
|
|
|
|
|
2014-02-20 17:56:55 +01:00
|
|
|
for (int i = 0; i < n; i++) {
|
2009-05-25 13:19:29 +00:00
|
|
|
t = TinyGL::find_texture(c, textures[i]);
|
|
|
|
if (t) {
|
|
|
|
if (t == c->current_texture) {
|
|
|
|
tglBindTexture(TGL_TEXTURE_2D, 0);
|
|
|
|
}
|
2014-07-25 12:59:51 +02:00
|
|
|
t->disposed = true;
|
2009-05-25 13:19:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|