ff8a5f0dc143c6126167394579fc4cced7922499
[fishladder.git] / vg / vg_shader.h
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 const char *vg_shader_gl_ver = "#version 330 core\n";
4
5 #pragma GCC diagnostic push
6 #pragma GCC diagnostic ignored "-Wreturn-type"
7 static inline int static_str_index( const char *list[], int len, const char *str )
8 {
9 for( int i = 0; i < len; i ++ )
10 {
11 if( !strcmp(list[i],str) )
12 return i;
13 }
14
15 #ifndef VG_RELEASE
16 fprintf( stderr, "That was not a static string index!! (%s)\n", str );
17 abort();
18 #endif
19 }
20 #pragma GCC diagnostic pop
21
22 #define SHADER_NAME( NAME ) (NAME##_static_shader.program)
23 #define SHADER_USE( NAME ) glUseProgram( NAME##_static_shader.program )
24
25 #define SHADER_UNIFORM( NAME, U ) NAME##_shader_uniforms[ STR_STATIC_INDEX( NAME##_shader_names, U ) ]
26 #define SHADER_UNIFORM_NAME( NAME, UID ) NAME##_shader_names[ UID ]
27 #define STR_STATIC_INDEX( LIST, STR ) static_str_index( LIST, vg_list_size(LIST), STR )
28
29 #define UNIFORMS(...) __VA_ARGS__
30
31 #define SHADER_DEFINE( NAME, VERT, FRAG, UNIFORMS ) \
32 const char * NAME##_shader_names[] = UNIFORMS; \
33 GLint NAME##_shader_uniforms[ vg_list_size( NAME##_shader_names ) ]; \
34 struct vg_shader NAME##_static_shader = { \
35 .src_vert = VERT, .src_frag = FRAG, \
36 .sym = #NAME "_static.shader", \
37 .uniform_names = NAME##_shader_names, \
38 .uniforms = NAME##_shader_uniforms, \
39 .uniform_count = vg_list_size( NAME##_shader_names ), \
40 };
41
42 #define SHADER_INIT( NAME ) arrpush( vg_shaders_active, &NAME##_static_shader )
43
44 #define SHADER_STATUS_NONE 0x00
45 #define SHADER_STATUS_COMPILED 0x1
46
47 struct vg_shader
48 {
49 GLuint program;
50
51 const char *src_vert;
52 const char *src_frag;
53 const char *src_geo;
54 const char *sym;
55
56 const char **uniform_names;
57 GLint *uniforms;
58 u32 uniform_count;
59 u32 status;
60 }
61 ** vg_shaders_active = NULL;
62
63 static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
64 {
65 GLint shader = glCreateShader( gliShaderType );
66 glShaderSource( shader, 2, (const char *[2]){ vg_shader_gl_ver, src }, NULL );
67 glCompileShader( shader );
68
69 int success;
70 char infoLog[512];
71 glGetShaderiv( shader, GL_COMPILE_STATUS, &success );
72
73 if( !success )
74 {
75 glGetShaderInfoLog( shader, 512, NULL, infoLog );
76 vg_error( "Error info:\n%s\n", infoLog );
77 return 0;
78 }
79
80 return shader;
81 }
82
83 static int vg_shader_compile( struct vg_shader *shader )
84 {
85 vg_info( "Compile shader '%s'\n", shader->sym );
86
87 GLuint vert, frag, geo = 0;
88
89 vert = vg_shader_subshader( shader->src_vert, GL_VERTEX_SHADER );
90 frag = vg_shader_subshader( shader->src_frag, GL_FRAGMENT_SHADER );
91
92 if( !vert || !frag )
93 return 0;
94
95 if( shader->src_geo )
96 {
97 geo = vg_shader_subshader( shader->src_geo, GL_GEOMETRY_SHADER );
98
99 if( !geo )
100 return 0;
101 }
102
103 shader->program = glCreateProgram();
104 if( geo )
105 glAttachShader( shader->program, geo );
106
107 glAttachShader( shader->program, vert );
108 glAttachShader( shader->program, frag );
109 glLinkProgram( shader->program );
110
111 glDeleteShader( vert );
112 glDeleteShader( frag );
113
114 if( geo )
115 glDeleteShader( geo );
116
117 // Check for link errors
118 char infoLog[ 512 ];
119 int success_link = 1;
120
121 glGetProgramiv( shader->program, GL_LINK_STATUS, &success_link );
122 if( !success_link )
123 {
124 glGetProgramInfoLog( shader->program, 512, NULL, infoLog );
125 vg_error( "Link failed: %s\n", infoLog );
126 glDeleteProgram( shader->program );
127
128 return 0;
129 }
130
131 // Complete linkeage
132 for( int i = 0; i < shader->uniform_count; i ++ )
133 shader->uniforms[ i ] = glGetUniformLocation( shader->program, shader->uniform_names[i] );
134
135 shader->status |= SHADER_STATUS_COMPILED;
136 return 1;
137 }
138
139 static void vg_shaders_free(void)
140 {
141 for( int i = 0; i < arrlen( vg_shaders_active ); i ++ )
142 {
143 struct vg_shader *shader = vg_shaders_active[i];
144
145 if( shader->status & SHADER_STATUS_COMPILED )
146 glDeleteProgram( shader->program );
147 }
148
149 arrfree( vg_shaders_active );
150 }
151
152 static int vg_shaders_compile(void)
153 {
154 vg_info( "Compiling shaders\n" );
155
156 for( int i = 0; i < arrlen( vg_shaders_active ); i ++ )
157 {
158 struct vg_shader *shader = vg_shaders_active[i];
159 if( !vg_shader_compile( shader ) )
160 {
161 vg_shaders_free();
162 return 0;
163 }
164 }
165
166 vg_register_exit( &vg_shaders_free, "vg_shaders_free" );
167 return 1;
168 }