# HG changeset patch # User Mike Becker # Date 1712690332 -7200 # Node ID d8d2e4817db160961d1eaeb47422d8f00e247b35 # Parent 77493525eac24dfba260bb5c4e4da76aa8a7514c add texture.h diff -r 77493525eac2 -r d8d2e4817db1 shader/sprite_frag.glsl --- a/shader/sprite_frag.glsl Mon Apr 01 19:44:00 2024 +0200 +++ b/shader/sprite_frag.glsl Tue Apr 09 21:18:52 2024 +0200 @@ -3,8 +3,8 @@ layout(location = 0) out vec4 diffuse; in vec2 texcoord; -uniform sampler2DRect surface; +uniform sampler2DRect tex; void main(void) { - diffuse = texture(surface, texcoord); + diffuse = texture(tex, texcoord); } diff -r 77493525eac2 -r d8d2e4817db1 src/Makefile --- a/src/Makefile Mon Apr 01 19:44:00 2024 +0200 +++ b/src/Makefile Tue Apr 09 21:18:52 2024 +0200 @@ -28,7 +28,7 @@ BUILD_DIR=../build/lib SRC = context.c glcontext.c error.c window.c files.c shader.c font.c text.c \ - scene.c camera.c primitives.c + texture.c scene.c camera.c primitives.c OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o) @@ -102,11 +102,15 @@ $(BUILD_DIR)/text.o: text.c ascension/ui/text.h ascension/ui/font.h \ ascension/ui/../scene.h ascension/ui/../datatypes.h \ - ascension/ui/../transform.h ascension/ui/../camera.h ascension/context.h \ - ascension/datatypes.h ascension/window.h ascension/glcontext.h \ - ascension/primitives.h ascension/mesh.h ascension/shader.h \ - ascension/scene.h ascension/ui/font.h ascension/error.h \ - ascension/shader.h + ascension/ui/../transform.h ascension/ui/../camera.h \ + ascension/ui/../texture.h ascension/context.h ascension/datatypes.h \ + ascension/window.h ascension/glcontext.h ascension/primitives.h \ + ascension/mesh.h ascension/shader.h ascension/scene.h \ + ascension/ui/font.h ascension/error.h ascension/shader.h + @echo "Compiling $<" + $(CC) -o $@ $(CFLAGS) -c $< + +$(BUILD_DIR)/texture.o: texture.c ascension/texture.h ascension/error.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< diff -r 77493525eac2 -r d8d2e4817db1 src/ascension/shader.h --- a/src/ascension/shader.h Mon Apr 01 19:44:00 2024 +0200 +++ b/src/ascension/shader.h Tue Apr 09 21:18:52 2024 +0200 @@ -41,8 +41,8 @@ typedef struct AscShaderSprite { AscShaderProgram base; - int surface; int depth; + int tex; } AscShaderSprite; diff -r 77493525eac2 -r d8d2e4817db1 src/ascension/texture.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ascension/texture.h Tue Apr 09 21:18:52 2024 +0200 @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef ASCENSION_TEXTURE_H +#define ASCENSION_TEXTURE_H + +#include + +typedef struct AscTexture AscTexture; + +struct AscTexture { + unsigned target; + unsigned tex_id; +}; + +#define asc_texture_uninitialized(tex) ((tex)->tex_id == 0) + +enum asc_texture_target { + ASC_TEXTURE_RECTANGLE +}; + +enum asc_texture_min_filter { + ASC_TEXTURE_MIN_FILTER_NEAREST, + ASC_TEXTURE_MIN_FILTER_LINEAR, + ASC_TEXTURE_MIN_FILTER_NEAREST_MIPMAP_NEAREST, + ASC_TEXTURE_MIN_FILTER_LINEAR_MIPMAP_NEAREST, + ASC_TEXTURE_MIN_FILTER_NEAREST_MIPMAP_LINEAR, + ASC_TEXTURE_MIN_FILTER_LINEAR_MIPMAP_LINEAR +}; + +enum asc_texture_mag_filter { + ASC_TEXTURE_MAG_FILTER_NEAREST, + ASC_TEXTURE_MAG_FILTER_LINEAR +}; + +__attribute__((__nonnull__)) +void asc_texture_init( + AscTexture *tex, + enum asc_texture_target target, + enum asc_texture_min_filter min_filter, + enum asc_texture_mag_filter mag_filter +); + +__attribute__((__nonnull__)) +void asc_texture_destroy(AscTexture *tex); + +#define asc_texture_init_rectangle(tex) \ + asc_texture_init(tex, ASC_TEXTURE_RECTANGLE, \ + ASC_TEXTURE_MIN_FILTER_LINEAR, ASC_TEXTURE_MAG_FILTER_LINEAR) + +__attribute__((__nonnull__)) +void asc_texture_bind(AscTexture const *tex, int uniform_location, int unit); + +__attribute__((__nonnull__)) +void asc_texture_from_surface(AscTexture *tex, SDL_Surface const *surface); + +#endif //ASCENSION_TEXTURE_H diff -r 77493525eac2 -r d8d2e4817db1 src/ascension/ui/text.h --- a/src/ascension/ui/text.h Mon Apr 01 19:44:00 2024 +0200 +++ b/src/ascension/ui/text.h Tue Apr 09 21:18:52 2024 +0200 @@ -30,6 +30,7 @@ #include "font.h" #include "../scene.h" +#include "../texture.h" typedef struct AscText { extend_asc_scene_node; @@ -39,7 +40,7 @@ unsigned max_width; bool hidden; bool centered; - unsigned tex_id; + AscTexture tex; } AscText; diff -r 77493525eac2 -r d8d2e4817db1 src/glcontext.c --- a/src/glcontext.c Mon Apr 01 19:44:00 2024 +0200 +++ b/src/glcontext.c Tue Apr 09 21:18:52 2024 +0200 @@ -51,8 +51,8 @@ static void asc_shader_initialize_predefined(AscGLContext *ctx) { AscShaderSprite *sprite = &ctx->shader.sprite; sprite->base = asc_shader_easy_compile_and_link("shader/sprite_vtx.glsl", "shader/sprite_frag.glsl"); - sprite->surface = glGetUniformLocation(sprite->base.id, "surface"); sprite->depth = glGetUniformLocation(sprite->base.id, "depth"); + sprite->tex = glGetUniformLocation(sprite->base.id, "texture"); } static void asc_shader_destroy_predefined(AscGLContext *ctx) { diff -r 77493525eac2 -r d8d2e4817db1 src/shader.c --- a/src/shader.c Mon Apr 01 19:44:00 2024 +0200 +++ b/src/shader.c Tue Apr 09 21:18:52 2024 +0200 @@ -32,9 +32,6 @@ #include #include -AscShaderSprite ASC_SHADER_SPRITE; - - AscShader asc_shader_compile(unsigned int type, char const *code, int length) { diff -r 77493525eac2 -r d8d2e4817db1 src/text.c --- a/src/text.c Mon Apr 01 19:44:00 2024 +0200 +++ b/src/text.c Tue Apr 09 21:18:52 2024 +0200 @@ -33,7 +33,7 @@ #include static void asc_text_draw(AscText const *node) { - if (node->color.alpha == 0 || node->hidden || node->tex_id == 0) { + if (node->color.alpha == 0 || node->hidden) { return; } @@ -44,10 +44,8 @@ glUniformMatrix4fv(shader->base.model, 1, GL_FALSE, node->base.world_transform); - // Upload surface - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); - glUniform1i(shader->surface, 0); + // Bind texture + asc_texture_bind(&node->tex, shader->tex, 0); // Apply depth glUniform1f(shader->depth, (float)(node->base.depth)); @@ -63,12 +61,8 @@ } // Generate new texture, if required - if (node->tex_id == 0) { - glGenTextures(1, &node->tex_id); - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); - glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - asc_dprintf("Generated new texture for text node: %u", node->tex_id); + if (asc_texture_uninitialized(&node->tex)) { + asc_texture_init_rectangle(&node->tex); } // Render text onto a surface @@ -87,12 +81,7 @@ asc_update_transform((AscSceneNode *) node); // Transfer Image Data - // TODO: move the image data transfer to a separate function - we will need it more often - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); - glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel); - glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, - surface->w, surface->h, - 0, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels); + asc_texture_from_surface(&node->tex, surface); // Free the surface SDL_FreeSurface(surface); @@ -100,10 +89,6 @@ AscSceneNode *asc_text(int x, int y, char const *text) { AscText *node = calloc(1, sizeof(AscText)); - if (node == NULL) { - asc_error("Out of memory."); - return NULL; - } node->base.render_group = ASC_RENDER_GROUP_SPRITE_BLEND; node->base.free_func = (asc_scene_free_func) asc_text_free; @@ -125,8 +110,7 @@ } void asc_text_free(AscText *node) { - asc_dprintf("Release text node texture: %u", node->tex_id); - glDeleteTextures(1, &node->tex_id); + asc_texture_destroy(&node->tex); free(node->text); free(node); } \ No newline at end of file diff -r 77493525eac2 -r d8d2e4817db1 src/texture.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/texture.c Tue Apr 09 21:18:52 2024 +0200 @@ -0,0 +1,87 @@ +/* + * 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/texture.h" +#include "ascension/error.h" + +#include +#include + +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); +} + +void asc_texture_from_surface(AscTexture *tex, SDL_Surface const *surface) { + glBindTexture(tex->target,tex->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH, + surface->pitch / surface->format->BytesPerPixel); + glTexImage2D(tex->target, 0, GL_RGBA, + surface->w, surface->h, + 0, GL_BGRA, + GL_UNSIGNED_BYTE, surface->pixels); +} + +void asc_texture_init( + AscTexture *tex, + 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 + }; + 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 + tex->target = texture_targets[target]; + glGenTextures(1, &tex->tex_id); + glBindTexture(tex->target, tex->tex_id); + glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, + texture_filters[min_filter]); + glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, + texture_filters[mag_filter]); + asc_dprintf("Generated new texture for text node: %u", tex->tex_id); +} + +void asc_texture_destroy(AscTexture *tex) { + asc_dprintf("Release text node texture: %u", tex->tex_id); + glDeleteTextures(1, &tex->tex_id); +} diff -r 77493525eac2 -r d8d2e4817db1 test/Makefile --- a/test/Makefile Mon Apr 01 19:44:00 2024 +0200 +++ b/test/Makefile Tue Apr 09 21:18:52 2024 +0200 @@ -49,7 +49,8 @@ ../src/ascension/scene.h ../src/ascension/transform.h \ ../src/ascension/camera.h ../src/ascension/ui/font.h \ ../src/ascension/ui.h ../src/ascension/ui/text.h \ - ../src/ascension/ui/font.h ../src/ascension/ui/../scene.h + ../src/ascension/ui/font.h ../src/ascension/ui/../scene.h \ + ../src/ascension/ui/../texture.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $<