-// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
-const char *vg_shader_gl_ver = "#version 330 core\n";
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
-static inline int static_str_index( const char *list[], int len, const char *str )
-{
- for( int i = 0; i < len; i ++ )
- {
- if( !strcmp(list[i],str) )
- return i;
- }
-
- #ifndef VG_RELEASE
- fprintf( stderr, "That was not a static string index!! (%s)\n", str );
- abort();
- #endif
-}
-#pragma GCC diagnostic pop
-
-#define SHADER_NAME( NAME ) (NAME##_static_shader.program)
-#define SHADER_USE( NAME ) glUseProgram( NAME##_static_shader.program )
+#ifndef VG_SHADER_H
+#define VG_SHADER_H
-#define SHADER_UNIFORM( NAME, U ) NAME##_shader_uniforms[ STR_STATIC_INDEX( NAME##_shader_names, U ) ]
-#define SHADER_UNIFORM_NAME( NAME, UID ) NAME##_shader_names[ UID ]
-#define STR_STATIC_INDEX( LIST, STR ) static_str_index( LIST, vg_list_size(LIST), STR )
+#include "vg/vg.h"
+#include "vg/vg_platform.h"
-#define UNIFORMS(...) __VA_ARGS__
+#if 0
+#define STB_INCLUDE_IMPLEMENTATION
+#define STB_INCLUDE_LINE_GLSL
+#define STB_MALLOC vg_alloc
+#define STB_FREE vg_free
+#define STB_REALLOC vg_realloc
+#include "stb/stb_include.h"
+#endif
-#define SHADER_DEFINE( NAME, VERT, FRAG, UNIFORMS ) \
- const char * NAME##_shader_names[] = UNIFORMS; \
- GLint NAME##_shader_uniforms[ vg_list_size( NAME##_shader_names ) ]; \
- struct vg_shader NAME##_static_shader = { \
- .src_vert = VERT, .src_frag = FRAG, \
- .sym = #NAME "_static.shader", \
- .uniform_names = NAME##_shader_names, \
- .uniforms = NAME##_shader_uniforms, \
- .uniform_count = vg_list_size( NAME##_shader_names ), \
- };
-
-#define SHADER_INIT( NAME ) arrpush( vg_shaders_active, &NAME##_static_shader )
+const char *vg_shader_gl_ver = "#version 330 core\n";
-#define SHADER_STATUS_NONE 0x00
-#define SHADER_STATUS_COMPILED 0x1
+typedef struct vg_shader vg_shader;
-struct vg_shader
+struct
{
- GLuint program;
-
- const char *src_vert;
- const char *src_frag;
- const char *src_geo;
- const char *sym;
-
- const char **uniform_names;
- GLint *uniforms;
- u32 uniform_count;
- u32 status;
+ struct vg_shader
+ {
+ GLuint id;
+ const char *name;
+
+ struct vg_subshader
+ {
+ const char *orig_file,
+ *static_src;
+ }
+ vs, fs;
+
+ void (*link)(void);
+ int compiled;
+ }
+ * shaders[32];
+ u32 count;
}
-** vg_shaders_active = NULL;
+static vg_shaders;
-static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
+VG_STATIC GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
{
GLint shader = glCreateShader( gliShaderType );
- glShaderSource( shader, 2, (const char *[2]){ vg_shader_gl_ver, src }, NULL );
+
+ if( shader == GL_NONE )
+ {
+ vg_error( "Could not 'glCreateShader()'\n" );
+ return 0;
+ }
+
+ glShaderSource( shader, 2, (const char*[2]){ vg_shader_gl_ver, src }, NULL );
glCompileShader( shader );
- int success;
- char infoLog[512];
- glGetShaderiv( shader, GL_COMPILE_STATUS, &success );
+ GLint status;
+ glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
- if( !success )
+ if( status != GL_TRUE )
{
- glGetShaderInfoLog( shader, 512, NULL, infoLog );
- vg_error( "Error info:\n%s\n", infoLog );
+ GLchar info[1024];
+ GLsizei len;
+
+ glGetShaderInfoLog( shader, sizeof(info), &len, info );
+ vg_error( "Error info:\n%s\n", info );
return 0;
}
return shader;
}
-static int vg_shader_compile( struct vg_shader *shader )
+VG_STATIC int vg_shader_compile( struct vg_shader *shader )
{
- vg_info( "Compile shader '%s'\n", shader->sym );
+ vg_info( "Compile shader '%s'\n", shader->name );
- GLuint vert, frag, geo = 0;
+ GLuint program, vert, frag;
+ const char *svs, *sfs;
+ char *avs, *afs;
+
+ int static_src = 1;
+
+ /* If we are compiling this again, we obviously need to try to take the src
+ * from the disk instead.
+ *
+ * Only do this if we have filenames set on the shader, so engine shaders
+ * dont have to do it (text.. etc).
+ */
+ if( shader->compiled )
+ {
+ if( shader->vs.orig_file && shader->fs.orig_file )
+ static_src = 0;
+ else return 1;
+ }
+
+ if( static_src )
+ {
+ svs = shader->vs.static_src;
+ sfs = shader->fs.static_src;
+ }
+ else
+ {
+ vg_fatal_exit_loop( "Unimplemented" );
+
+#if 0
+ char error[260];
+ char path[260];
+ strcpy( path, shader->vs.orig_file );
+ avs = stb_include_file( path, "", "../../shaders", error );
+
+ strcpy( path, shader->fs.orig_file );
+ afs = stb_include_file( path, "", "../../shaders", error );
+
+ if( !avs || !afs )
+ {
+ vg_error( "Could not find shader source files (%s)\n",
+ shader->vs.orig_file );
+
+ vg_free( avs );
+ vg_free( afs );
+ return 0;
+ }
+
+ svs = avs;
+ sfs = afs;
+#endif
+ }
- vert = vg_shader_subshader( shader->src_vert, GL_VERTEX_SHADER );
- frag = vg_shader_subshader( shader->src_frag, GL_FRAGMENT_SHADER );
+ vert = vg_shader_subshader( svs, GL_VERTEX_SHADER );
+ frag = vg_shader_subshader( sfs, GL_FRAGMENT_SHADER );
+#if 0
+ if( !static_src )
+ {
+ free( avs );
+ free( afs );
+ }
+#endif
+
if( !vert || !frag )
return 0;
- if( shader->src_geo )
- {
- geo = vg_shader_subshader( shader->src_geo, GL_GEOMETRY_SHADER );
+ program = glCreateProgram();
- if( !geo )
- return 0;
- }
-
- shader->program = glCreateProgram();
- if( geo )
- glAttachShader( shader->program, geo );
-
- glAttachShader( shader->program, vert );
- glAttachShader( shader->program, frag );
- glLinkProgram( shader->program );
+ glAttachShader( program, vert );
+ glAttachShader( program, frag );
+ glLinkProgram( program );
glDeleteShader( vert );
glDeleteShader( frag );
-
- if( geo )
- glDeleteShader( geo );
- // Check for link errors
+ /* Check for link errors */
char infoLog[ 512 ];
int success_link = 1;
- glGetProgramiv( shader->program, GL_LINK_STATUS, &success_link );
+ glGetProgramiv( program, GL_LINK_STATUS, &success_link );
if( !success_link )
{
- glGetProgramInfoLog( shader->program, 512, NULL, infoLog );
+ glGetProgramInfoLog( program, 512, NULL, infoLog );
vg_error( "Link failed: %s\n", infoLog );
- glDeleteProgram( shader->program );
-
+ glDeleteProgram( program );
return 0;
}
- // Complete linkeage
- for( int i = 0; i < shader->uniform_count; i ++ )
- shader->uniforms[ i ] = glGetUniformLocation( shader->program, shader->uniform_names[i] );
-
- shader->status |= SHADER_STATUS_COMPILED;
+ if( shader->compiled )
+ glDeleteProgram( shader->id );
+
+ shader->id = program;
+ shader->compiled = 1;
+ if( shader->link )
+ shader->link();
return 1;
}
-static void vg_shaders_free(void)
+VG_STATIC void vg_free_shader( struct vg_shader *shader )
{
- for( int i = 0; i < arrlen( vg_shaders_active ); i ++ )
- {
- struct vg_shader *shader = vg_shaders_active[i];
-
- if( shader->status & SHADER_STATUS_COMPILED )
- glDeleteProgram( shader->program );
- }
-
- arrfree( vg_shaders_active );
+ if( shader->compiled )
+ {
+ glDeleteProgram( shader->id );
+ shader->compiled = 0;
+ }
}
-static int vg_shaders_compile(void)
+VG_STATIC void vg_shaders_compile(void)
{
vg_info( "Compiling shaders\n" );
- for( int i = 0; i < arrlen( vg_shaders_active ); i ++ )
+ for( int i=0; i<vg_shaders.count; i ++ )
{
- struct vg_shader *shader = vg_shaders_active[i];
+ vg_shader *shader = vg_shaders.shaders[i];
+
if( !vg_shader_compile( shader ) )
- {
- vg_shaders_free();
- return 0;
- }
+ vg_fatal_exit_loop( "Failed to compile shader" );
}
-
- vg_register_exit( &vg_shaders_free, "vg_shaders_free" );
- return 1;
}
+
+VG_STATIC int vg_shaders_live_recompile(int argc, const char *argv[])
+{
+ vg_info( "Recompiling shaders\n" );
+ for( int i=0; i<vg_shaders.count; i ++ )
+ {
+ struct vg_shader *shader = vg_shaders.shaders[i];
+ vg_shader_compile( shader );
+ }
+
+ return 0;
+}
+
+VG_STATIC void vg_shader_register( struct vg_shader *shader )
+{
+ if( vg_shaders.count == vg_list_size(vg_shaders.shaders) )
+ vg_fatal_exit_loop( "Too many shaders" );
+
+ shader->compiled = 0;
+ shader->id = 0; /* TODO: make this an error shader */
+ vg_shaders.shaders[ vg_shaders.count ++ ] = shader;
+}
+
+#endif /* VG_SHADER_H */