medfall

A super great game engine
Log | Files | Refs

shaders.cc (3710B)


      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 
      4 #include "intrinsics.h"
      5 #include "array.h"
      6 #include "renderer.h"
      7 #include "shaders.h"
      8 
      9 struct HotloadShader {
     10 	const char * path = NULL;
     11 	Shader shader = { };
     12 	time_t last_modified = 0;
     13 };
     14 
     15 struct ShaderInclude {
     16 	const char * path = NULL;
     17 	char * contents = NULL;
     18 	time_t last_modified = 0;
     19 };
     20 
     21 static StaticArray< ShaderInclude, 64 > includes;
     22 static StaticArray< HotloadShader, SHADER_COUNT > shaders;
     23 
     24 static time_t file_last_write_time( const char * path ) {
     25 	struct stat buf;
     26 	if( stat( path, &buf ) == -1 ) {
     27 		return 0;
     28 	}
     29 
     30 	return buf.st_mtime;
     31 }
     32 
     33 void shaders_init() {
     34 	includes[ 0 ].path = "shaders/common.glsl";
     35 	includes[ 1 ].path = "shaders/pbr.glsl";
     36 
     37 	shaders[ SHADER_TEXT ].path = "shaders/text.glsl";
     38 
     39 	shaders[ SHADER_MSDF ].path = "shaders/msdf.glsl";
     40 
     41 	shaders[ SHADER_SKYBOX ].path = "shaders/skybox.glsl";
     42 
     43 	shaders[ SHADER_FLAT_VERTEX_COLOURS ].path = "shaders/flat_vertex_colours.glsl";
     44 
     45 	shaders[ SHADER_FLAT_TEXTURED ].path = "shaders/flat_textured.glsl";
     46 
     47 	shaders[ SHADER_UI ].path = "shaders/ui.glsl";
     48 
     49 	shaders[ SHADER_TREE ].path = "shaders/tree.glsl";
     50 
     51 	shaders[ SHADER_WRITE_SHADOW_MAP ].path = "shaders/write_shadow_map.glsl";
     52 
     53 	shaders[ SHADER_DEBUG_RENDER_SHADOW_MAP ].path = "shaders/debug_render_shadow_map.glsl";
     54 
     55 	shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].path = "shaders/shadowed_vertex_colours.glsl";
     56 
     57 	shaders[ SHADER_WIREFRAME ].path = "shaders/wireframe.glsl";
     58 
     59 	shaders[ SHADER_CLIPMAP ].path = "shaders/clipmap.glsl";
     60 
     61 	shaders[ SHADER_CLIPMAP_SKIRT ].path = "shaders/clipmap_skirt.glsl";
     62 
     63 	shaders[ SHADER_SHADOWED_VERTEX_COLOURS_TO_GBUFFER ].path = "shaders/shadowed_vertex_colours_to_gbuffer.glsl";
     64 
     65 	shaders[ SHADER_FLAT_VERTEX_COLOURS_TO_GBUFFER ].path = "shaders/flat_vertex_colours_to_gbuffer.glsl";
     66 
     67 	shaders[ SHADER_GBUFFER ].path = "shaders/gbuffer.glsl";
     68 
     69 	shaders[ SHADER_DEPTH_EDGE ].path = "shaders/depth_edge.glsl";
     70 
     71 	shaders[ SHADER_SKINNED_FLAT_VERTEX_COLOURS ].path = "shaders/skinned_flat_vertex_colours.glsl";
     72 
     73 	int failed = hotload_shaders();
     74 	if( failed != 0 ) {
     75 		FATAL( "failed to load shaders" );
     76 	}
     77 }
     78 
     79 const Shader * get_shader( ShaderID id ) {
     80 	return &shaders[ id ].shader;
     81 }
     82 
     83 void shaders_term() {
     84 	for( HotloadShader & shader : shaders ) {
     85 		renderer_delete_shader( shader.shader );
     86 	}
     87 }
     88 
     89 static void reload_include( ShaderInclude & include, time_t t ) {
     90 	if( include.contents != NULL ) {
     91 		free( include.contents );
     92 	}
     93 
     94 	include.contents = ( char * ) file_get_contents( include.path );
     95 	include.last_modified = t;
     96 }
     97 
     98 static bool reload_shader( HotloadShader & shader, time_t t ) {
     99 	INFO( "loading {}", shader.path );
    100 	char * contents = ( char * ) file_get_contents( shader.path );
    101 
    102 	StaticArray< const char *, 8 > srcs;
    103 
    104 	size_t n = 0;
    105 	for( ShaderInclude & include : includes ) {
    106 		if( include.contents == NULL ) break;
    107 		srcs[ n ] = include.contents;
    108 		n++;
    109 	}
    110 	srcs[ n ] = contents;
    111 	n++;
    112 
    113 	Shader new_shader = renderer_new_shader( srcs.slice( 0, n ) );
    114 
    115 	if( new_shader.program != 0 ) {
    116 		renderer_delete_shader( shader.shader );
    117 		shader.shader = new_shader;
    118 	}
    119 	else {
    120 		return false;
    121 	}
    122 
    123 	shader.last_modified = t;
    124 
    125 	free( contents );
    126 
    127 	return true;
    128 }
    129 
    130 int hotload_shaders() {
    131 	int failed = 0;
    132 	bool reload_all = false;
    133 
    134 	for( ShaderInclude & include : includes ) {
    135 		if( include.path == NULL ) break;
    136 
    137 		time_t t = file_last_write_time( include.path );
    138 		if( t > include.last_modified ) {
    139 			reload_all = true;
    140 			reload_include( include, t );
    141 		}
    142 	}
    143 
    144 	for( HotloadShader & shader : shaders ) {
    145 		time_t t = file_last_write_time( shader.path );
    146 		if( reload_all || t > shader.last_modified ) {
    147 			if( !reload_shader( shader, t ) ) {
    148 				failed++;
    149 			}
    150 		}
    151 	}
    152 	return failed;
    153 }