/** * 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; icolorCount, "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 }