From bd57f345ed9dbed1d81683e48199626de2ea9044 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 27 Jun 2025 10:18:39 -0700 Subject: Restructure project --- src/core/texture.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 src/core/texture.c (limited to 'src/core/texture.c') diff --git a/src/core/texture.c b/src/core/texture.c new file mode 100644 index 0000000..89f7ec0 --- /dev/null +++ b/src/core/texture.c @@ -0,0 +1,218 @@ +#include "texture.h" + +#include + +#include +#include + +#include + +bool gfx_init_texture(Texture* texture, const TextureDesc* desc) { + assert(texture); + assert(desc); + + glGenTextures(1, &texture->id); + if (!texture->id) { + log_error("glGenTextures() failed"); + return false; + } + texture->target = to_GL_dimension(desc->dimension); + glBindTexture(texture->target, texture->id); + + // glTexStorageXD + const int levels = + desc->mipmaps + ? max(max(log2(desc->width), log2(desc->height)), log2(desc->depth)) + + 1 + : 1; + const GLenum internal_format = to_GL_internal_format(desc->format); + switch (texture->target) { + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + glTexStorage2D( + texture->target, levels, internal_format, desc->width, desc->height); + break; + default: + FAIL("Unhandled texture dimension"); + gfx_del_texture(texture); + return false; + } + + texture->format = to_GL_format(desc->format); + texture->type = to_GL_type(desc->format); + texture->width = desc->width; + texture->height = desc->height; + gfx_update_texture(texture, &desc->data); + + // gfx_update_texture() unbinds the texture at the end, so re-bind it here. + glBindTexture(texture->target, texture->id); + + // Mipmaps. + if (desc->mipmaps) { + glGenerateMipmap(texture->target); + } + + // Texture filtering. + const bool linear = desc->filtering == LinearFiltering; + GLenum min = desc->mipmaps ? (linear ? GL_LINEAR_MIPMAP_LINEAR + : GL_NEAREST_MIPMAP_NEAREST) + : (linear ? GL_LINEAR : GL_NEAREST); + GLenum mag = linear ? GL_LINEAR : GL_NEAREST; + glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min); + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag); + + // Texture wrapping. + GLenum wrap = GL_INVALID_ENUM; + switch (desc->wrap) { + case Repeat: + wrap = GL_REPEAT; + break; + case ClampToEdge: + wrap = GL_CLAMP_TO_EDGE; + break; + } + glTexParameteri(texture->target, GL_TEXTURE_WRAP_R, wrap); + glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, wrap); + + glBindTexture(texture->target, 0); + return true; +} + +void gfx_del_texture(Texture* texture) { + assert(texture); + + if (texture->id) { + glDeleteTextures(1, &texture->id); + texture->id = 0; + } +} + +void gfx_update_texture(Texture* texture, const TextureDataDesc* desc) { + assert(texture); + assert(desc); + + glBindTexture(texture->target, texture->id); + + // glTexSubImageXD + switch (texture->target) { + case GL_TEXTURE_2D: + if (desc->pixels) { + glTexSubImage2D( + GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, + /*yoffset=*/0, texture->width, texture->height, texture->format, + texture->type, desc->pixels); + } + break; + case GL_TEXTURE_CUBE_MAP: + for (int i = 0; i < 6; ++i) { + const void* pixels = *(&desc->cubemap.pixels_pos_x + i); + if (pixels) { + glTexSubImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, /*level=*/0, /*xoffset=*/0, + /*yoffset=*/0, texture->width, texture->height, texture->format, + texture->type, pixels); + } + } + break; + default: + FAIL("Unhandled texture dimension"); + break; + } + + glBindTexture(texture->target, 0); +} + +GLenum to_GL_dimension(TextureDimension dim) { + switch (dim) { + case Texture2D: + return GL_TEXTURE_2D; + case TextureCubeMap: + return GL_TEXTURE_CUBE_MAP; + default: + FAIL("Unhandled TextureDimension"); + return GL_INVALID_ENUM; + } +} + +GLenum to_GL_internal_format(TextureFormat format) { + switch (format) { + case TextureDepth: + return GL_DEPTH_COMPONENT; + case TextureRG16: + return GL_RG16; + case TextureRG16F: + return GL_RG16F; + case TextureRGB8: + return GL_RGB8; + case TextureR11G11B10F: + return GL_R11F_G11F_B10F; + case TextureRGBA8: + return GL_RGBA8; + case TextureSRGB8: + return GL_SRGB8; + case TextureSRGBA8: + return GL_SRGB8_ALPHA8; + default: + FAIL("Unhandled TextureFormat"); + return GL_INVALID_ENUM; + } +} + +GLenum to_GL_format(TextureFormat format) { + switch (format) { + case TextureDepth: + return GL_DEPTH_COMPONENT; + case TextureRG16: + case TextureRG16F: + return GL_RG; + case TextureRGB8: + case TextureR11G11B10F: + case TextureSRGB8: + return GL_RGB; + case TextureRGBA8: + case TextureSRGBA8: + return GL_RGBA; + default: + FAIL("Unhandled TextureFormat"); + return GL_INVALID_ENUM; + } +} + +GLenum to_GL_type(TextureFormat format) { + switch (format) { + case TextureDepth: + case TextureRG16F: + case TextureR11G11B10F: + return GL_FLOAT; + case TextureRG16: + case TextureRGB8: + case TextureRGBA8: + case TextureSRGB8: + case TextureSRGBA8: + return GL_UNSIGNED_BYTE; + default: + FAIL("Unhandled TextureFormat"); + return GL_INVALID_ENUM; + } +} + +GLenum to_GL_cubemap_face(CubemapFace face) { + switch (face) { + case CubemapFacePosX: + return GL_TEXTURE_CUBE_MAP_POSITIVE_X; + case CubemapFaceNegX: + return GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + case CubemapFacePosY: + return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + case CubemapFaceNegY: + return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + case CubemapFacePosZ: + return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + case CubemapFaceNegZ: + return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + default: + FAIL("Unhandled CubemapFace"); + return GL_INVALID_ENUM; + } +} -- cgit v1.2.3