Initial commit
This commit is contained in:
357
graphics/tinygl/texture.cpp
Normal file
357
graphics/tinygl/texture.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* 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.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is based on, or a modified version of code from TinyGL (C) 1997-2022 Fabrice Bellard,
|
||||
* which is licensed under the MIT license (see LICENSE).
|
||||
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
|
||||
*/
|
||||
|
||||
// Texture Manager
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "graphics/tinygl/zgl.h"
|
||||
|
||||
namespace TinyGL {
|
||||
|
||||
GLTexture *GLContext::find_texture(uint h) {
|
||||
GLTexture *t;
|
||||
|
||||
t = shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
|
||||
while (t) {
|
||||
if (t->handle == h)
|
||||
return t;
|
||||
t = t->next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GLContext::free_texture(GLTexture *t) {
|
||||
GLTexture **ht;
|
||||
GLImage *im;
|
||||
|
||||
assert(t);
|
||||
|
||||
if (!t->prev) {
|
||||
ht = &shared_state.texture_hash_table[t->handle % TEXTURE_HASH_TABLE_SIZE];
|
||||
*ht = t->next;
|
||||
} else {
|
||||
t->prev->next = t->next;
|
||||
}
|
||||
if (t->next)
|
||||
t->next->prev = t->prev;
|
||||
|
||||
for (int i = 0; i < MAX_TEXTURE_LEVELS; i++) {
|
||||
im = &t->images[i];
|
||||
if (im->pixmap) {
|
||||
delete im->pixmap;
|
||||
im->pixmap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gl_free(t);
|
||||
}
|
||||
|
||||
GLTexture *GLContext::alloc_texture(uint h) {
|
||||
GLTexture *t, **ht;
|
||||
|
||||
t = (GLTexture *)gl_zalloc(sizeof(GLTexture));
|
||||
|
||||
ht = &shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
|
||||
|
||||
t->next = *ht;
|
||||
t->prev = nullptr;
|
||||
if (t->next)
|
||||
t->next->prev = t;
|
||||
*ht = t;
|
||||
|
||||
t->handle = h;
|
||||
t->disposed = false;
|
||||
t->versionNumber = 0;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void GLContext::glopBindTexture(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
uint texture = p[2].ui;
|
||||
GLTexture *t;
|
||||
|
||||
assert(target == TGL_TEXTURE_2D);
|
||||
(void)target;
|
||||
|
||||
t = find_texture(texture);
|
||||
if (!t) {
|
||||
t = alloc_texture(texture);
|
||||
}
|
||||
current_texture = t;
|
||||
}
|
||||
|
||||
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 = ¤t_texture->images[level];
|
||||
im->xsize = _textureSize;
|
||||
im->ysize = _textureSize;
|
||||
if (im->pixmap) {
|
||||
delete im->pixmap;
|
||||
im->pixmap = nullptr;
|
||||
}
|
||||
if (pixels) {
|
||||
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);
|
||||
|
||||
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:
|
||||
im->pixmap = createBilinearTexelBuffer(
|
||||
pixels, pf,
|
||||
format, type,
|
||||
width, height,
|
||||
_textureSize,
|
||||
internalformat
|
||||
);
|
||||
break;
|
||||
default:
|
||||
im->pixmap = createNearestTexelBuffer(
|
||||
pixels, pf,
|
||||
format, type,
|
||||
width, height,
|
||||
_textureSize,
|
||||
internalformat
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not all tests are done
|
||||
void GLContext::glopTexEnv(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
int pname = p[2].i;
|
||||
int param = p[3].i;
|
||||
|
||||
if (target != TGL_TEXTURE_ENV) {
|
||||
error:
|
||||
error("tglTexEnv: unsupported option");
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case TGL_TEXTURE_ENV_MODE:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_DECAL ||
|
||||
param == TGL_BLEND ||
|
||||
param == TGL_ADD ||
|
||||
param == TGL_COMBINE)
|
||||
_texEnv.envMode = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_COMBINE_RGB:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_ADD)
|
||||
_texEnv.combineRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_COMBINE_ALPHA:
|
||||
if (param == TGL_REPLACE ||
|
||||
param == TGL_MODULATE ||
|
||||
param == TGL_ADD)
|
||||
_texEnv.combineAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
case TGL_SOURCE0_RGB:
|
||||
case TGL_SOURCE1_RGB:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_SOURCE0_RGB ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_TEXTURE ||
|
||||
param == TGL_PRIMARY_COLOR ||
|
||||
param == TGL_CONSTANT)
|
||||
op->sourceRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_SOURCE0_ALPHA:
|
||||
case TGL_SOURCE1_ALPHA:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_SOURCE0_ALPHA ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_TEXTURE ||
|
||||
param == TGL_PRIMARY_COLOR ||
|
||||
param == TGL_CONSTANT)
|
||||
op->sourceAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_OPERAND0_RGB:
|
||||
case TGL_OPERAND1_RGB:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_OPERAND0_RGB ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_SRC_COLOR ||
|
||||
param == TGL_ONE_MINUS_SRC_COLOR ||
|
||||
param == TGL_SRC_ALPHA)
|
||||
op->operandRGB = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_OPERAND0_ALPHA:
|
||||
case TGL_OPERAND1_ALPHA:
|
||||
{
|
||||
GLTextureEnvArgument *op = pname == TGL_OPERAND0_ALPHA ? &_texEnv.arg0 : &_texEnv.arg1;
|
||||
if (param == TGL_SRC_ALPHA ||
|
||||
param == TGL_ONE_MINUS_SRC_ALPHA)
|
||||
op->operandAlpha = param;
|
||||
else
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
case TGL_TEXTURE_ENV_COLOR:
|
||||
{
|
||||
_texEnv.constR = (byte)clampf(p[4].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constG = (byte)clampf(p[5].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constB = (byte)clampf(p[6].f * 255.0f, 0, 255.0f);
|
||||
_texEnv.constA = (byte)clampf(p[7].f * 255.0f, 0, 255.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not all tests are done
|
||||
void GLContext::glopTexParameter(GLParam *p) {
|
||||
int target = p[1].i;
|
||||
int pname = p[2].i;
|
||||
int param = p[3].i;
|
||||
|
||||
if (target != TGL_TEXTURE_2D) {
|
||||
error:
|
||||
error("tglTexParameter: unsupported option");
|
||||
}
|
||||
|
||||
switch (pname) {
|
||||
case TGL_TEXTURE_WRAP_S:
|
||||
texture_wrap_s = param;
|
||||
break;
|
||||
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:
|
||||
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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::gl_PixelStore(TGLenum pname, TGLint param) {
|
||||
if (pname != TGL_UNPACK_ALIGNMENT || param != 1) {
|
||||
error("tglPixelStore: unsupported option");
|
||||
}
|
||||
}
|
||||
|
||||
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 = default_texture;
|
||||
}
|
||||
t->disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace TinyGL
|
||||
|
||||
Reference in New Issue
Block a user