X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=vg%2Fvg_shader.h;fp=vg%2Fvg_shader.h;h=ff8a5f0dc143c6126167394579fc4cced7922499;hb=6836e834f8db725e08015a98401f2be97e5b9849;hp=0000000000000000000000000000000000000000;hpb=b5740880fe3ffe59546bb80173ad3a6e1312648e;p=vg.git diff --git a/vg/vg_shader.h b/vg/vg_shader.h new file mode 100644 index 0000000..ff8a5f0 --- /dev/null +++ b/vg/vg_shader.h @@ -0,0 +1,168 @@ +// Copyright (C) 2021 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 ) + +#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 ) + +#define UNIFORMS(...) __VA_ARGS__ + +#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 ) + +#define SHADER_STATUS_NONE 0x00 +#define SHADER_STATUS_COMPILED 0x1 + +struct vg_shader +{ + 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; +} +** vg_shaders_active = NULL; + +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 ); + glCompileShader( shader ); + + int success; + char infoLog[512]; + glGetShaderiv( shader, GL_COMPILE_STATUS, &success ); + + if( !success ) + { + glGetShaderInfoLog( shader, 512, NULL, infoLog ); + vg_error( "Error info:\n%s\n", infoLog ); + return 0; + } + + return shader; +} + +static int vg_shader_compile( struct vg_shader *shader ) +{ + vg_info( "Compile shader '%s'\n", shader->sym ); + + GLuint vert, frag, geo = 0; + + vert = vg_shader_subshader( shader->src_vert, GL_VERTEX_SHADER ); + frag = vg_shader_subshader( shader->src_frag, GL_FRAGMENT_SHADER ); + + if( !vert || !frag ) + return 0; + + if( shader->src_geo ) + { + geo = vg_shader_subshader( shader->src_geo, GL_GEOMETRY_SHADER ); + + if( !geo ) + return 0; + } + + shader->program = glCreateProgram(); + if( geo ) + glAttachShader( shader->program, geo ); + + glAttachShader( shader->program, vert ); + glAttachShader( shader->program, frag ); + glLinkProgram( shader->program ); + + glDeleteShader( vert ); + glDeleteShader( frag ); + + if( geo ) + glDeleteShader( geo ); + + // Check for link errors + char infoLog[ 512 ]; + int success_link = 1; + + glGetProgramiv( shader->program, GL_LINK_STATUS, &success_link ); + if( !success_link ) + { + glGetProgramInfoLog( shader->program, 512, NULL, infoLog ); + vg_error( "Link failed: %s\n", infoLog ); + glDeleteProgram( shader->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; + return 1; +} + +static void vg_shaders_free(void) +{ + 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 ); +} + +static int vg_shaders_compile(void) +{ + vg_info( "Compiling shaders\n" ); + + for( int i = 0; i < arrlen( vg_shaders_active ); i ++ ) + { + struct vg_shader *shader = vg_shaders_active[i]; + if( !vg_shader_compile( shader ) ) + { + vg_shaders_free(); + return 0; + } + } + + vg_register_exit( &vg_shaders_free, "vg_shaders_free" ); + return 1; +}