Mon, 21 Apr 2025 17:52:01 +0200
fix probably incorrect array access of struct members
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * Copyright 2024 Mike Becker. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ascension/context.h" #include "ascension/texture.h" #include "ascension/error.h" #include "ascension/filesystem.h" #include <assert.h> #include <cx/utils.h> #include <GL/glew.h> #include <SDL2/SDL_image.h> void asc_texture_bind(AscTexture const *tex, int uniform_location, int unit) { glActiveTexture(GL_TEXTURE0 + unit); GLenum error = glGetError(); if (error == GL_INVALID_ENUM) { asc_error("Tried to use more texture units than available."); } glBindTexture(tex->target, tex->tex_id); glUniform1i(uniform_location, unit); asc_error_catch_all_gl(); } void asc_texture_from_surface(AscTexture *tex, SDL_Surface const *surface) { if (tex->tex_id == 0) { asc_error("Tried to use uninitialized texture."); asc_dprintf("Texture address: %"PRIxPTR, (uintptr_t) tex); return; } tex->width = surface->w; tex->height = surface->h; glBindTexture(tex->target,tex->tex_id); glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel); // Determine the format and internal format based on the SDL surface format GLint internal_format; GLenum format; switch (surface->format->format) { case SDL_PIXELFORMAT_RGB24: internal_format = GL_RGB8; format = GL_RGB; break; case SDL_PIXELFORMAT_BGR24: internal_format = GL_RGB8; format = GL_BGR; break; case SDL_PIXELFORMAT_RGBA32: case SDL_PIXELFORMAT_ABGR32: internal_format = GL_RGBA8; format = GL_RGBA; break; case SDL_PIXELFORMAT_ARGB32: case SDL_PIXELFORMAT_BGRA32: internal_format = GL_RGBA8; format = GL_BGRA; break; default: // TODO: add more output once asc_error allows format strings asc_error("Unsupported pixel format."); return; } glTexImage2D(tex->target, 0, internal_format, surface->w, surface->h, 0, format, GL_UNSIGNED_BYTE, surface->pixels); // TODO: replace catch all with proper error handling for this single call asc_error_catch_all_gl(); } void asc_texture_from_file(AscTexture *tex, const char *name) { cxmutstr filepath = asc_filesystem_combine_paths(cx_strcast(asc_context.texture_path), cx_str(name)); asc_dprintf("Load texture from %" CX_PRIstr, CX_SFMT(filepath)); SDL_Surface *image = IMG_Load(filepath.ptr); cx_strfree(&filepath); if (image == NULL) { asc_error("Failed to load texture."); asc_error(IMG_GetError()); return; } asc_texture_from_surface(tex, image); asc_dprintf("Free temporary surface %"PRIxPTR, (uintptr_t) image); SDL_FreeSurface(image); } void asc_texture_init( AscTexture *tex, unsigned count, enum asc_texture_target target, enum asc_texture_min_filter min_filter, enum asc_texture_mag_filter mag_filter ) { static const GLenum texture_targets[] = { GL_TEXTURE_RECTANGLE, GL_TEXTURE_2D, }; static const GLint texture_filters[] = { GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR }; assert(target < sizeof(texture_targets) / sizeof(GLenum)); assert(min_filter < sizeof(texture_filters) / sizeof(GLint)); assert(mag_filter < 2); // mag filter only supports nearest/linear GLuint textures[count]; glGenTextures(count, textures); for (unsigned i = 0; i < count; ++i) { memset(&tex[i], 0, sizeof(AscTexture)); tex[i].tex_id = textures[i]; tex[i].target = texture_targets[target]; glBindTexture(tex[i].target, tex[i].tex_id); glTexParameteri(tex[i].target, GL_TEXTURE_MIN_FILTER, texture_filters[min_filter]); glTexParameteri(tex[i].target, GL_TEXTURE_MAG_FILTER, texture_filters[mag_filter]); asc_dprintf("Initialized texture: %u", tex[i].tex_id); } // TODO: proper error handling for each gl call asc_error_catch_all_gl(); } void asc_texture_destroy(AscTexture *tex, unsigned count) { GLuint textures[count]; for (unsigned i = 0; i < count; ++i) { if (tex[i].refcount > 0) { // TODO: asc_wprintf() for warnings asc_dprintf("Texture %u still in use by %u objects.", tex[i].tex_id, tex[i].refcount); } asc_dprintf("Destroy texture: %u", tex[i].tex_id); textures[i] = tex[i].tex_id; memset(&tex[i], 0, sizeof(AscTexture)); } glDeleteTextures(count, textures); }