173 lines
5.0 KiB
C
173 lines
5.0 KiB
C
/**
|
|
* Copyright (c) 2025 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "texture.h"
|
|
#include "assert/assert.h"
|
|
#include "util/memory.h"
|
|
#include "util/math.h"
|
|
#include "display/palette/palettelist.h"
|
|
|
|
const texture_t *TEXTURE_BOUND = NULL;
|
|
|
|
void textureInit(
|
|
texture_t *texture,
|
|
const int32_t width,
|
|
const int32_t height,
|
|
const textureformat_t format,
|
|
const texturedata_t data
|
|
) {
|
|
assertNotNull(texture, "Texture cannot be NULL");
|
|
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
|
|
|
memoryZero(texture, sizeof(texture_t));
|
|
texture->width = width;
|
|
texture->height = height;
|
|
|
|
#if PSP
|
|
assertTrue(
|
|
width == mathNextPowTwo(width),
|
|
"Width must be powers of 2 for PSP"
|
|
);
|
|
assertTrue(
|
|
height == mathNextPowTwo(height),
|
|
"Height must be powers of 2 for PSP"
|
|
);
|
|
#endif
|
|
|
|
#if DISPLAY_SDL2
|
|
glGenTextures(1, &texture->id);
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
|
|
switch(format) {
|
|
case TEXTURE_FORMAT_RGBA:
|
|
assertNotNull(data.rgba.colors, "RGBA texture data cannot be NULL");
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
format, GL_UNSIGNED_BYTE, (void*)data.rgba.colors
|
|
);
|
|
break;
|
|
|
|
case TEXTURE_FORMAT_ALPHA:
|
|
assertNotNull(data.alpha.data, "Alpha texture data cannot be NULL");
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D, 0, format, width, height, 0,
|
|
format, GL_UNSIGNED_BYTE, (void*)data.alpha.data
|
|
);
|
|
break;
|
|
|
|
case TEXTURE_FORMAT_PALETTE:
|
|
assertNotNull(data.palette.data, "Palette texture data cannot be NULL");
|
|
assertTrue(
|
|
data.palette.palette < PALETTE_LIST_COUNT,
|
|
"Palette index out of range"
|
|
);
|
|
|
|
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
|
assertNotNull(pal, "Palette cannot be NULL");
|
|
GLenum err = glGetError();
|
|
if (err != GL_NO_ERROR) {
|
|
assertUnreachable("GL Error before setting color table");
|
|
}
|
|
|
|
// Do we support paletted textures?
|
|
bool_t havePalTex = false;
|
|
GLint mask = 0;
|
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
|
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
|
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
|
for (GLint i=0; i<n; ++i) {
|
|
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
|
if (e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
|
}
|
|
} else {
|
|
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
|
havePalTex = ext && strstr(ext, "GL_EXT_paletted_texture");
|
|
}
|
|
|
|
if(!havePalTex) {
|
|
// Not supported, convert to RGBA using lookup
|
|
color_t formatted[width * height];
|
|
for(int32_t i = 0; i < width * height; i++) {
|
|
uint8_t index = data.palette.data[i];
|
|
assertTrue(
|
|
index < pal->colorCount,
|
|
"Palette index out of range"
|
|
);
|
|
formatted[i] = pal->colors[index];
|
|
}
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
|
GL_RGBA, GL_UNSIGNED_BYTE, (void*)formatted
|
|
);
|
|
} else {
|
|
// Supported.
|
|
glColorTableEXT(
|
|
GL_TEXTURE_2D, GL_RGBA, pal->colorCount, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, (const void*)pal->colors
|
|
);
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D,
|
|
0, GL_COLOR_INDEX8_EXT,
|
|
width, height,
|
|
0, GL_COLOR_INDEX8_EXT,
|
|
GL_UNSIGNED_BYTE, (void*)data.palette.data
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
assertUnreachable("Unknown texture format");
|
|
break;
|
|
}
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
#endif
|
|
}
|
|
|
|
void textureBind(const texture_t *texture) {
|
|
if(TEXTURE_BOUND == texture) return;
|
|
|
|
if(texture == NULL) {
|
|
#if DISPLAY_SDL2
|
|
glDisable(GL_TEXTURE_2D);
|
|
#endif
|
|
TEXTURE_BOUND = NULL;
|
|
return;
|
|
}
|
|
|
|
assertTrue(
|
|
texture->id != 0,
|
|
"Texture ID must not be 0"
|
|
);
|
|
assertTrue(
|
|
texture->width > 0 && texture->height > 0,
|
|
"Texture width and height must be greater than 0"
|
|
);
|
|
|
|
#if DISPLAY_SDL2
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
|
#endif
|
|
TEXTURE_BOUND = texture;
|
|
}
|
|
|
|
void textureDispose(texture_t *texture) {
|
|
assertNotNull(texture, "Texture cannot be NULL");
|
|
assertTrue(texture->id != 0, "Texture ID must not be 0");
|
|
|
|
#if DISPLAY_SDL2
|
|
glDeleteTextures(1, &texture->id);
|
|
#endif
|
|
} |