scummvm/graphics/tinygl/texture.cpp

293 lines
6.7 KiB
C++
Raw Normal View History

2021-12-26 21:19:38 +01:00
/* ScummVM - Graphic Adventure Engine
2014-08-13 18:52:52 +02:00
*
2021-12-26 21:19:38 +01:00
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
2014-08-13 18:52:52 +02:00
* 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 3 of the License, or
* (at your option) any later version.
2014-08-13 18:52:52 +02:00
*
* 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, see <http://www.gnu.org/licenses/>.
2014-08-13 18:52:52 +02:00
*
*/
/*
* 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
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"
namespace TinyGL {
GLTexture *GLContext::find_texture(uint h) {
2006-05-16 14:52:36 +00:00
GLTexture *t;
t = 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;
}
2021-12-04 14:27:35 +01:00
return nullptr;
}
void GLContext::free_texture(uint h) {
free_texture(find_texture(h));
}
void GLContext::free_texture(GLTexture *t) {
GLTexture **ht;
2006-05-16 14:52:36 +00:00
GLImage *im;
assert(t);
2008-07-29 19:28:19 +00:00
if (!t->prev) {
ht = &shared_state.texture_hash_table[t->handle % TEXTURE_HASH_TABLE_SIZE];
2006-05-16 14:52:36 +00:00
*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 (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
2006-05-16 14:52:36 +00:00
im = &t->images[i];
if (im->pixmap) {
delete im->pixmap;
im->pixmap = nullptr;
}
2006-05-16 14:52:36 +00:00
}
gl_free(t);
}
GLTexture *GLContext::alloc_texture(uint h) {
2008-07-29 19:28:19 +00:00
GLTexture *t, **ht;
2008-07-29 19:28:19 +00:00
t = (GLTexture *)gl_zalloc(sizeof(GLTexture));
ht = &shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
2008-07-29 19:28:19 +00:00
t->next = *ht;
2021-12-04 14:27:35 +01:00
t->prev = nullptr;
2008-07-29 19:28:19 +00:00
if (t->next)
t->next->prev = t;
*ht = t;
2008-07-29 19:28:19 +00:00
t->handle = h;
t->disposed = false;
t->versionNumber = 0;
2008-07-29 19:28:19 +00:00
return t;
}
2021-12-07 09:54:19 +01:00
void GLContext::glopBindTexture(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);
t = find_texture(texture);
2008-07-29 19:28:19 +00:00
if (!t) {
t = alloc_texture(texture);
2008-07-29 19:28:19 +00:00
}
current_texture = t;
}
2021-12-07 09:54:19 +01:00
void GLContext::glopTexImage2D(GLParam *p) {
int target = p[1].i;
int level = p[2].i;
int internalformat = p[3].i;
int width = p[4].i;
int height = p[5].i;
int border = p[6].i;
uint format = (uint)p[7].i;
uint type = (uint)p[8].i;
byte *pixels = (byte *)p[9].p;
GLImage *im;
if (target != TGL_TEXTURE_2D)
error("tglTexImage2D: target not handled");
if (level < 0 || level >= MAX_TEXTURE_LEVELS)
error("tglTexImage2D: invalid level");
if (internalformat != TGL_RGBA && internalformat != TGL_RGB)
error("tglTexImage2D: invalid internalformat");
if (border != 0)
error("tglTexImage2D: invalid border");
assert (current_texture);
current_texture->versionNumber++;
im = &current_texture->images[level];
im->xsize = _textureSize;
im->ysize = _textureSize;
if (im->pixmap) {
delete im->pixmap;
im->pixmap = nullptr;
}
2022-01-01 12:00:38 +01:00
if (pixels) {
2021-12-15 23:55:36 +01:00
uint filter;
Graphics::PixelFormat pf;
bool found = false;
Common::Array<struct tglColorAssociation>::const_iterator it = colorAssociationList.begin();
for (; it != colorAssociationList.end(); it++) {
if (it->format == format &&
it->type == type) {
pf = it->pf;
found = true;
break;
}
}
if (!found)
error("TinyGL texture: format 0x%04x and type 0x%04x combination not supported", format, type);
Graphics::PixelBuffer src(pf, pixels);
Graphics::PixelFormat internalPf;
#if defined(SCUMM_LITTLE_ENDIAN)
if (internalformat == TGL_RGBA)
internalPf = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
else if (internalformat == TGL_RGB)
internalPf = Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0);
#else
if (internalformat == TGL_RGBA)
internalPf = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
else if (internalformat == TGL_RGB)
internalPf = Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0);
#endif
Graphics::PixelBuffer srcInternal(internalPf, width * height, DisposeAfterUse::YES);
srcInternal.copyBuffer(0, width * height, src);
if (width > _textureSize || height > _textureSize)
filter = texture_mag_filter;
else
filter = texture_min_filter;
switch (filter) {
case TGL_LINEAR_MIPMAP_NEAREST:
case TGL_LINEAR_MIPMAP_LINEAR:
case TGL_LINEAR:
2021-12-15 23:55:36 +01:00
im->pixmap = new BilinearTexelBuffer(
srcInternal,
width, height,
_textureSize
);
break;
default:
2021-12-15 23:55:36 +01:00
im->pixmap = new NearestTexelBuffer(
srcInternal,
width, height,
_textureSize
);
break;
2014-12-23 20:39:38 +01:00
}
2008-07-29 19:28:19 +00:00
}
}
2008-07-29 19:28:19 +00:00
// TODO: not all tests are done
2021-12-07 09:54:19 +01:00
void GLContext::glopTexEnv(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:
2014-09-21 15:05:17 +02:00
error("tglTexParameter: 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
2021-12-07 09:54:19 +01:00
void GLContext::glopTexParameter(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:
texture_wrap_s = param;
break;
2008-07-29 19:28:19 +00:00
case TGL_TEXTURE_WRAP_T:
texture_wrap_t = param;
break;
case TGL_TEXTURE_MAG_FILTER:
switch (param) {
case TGL_NEAREST:
case TGL_LINEAR:
texture_mag_filter = param;
break;
default:
2008-07-29 19:28:19 +00:00
goto error;
}
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:
texture_min_filter = param;
break;
default:
goto error;
}
2008-07-29 19:28:19 +00:00
break;
default:
;
}
}
2021-12-07 09:54:19 +01:00
void GLContext::glopPixelStore(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) {
2014-09-21 15:05:17 +02:00
error("tglPixelStore: unsupported option");
2008-07-29 19:28:19 +00:00
}
}
void GLContext::gl_GenTextures(TGLsizei n, TGLuint *textures) {
for (int i = 0; i < n; i++) {
textures[i] = maxTextureName + i + 1;
}
maxTextureName += n;
}
void GLContext::gl_DeleteTextures(TGLsizei n, const TGLuint *textures) {
for (int i = 0; i < n; i++) {
TinyGL::GLTexture *t = find_texture(textures[i]);
if (t) {
if (t == current_texture) {
current_texture = find_texture(0);
}
t->disposed = true;
}
}
}
} // end of namespace TinyGL