add texture.h

Tue, 09 Apr 2024 21:18:52 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 09 Apr 2024 21:18:52 +0200
changeset 50
d8d2e4817db1
parent 49
77493525eac2
child 51
a656496594f9

add texture.h

shader/sprite_frag.glsl file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/ascension/shader.h file | annotate | diff | comparison | revisions
src/ascension/texture.h file | annotate | diff | comparison | revisions
src/ascension/ui/text.h file | annotate | diff | comparison | revisions
src/glcontext.c file | annotate | diff | comparison | revisions
src/shader.c file | annotate | diff | comparison | revisions
src/text.c file | annotate | diff | comparison | revisions
src/texture.c file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
--- 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);
 }
--- 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 $<
 
--- 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;
 
 
--- /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 <SDL2/SDL_surface.h>
+
+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
--- 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;
 
 
--- 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) {
--- 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 <GL/glew.h>
 #include <string.h>
 
-AscShaderSprite ASC_SHADER_SPRITE;
-
-
 AscShader asc_shader_compile(unsigned int type,
                              char const *code,
                              int length) {
--- 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 <GL/glew.h>
 
 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
--- /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 <assert.h>
+#include <GL/glew.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);
+}
+
+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);
+}
--- 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 $<
 

mercurial