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