improve the combination of shader preprocessor flags default tip

Thu, 19 Jun 2025 19:22:07 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 19 Jun 2025 19:22:07 +0200
changeset 160
80700db530ff
parent 159
da7ebfcdd159

improve the combination of shader preprocessor flags

src/2d.c file | annotate | diff | comparison | revisions
src/ascension/shader.h file | annotate | diff | comparison | revisions
src/shader.c file | annotate | diff | comparison | revisions
test/snake/snake.c file | annotate | diff | comparison | revisions
--- a/src/2d.c	Wed Jun 18 23:55:08 2025 +0200
+++ b/src/2d.c	Thu Jun 19 19:22:07 2025 +0200
@@ -33,6 +33,7 @@
 #include "ascension/shader.h"
 
 #include <GL/glew.h>
+#include <assert.h>
 
 typedef struct asc_rectangle_shader_s {
     AscShaderProgram program;
@@ -51,19 +52,15 @@
     AscShaderCodes codes;
     // TODO: create a utility that rolls out those defines
     const char * const defines[] = {
-        NULL,
-        "#define FILL",
-        "#define BORDER\n#define ROUNDED_CORNERS",
-        "#define FILL\n#define ROUNDED_CORNERS",
-        "#define BORDER",
-        "#define BORDER\n#define FILL",
-        "#define BORDER\n#define ROUNDED_CORNERS",
-        "#define BORDER\n#define FILL\n#define ROUNDED_CORNERS",
+        "#define FILL\n",
+        "#define ROUNDED_CORNERS\n",
+        "#define BORDER\n"
     };
     if (asc_shader_load_code_files((AscShaderCodeInfo){
         .files.vtx = "sprite_vtx.glsl",
         .files.frag = "rectangle_frag.glsl",
-        .defines.frag = defines[flags],
+        .defines.frag_list = defines,
+        .defines.frag_list_select = flags
     }, &codes)) {
         asc_error("Loading sprite shader failed.");
         return NULL;
@@ -71,6 +68,7 @@
     AscRectangleShader *shader = asc_shader_create(codes, sizeof(*shader));
     if (asc_has_error()) {
         asc_shader_free_codes(codes);
+        // TODO: must not return NULL or must add error handling on caller site
         return NULL;
     }
     shader->size = glGetUniformLocation(shader->program.gl_id, "size");
--- a/src/ascension/shader.h	Wed Jun 18 23:55:08 2025 +0200
+++ b/src/ascension/shader.h	Thu Jun 19 19:22:07 2025 +0200
@@ -50,6 +50,24 @@
      * Preprocessor code that shall be prepended to the fragment shader.
      */
     const char *frag;
+    /**
+     * A list of flag-based preprocessor code for the vertex shader.
+     * Each code must end with a new-line.
+     */
+    const char * const *vtx_list;
+    /**
+     * A list of flag-based preprocessor code for the fragment shader.
+     * Each code must end with a new-line.
+     */
+    const char * const *frag_list;
+    /**
+     * Selection flags for the list of codes for the vertex shader.
+     */
+    unsigned short vtx_list_select;
+    /**
+     * Selection flags for the list of codes for the fragment shader.
+     */
+    unsigned short frag_list_select;
 };
 
 typedef struct asc_shader_code_info_s {
@@ -68,6 +86,10 @@
      * Optional preprocessor code for the fragment shader.
      */
     const char *frag_pp;
+    const char * const *vtx_pp_list;
+    const char * const *frag_pp_list;
+    unsigned short vtx_pp_list_select;
+    unsigned short frag_pp_list_select;
 } AscShaderCodes;
 
 typedef struct asc_shader_program_s {
--- a/src/shader.c	Wed Jun 18 23:55:08 2025 +0200
+++ b/src/shader.c	Thu Jun 19 19:22:07 2025 +0200
@@ -44,32 +44,43 @@
  * @param type the shader type (use the GL enum)
  * @param code the source code
  * @param code_pp the optional preprocessor code
+ * @param code_pp_list list of optional preprocessor code
+ * @param code_pp_list_select selection flags for the preprocessor code list
  * @return the compiled shader
  */
-static unsigned asc_shader_compile(unsigned int type, const char *code, const char *code_pp) {
+static unsigned asc_shader_compile(unsigned int type, const char *code, const char *code_pp,
+    const char * const *code_pp_list, unsigned short code_pp_list_select) {
     GLuint id = glCreateShader(type);
     if (id == 0) {
         asc_error("glCreateShader failed: %s", glGetError());
         return 0;
     }
 
-    // some drivers don't like NULL strings, even when length is zero
-    if (code_pp == NULL) code_pp = "";
+    GLint success;
+    const char *code_array[20];
+    GLsizei code_count = 0;
+    code_array[code_count++] = "#version 400 core\n";
+    if (code_pp != NULL) code_array[code_count++] = code_pp;
+    unsigned test_flag = 1;
+    unsigned select_index = 0;
+    while (test_flag <= code_pp_list_select) {
+        if (asc_test_flag(code_pp_list_select, test_flag)) {
+            code_array[code_count++] = code_pp_list[select_index];
+        }
+        select_index++;
+        test_flag <<= 1;
+    }
+    code_array[code_count++] = "\n#line 1\n";
+    code_array[code_count++] = code;
 
-    GLint success;
-    const char *code_array[4] = {
-        "#version 400 core\n",
-        code_pp,
-        "\n#line 1\n",
-        code
-    };
-    GLint length_array[4];
-    for (unsigned int i = 0; i < cx_nmemb(length_array); i++) {
+    // compute the lengths
+    GLint length_array[20];
+    for (int i = 0; i < code_count ; i++) {
         length_array[i] = (GLint) strlen(code_array[i]);
     }
 
     // compile
-    glShaderSource(id, cx_nmemb(length_array), code_array, length_array);
+    glShaderSource(id, code_count, code_array, length_array);
     glCompileShader(id);
     glGetShaderiv(id, GL_COMPILE_STATUS, &success);
     if (success) {
@@ -145,10 +156,10 @@
     unsigned shader[2];
     unsigned n = 0;
     if (codes.vtx) {
-        shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp);
+        shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp, codes.vtx_pp_list, codes.vtx_pp_list_select);
     }
     if (codes.frag) {
-        shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp);
+        shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp, codes.frag_pp_list, codes.frag_pp_list_select);
     }
     if (asc_shader_link(shader, n, prog)) {
         cxFreeDefault(prog);
@@ -197,8 +208,12 @@
     int ret = 0;
     ret |= asc_shader_load_code_file(info.files.vtx, &codes->vtx);
     codes->vtx_pp = info.defines.vtx;
+    codes->vtx_pp_list = info.defines.vtx_list;
+    codes->vtx_pp_list_select = info.defines.vtx_list_select;
     ret |= asc_shader_load_code_file(info.files.frag, &codes->frag);
     codes->frag_pp = info.defines.frag;
+    codes->frag_pp_list = info.defines.frag_list;
+    codes->frag_pp_list_select = info.defines.frag_list_select;
     return ret;
 }
 
--- a/test/snake/snake.c	Wed Jun 18 23:55:08 2025 +0200
+++ b/test/snake/snake.c	Thu Jun 19 19:22:07 2025 +0200
@@ -196,12 +196,40 @@
     // create spaceship
     create_spaceship();
 
-    // TODO: play around with the test rectangle
+    // TODO: play around with the test rectangles
     asc_ink_rgb(255, 0, 0);
     asc_scene_add_node(MAIN_SCENE,
         asc_rectangle(.x = 200, .y = 250, .width = 100, .height = 75,
             .thickness = 4, .radius = 15, .filled = true, .border_color = asc_col4i_new(0, 255, 0, 255))
     );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 50, .y = 150, .width = 100, .height = 75,
+        .thickness = 4, .radius = 15, .filled = false, .border_color = asc_col4i_new(0, 255, 0, 255))
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 50, .y = 25, .width = 100, .height = 75,
+        .thickness = 4, .filled = false, .border_color = asc_col4i_new(0, 255, 0, 255))
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 250, .y = 25, .width = 100, .height = 75,
+        .thickness = 4, .filled = true, .border_color = asc_col4i_new(0, 255, 0, 255))
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 350, .y = 250, .width = 100, .height = 75,
+        .radius = 15, .filled = true)
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 350, .y = 50, .width = 100, .height = 75,
+        .filled = true)
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 50, .y = 350, .width = 100, .height = 75,
+        .radius = 15)
+    );
+    asc_scene_add_node(MAIN_SCENE,
+    asc_rectangle(.x = 350, .y = 350, .width = 100, .height = 75)
+    );
+
 
     // Main Loop
     do {

mercurial