--- /dev/null
+/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
+
+#pragma once
+#include "vg_platform.h"
+#include "vg_shader.h"
+#include "vg_engine.h"
+
+#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 "submodules/stb/stb_include.h"
+
+const char *vg_shader_gl_ver = "#version 330 core\n";
+
+struct vg_shaders vg_shaders;
+
+static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
+{
+ GLint shader = glCreateShader( gliShaderType );
+
+ 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 );
+
+ GLint status;
+ glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
+
+ if( status != GL_TRUE )
+ {
+ GLchar info[1024];
+ GLsizei len;
+
+ glGetShaderInfoLog( shader, sizeof(info), &len, info );
+ vg_error( "Error info:\n%s\n", info );
+ return 0;
+ }
+
+ return shader;
+}
+
+int vg_shader_compile( struct vg_shader *shader )
+{
+ GLuint program, vert, frag;
+
+ /* 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).
+ */
+
+ int use_source_files = 0;
+ if( shader->compiled ){
+ if( shader->vs.orig_file && shader->fs.orig_file ){
+ use_source_files = 1;
+ }
+ else {
+ vg_warn( "No source files for shader '%s'\n", shader->name );
+ return 1;
+ }
+ }
+
+ vg_info( "Compile shader '%s'\n", shader->name );
+
+ if( use_source_files ){
+ char error[260];
+ char path[260];
+
+ strcpy( path, "../../" );
+ strcat( path, shader->vs.orig_file );
+ char *vertex_src = stb_include_file( path, "", "../../shaders", error );
+
+ strcpy( path, "../../" );
+ strcat( path, shader->fs.orig_file );
+ char *fragment_src = stb_include_file( path, "", "../../shaders", error );
+
+ if( !vertex_src || !fragment_src ){
+ const char *errstr = "Could not find shader source files (%s)\n";
+ if( shader->compiled ){
+ vg_warn( errstr, shader->vs.orig_file );
+ free( vertex_src );
+ free( fragment_src );
+ return 1;
+ }
+ else{
+ vg_error( errstr, shader->vs.orig_file );
+ free( vertex_src );
+ free( fragment_src );
+ return 0;
+ }
+ }
+
+ vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER );
+ frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER );
+
+ free( vertex_src );
+ free( fragment_src );
+ }
+ else{
+ vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER );
+ frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER );
+ }
+
+ if( !vert || !frag )
+ return 0;
+
+ program = glCreateProgram();
+
+ glAttachShader( program, vert );
+ glAttachShader( program, frag );
+ glLinkProgram( program );
+
+ glDeleteShader( vert );
+ glDeleteShader( frag );
+
+ /* Check for link errors */
+ char infoLog[ 512 ];
+ int success_link = 1;
+
+ glGetProgramiv( program, GL_LINK_STATUS, &success_link );
+ if( !success_link )
+ {
+ glGetProgramInfoLog( program, 512, NULL, infoLog );
+ vg_error( "Link failed: %s\n", infoLog );
+ glDeleteProgram( program );
+ return 0;
+ }
+
+ if( shader->compiled )
+ glDeleteProgram( shader->id );
+
+ shader->id = program;
+ shader->compiled = 1;
+ if( shader->link )
+ shader->link();
+ return 1;
+}
+
+static void vg_free_shader( struct vg_shader *shader )
+{
+ if( shader->compiled )
+ {
+ glDeleteProgram( shader->id );
+ shader->compiled = 0;
+ }
+}
+
+void vg_shaders_compile(void)
+{
+ vg_info( "Compiling shaders\n" );
+
+ for( int i=0; i<vg_shaders.count; i ++ ){
+ vg_shader *shader = vg_shaders.shaders[i];
+
+ if( !vg_shader_compile( shader ) )
+ vg_fatal_error( "Failed to compile shader" );
+ }
+}
+
+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;
+}
+
+void vg_shader_register( struct vg_shader *shader )
+{
+ if( vg_shaders.count == vg_list_size(vg_shaders.shaders) )
+ vg_fatal_error( "Too many shaders" );
+
+ shader->compiled = 0;
+ shader->id = 0; /* TODO: make this an error shader */
+ vg_shaders.shaders[ vg_shaders.count ++ ] = shader;
+}