revision 2
[vg.git] / vg_shader.c
1 /* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
2
3 #pragma once
4 #include "vg_platform.h"
5 #include "vg_shader.h"
6 #include "vg_engine.h"
7
8 #define STB_INCLUDE_IMPLEMENTATION
9 #define STB_INCLUDE_LINE_GLSL
10 #define STB_MALLOC vg_alloc
11 #define STB_FREE vg_free
12 #define STB_REALLOC vg_realloc
13 #include "submodules/stb/stb_include.h"
14
15 const char *vg_shader_gl_ver = "#version 330 core\n";
16
17 struct vg_shaders vg_shaders;
18
19 static GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
20 {
21 GLint shader = glCreateShader( gliShaderType );
22
23 if( shader == GL_NONE )
24 {
25 vg_error( "Could not 'glCreateShader()'\n" );
26 return 0;
27 }
28
29 glShaderSource( shader, 2, (const char*[2]){ vg_shader_gl_ver, src }, NULL );
30 glCompileShader( shader );
31
32 GLint status;
33 glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
34
35 if( status != GL_TRUE )
36 {
37 GLchar info[1024];
38 GLsizei len;
39
40 glGetShaderInfoLog( shader, sizeof(info), &len, info );
41 vg_error( "Error info:\n%s\n", info );
42 return 0;
43 }
44
45 return shader;
46 }
47
48 int vg_shader_compile( struct vg_shader *shader )
49 {
50 GLuint program, vert, frag;
51
52 /* If we are compiling this again, we obviously need to try to take the src
53 * from the disk instead.
54 *
55 * Only do this if we have filenames set on the shader, so engine shaders
56 * dont have to do it (text.. etc).
57 */
58
59 int use_source_files = 0;
60 if( shader->compiled ){
61 if( shader->vs.orig_file && shader->fs.orig_file ){
62 use_source_files = 1;
63 }
64 else {
65 vg_warn( "No source files for shader '%s'\n", shader->name );
66 return 1;
67 }
68 }
69
70 vg_info( "Compile shader '%s'\n", shader->name );
71
72 if( use_source_files ){
73 char error[260];
74 char path[260];
75
76 strcpy( path, "../../" );
77 strcat( path, shader->vs.orig_file );
78 char *vertex_src = stb_include_file( path, "", "../../shaders", error );
79
80 strcpy( path, "../../" );
81 strcat( path, shader->fs.orig_file );
82 char *fragment_src = stb_include_file( path, "", "../../shaders", error );
83
84 if( !vertex_src || !fragment_src ){
85 const char *errstr = "Could not find shader source files (%s)\n";
86 if( shader->compiled ){
87 vg_warn( errstr, shader->vs.orig_file );
88 free( vertex_src );
89 free( fragment_src );
90 return 1;
91 }
92 else{
93 vg_error( errstr, shader->vs.orig_file );
94 free( vertex_src );
95 free( fragment_src );
96 return 0;
97 }
98 }
99
100 vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER );
101 frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER );
102
103 free( vertex_src );
104 free( fragment_src );
105 }
106 else{
107 vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER );
108 frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER );
109 }
110
111 if( !vert || !frag )
112 return 0;
113
114 program = glCreateProgram();
115
116 glAttachShader( program, vert );
117 glAttachShader( program, frag );
118 glLinkProgram( program );
119
120 glDeleteShader( vert );
121 glDeleteShader( frag );
122
123 /* Check for link errors */
124 char infoLog[ 512 ];
125 int success_link = 1;
126
127 glGetProgramiv( program, GL_LINK_STATUS, &success_link );
128 if( !success_link )
129 {
130 glGetProgramInfoLog( program, 512, NULL, infoLog );
131 vg_error( "Link failed: %s\n", infoLog );
132 glDeleteProgram( program );
133 return 0;
134 }
135
136 if( shader->compiled )
137 glDeleteProgram( shader->id );
138
139 shader->id = program;
140 shader->compiled = 1;
141 return 1;
142 }
143
144 static void vg_free_shader( struct vg_shader *shader )
145 {
146 if( shader->compiled )
147 {
148 glDeleteProgram( shader->id );
149 shader->compiled = 0;
150 }
151 }
152
153 #ifdef VG_CUSTOM_SHADERS
154 void vg_auto_shader_link(void);
155 #endif
156
157 void vg_shaders_compile(void)
158 {
159 vg_info( "Compiling shaders\n" );
160
161 for( int i=0; i<vg_shaders.count; i ++ ){
162 vg_shader *shader = vg_shaders.shaders[i];
163
164 if( !vg_shader_compile( shader ) )
165 vg_fatal_error( "Failed to compile shader" );
166 }
167
168 #ifdef VG_CUSTOM_SHADERS
169 vg_auto_shader_link();
170 #endif
171 }
172
173 int vg_shaders_live_recompile(int argc, const char *argv[])
174 {
175 vg_info( "Recompiling shaders\n" );
176 for( int i=0; i<vg_shaders.count; i ++ )
177 {
178 struct vg_shader *shader = vg_shaders.shaders[i];
179 vg_shader_compile( shader );
180 }
181
182 return 0;
183 }
184
185 void vg_shader_register( struct vg_shader *shader )
186 {
187 if( vg_shaders.count == vg_list_size(vg_shaders.shaders) )
188 vg_fatal_error( "Too many shaders" );
189
190 shader->compiled = 0;
191 shader->id = 0; /* TODO: make this an error shader */
192 vg_shaders.shaders[ vg_shaders.count ++ ] = shader;
193 }