1#include <cgv/base/base.h>
2#include "shader_program.h"
3#include <cgv/utils/file.h>
4#include <cgv/utils/dir.h>
7#include <cgv/utils/tokenizer.h>
8#include <cgv/base/import.h>
16std::map<std::string, std::vector<std::string>> shader_program::files_cache;
20 bool get_location,
bool get_value)
22 ctx.shader_program_inspect_variables(*
this, kind, Vs, get_location, get_value);
29 for(
unsigned int i = 0; i < file_names.size(); ++i) {
30 no_error =
attach_file(ctx, file_names[i], ST_DETECT, options) && no_error;
39 auto it = files_cache.find(name);
40 if(it != files_cache.end()) {
41 const std::vector<std::string>& cached_file_names = it->second;
42 for(
size_t i = 0; i < cached_file_names.size(); ++i)
43 file_names.push_back(cached_file_names[i]);
45 added_files = !cached_file_names.empty();
56 bool added_files =
false;
61 std::vector<std::string> collected_file_names;
67 file_names.push_back(fn);
69 collected_file_names.push_back(fn);
74 files_cache.emplace(file_name, collected_file_names);
82 bool added_files =
false;
87 std::vector<std::string> collected_file_names;
89 const char* exts[] = {
"glvs",
"glgs",
"glfs",
"glcs",
"gltc",
"glte",
"pglvs",
"pglfs",
"pglgs",
"pglcs",
"pgltc",
"pglte", 0 };
90 const char** iter = exts;
91 bool added_file =
false;
95 file_names.push_back(fn);
98 collected_file_names.push_back(fn);
105 std::cerr <<
"could not find shader file " << base_name.c_str() << std::endl;
108 files_cache.emplace(base_name, collected_file_names);
115 std::string dn = dir_name;
116 if (!dir::exists(dn)) {
125 void* handle = file::find_first(dn+
"/*.gl*");
129 file_names.push_back(dir_name+
"/"+file::find_name(handle));
130 handle = file::find_next(handle);
146 std::vector<line> lines;
148 bool added_file =
false;
150 std::string path = file::get_path(file_name);
154 for (
auto line : lines) {
156 if (l.substr(0,5) ==
"file:")
157 added_file =
collect_file(l.substr(5), use_cache, file_names) || added_file;
158 else if (l.substr(0,12) ==
"vertex_file:")
159 added_file =
collect_file(l.substr(12), use_cache, file_names) || added_file;
160 else if (l.substr(0, 14) ==
"geometry_file:")
161 added_file =
collect_file(l.substr(14), use_cache, file_names) || added_file;
162 else if (l.substr(0, 26) ==
"tessellation_control_file:")
163 added_file =
collect_file(l.substr(26), use_cache, file_names) || added_file;
164 else if (l.substr(0, 29) ==
"tessellation_evaluation_file:")
165 added_file =
collect_file(l.substr(29), use_cache, file_names) || added_file;
166 else if (l.substr(0,14) ==
"fragment_file:")
167 added_file =
collect_file(l.substr(14), use_cache, file_names) || added_file;
168 else if (l.substr(0,6) ==
"files:")
169 added_file =
collect_files(l.substr(6), use_cache, file_names) || added_file;
170 else if (l.substr(0,4) ==
"dir:")
171 added_file =
collect_dir(l.substr(4),
false, file_names) || added_file;
172 else if (l.substr(0,8) ==
"rec_dir:")
173 added_file =
collect_dir(l.substr(8),
true, file_names) || added_file;
174 else if (l.substr(0,8) ==
"program:")
175 added_file =
collect_program(l.substr(8), use_cache, file_names) || added_file;
185 show_code_errors = _show_code_errors;
187 state_out_of_date =
true;
188 nr_attached_geometry_shaders = 0;
198 std::cerr <<
"could not destruct shader program properly" << std::endl;
204 state_out_of_date =
true;
205 nr_attached_geometry_shaders = 0;
212 return ctx.shader_program_create(*
this);
219 last_error =
"attach_code to shader program that was not created";
223 last_error =
"attempt to attach_code that is not created to shader program";
227 last_error =
"attempt to attach_code that is not compiled to shader program";
230 ctx.shader_program_attach(*
this, code);
232 ++nr_attached_geometry_shaders;
239 last_error =
"detach_code from shader program that was not created";
243 last_error =
"attempt to detach_code that is not created to shader program";
246 ctx.shader_program_detach(*
this, code);
248 --nr_attached_geometry_shaders;
257 managed_codes.push_back(code_ptr);
269 if(!code_ptr->
read_and_compile(ctx, file_name, st, options, show_code_errors)) {
274 managed_codes.push_back(code_ptr);
280 std::vector<std::string> file_names;
287 std::vector<std::string> file_names;
311 *last_error_ptr =
"could not find shader program file " + file_name;
316 *last_error_ptr =
"could not read shader program file " + file_name;
327 std::vector<line> lines;
328 std::vector<shader_compile_options> result;
331 for (
unsigned int i = 0; i < lines.size(); ++i) {
332 token tok = lines[i];
336 if (l.empty() || l[0] ==
'/')
338 if (l.substr(0, 9) !=
"instance:")
340 std::string defs=l.substr(9);
341 std::vector<token> toks;
344 for (
const auto& t : toks) {
345 std::vector<token> sides;
347 std::vector<std::string> S;
348 for (
auto& s : sides) {
349 while (s.begin < s.end &&
is_space(*s.begin))
351 while (s.begin < s.end &&
is_space(s.end[-1]))
359 result.push_back(options);
367 std::vector<line> lines;
373 std::cout <<
"read shader program <" << file_name <<
">" << std::endl;
375 std::string path = file::get_path(file_name);
379 bool no_error =
true;
380 std::string error =
"2 : attach command failed";
381 for (
unsigned int i=0; i<lines.size(); ++i) {
382 token tok = lines[i];
394 if (l.substr(0,5) ==
"file:")
395 success =
attach_file(ctx, l.substr(5), ST_DETECT, options);
396 else if (l.substr(0,12) ==
"vertex_file:")
397 success =
attach_file(ctx, l.substr(12), ST_VERTEX, options);
398 else if (l.substr(0,14) ==
"geometry_file:")
399 success =
attach_file(ctx, l.substr(14), ST_GEOMETRY, options);
400 else if (l.substr(0, 26) ==
"tessellation_control_file:")
401 success =
attach_file(ctx, l.substr(26), ST_TESS_CONTROL, options);
402 else if (l.substr(0, 29) ==
"tessellation_evaluation_file:")
403 success =
attach_file(ctx, l.substr(29), ST_TESS_EVALUATION, options);
404 else if (l.substr(0,14) ==
"fragment_file:")
405 success =
attach_file(ctx, l.substr(14), ST_FRAGMENT, options);
406 else if(l.substr(0, 13) ==
"compute_file:")
407 success =
attach_file(ctx, l.substr(13), ST_COMPUTE, options);
408 else if (l.substr(0,6) ==
"files:")
410 else if (l.substr(0,4) ==
"dir:")
411 success =
attach_dir(ctx, l.substr(4),
false);
412 else if (l.substr(0,8) ==
"rec_dir:")
414 else if (l.substr(0,8) ==
"program:")
416 else if (l.substr(0,21) ==
"geometry_shader_info:") {
417 std::vector<token> toks;
418 std::string l1 = l.substr(21);
420 if (toks.size() == 3) {
423 for (pi = PT_UNDEF+1; pi < PT_LAST; ++pi) {
431 if (i_pt == PT_UNDEF) {
432 error =
"4 : unknown input_type for geometry shader <";
436 else if (o_pt == PT_UNDEF) {
437 error =
"5 : unknown ouput_type for geometry shader <";
441 else if (!
is_integer(toks[2].begin,toks[2].end,count)) {
442 error =
"6 : max_output_count of geometry shader must be an integer but received <";
452 error =
"3 : geometry_shader_info takes three arguments separated by colons";
455 else if (l.substr(0, 9) ==
"instance:") {
457 else if (show_error) {
458 std::cerr << file_name.c_str() <<
" (" << i + 1
459 <<
"): warning G0001 : syntax error in line '"
460 << l.c_str() <<
"'" << std::endl;
464 std::cerr << file_name.c_str() <<
" (" << i+1
465 <<
"): error G000" << error.c_str() << std::endl;
472 if (show_error && !no_error)
479 return build_files(ctx, base_name, {}, show_error);
484 return build_dir(ctx, dir_name, {}, recursive, show_error);
500 attach_dir(ctx, dir_name, recursive, options) &&
link(ctx, show_error);
511 if(!
link(ctx, show_error)) {
514 std::vector<line> lines;
516 std::string formated_error;
517 for(
unsigned int i = 0; i < lines.size(); ++i) {
518 formated_error += fn +
"(1) : error G0002: " +
to_string(lines[i]) +
"\n";
520 std::cerr << formated_error.c_str() << std::endl;
537 if (state_out_of_date) {
538 if (nr_attached_geometry_shaders > 0) {
539 if (geometry_shader_output_count < 1)
541 ctx.shader_program_set_state(*
this);
543 state_out_of_date =
false;
551 if (ctx.shader_program_link(*
this)) {
552 ctx.shader_program_set_uniform_locations(*
this);
559 std::cerr <<
"link error:\n" <<
last_error.c_str() << std::endl;
572 geometry_shader_input_type = input_type;
573 geometry_shader_output_type = output_type;
574 geometry_shader_output_count = max_output_count;
575 state_out_of_date =
true;
582 ctx.
error(
"attempt to enable shader_program that is not created",
this);
586 ctx.
error(
"attempt to enable shader_program that is not linked",
this);
590 ctx.
error(
"attempt to enable shader_program that is already enabled or was not disabled properly",
this);
594 bool res = ctx.shader_program_enable(*
this);
596 shader_program_base::is_enabled =
true;
604 ctx.
error(
"attempt to disable shader_program that is not enabled",
this);
607 bool res = ctx.shader_program_disable(*
this);
608 shader_program_base::is_enabled =
false;
615 return uniform_locations;
625 auto it = uniform_locations.find(name);
626 return it != uniform_locations.end() ? it->second : -1;
631 bool res =
set_uniform(ctx, name +
".brdf_type",
static_cast<int>(material.
brdf_type), generate_error);
648 const char* texture_names[] = {
649 "tex0",
"tex1",
"tex2",
"tex3",
"tex4",
"tex5"
652 if (!
set_uniform(ctx, texture_names[i], i, generate_error))
672 if (!
set_uniform(ctx, name +
".light_source_type",
static_cast<int>(L.get_type()), generate_error))
674 if (!
set_uniform(ctx, name +
".position", L.get_position(), generate_error))
676 if (!
set_uniform(ctx, name +
".emission", L.get_emission(), generate_error))
678 if (!
set_uniform(ctx, name +
".ambient_scale", L.get_ambient_scale(), generate_error))
680 if (!
set_uniform(ctx, name +
".spot_direction", L.get_spot_direction(), generate_error))
682 if (!
set_uniform(ctx, name +
".spot_exponent", L.get_spot_exponent(), generate_error))
684 if (!
set_uniform(ctx, name +
".spot_cos_cutoff", cos(0.01745329252f*L.get_spot_cutoff()), generate_error))
686 if (!
set_uniform(ctx, name +
".constant_attenuation", L.get_constant_attenuation(), generate_error))
688 if (!
set_uniform(ctx, name +
".linear_attenuation", L.get_linear_attenuation(), generate_error))
690 if (!
set_uniform(ctx, name +
".quadratic_attenuation", L.get_quadratic_attenuation(), generate_error))
698 return ctx.get_attribute_location(*
this, name);
704 while (managed_codes.size() > 0) {
705 delete managed_codes.back();
706 managed_codes.pop_back();
709 ctx.shader_program_destruct(*
this);
713 state_out_of_date =
true;
714 auto_detect_uniforms =
true;
715 auto_detect_vertex_attributes =
true;
716 nr_attached_geometry_shaders = 0;
More advanced text processing for splitting text into lines or tokens.
bool empty() const
check if pointer is not yet set
int metalness_index
index of image from which metalness should be mapped, -1 corresponds to no mapping
int transparency_index
index of image from which transparency should be mapped, -1 corresponds to no mapping
bool sRGBA_textures
whether textures are in sRGB format
int roughness_index
index of image from which roughness should be mapped, -1 corresponds to no mapping
int specular_index
index of image from which specular_reflectance should be mapped, -1 corresponds to no mapping
int ambient_index
index of image from which ambient_occlusion should be mapped, -1 corresponds to no mapping
int emission_index
index of image from which emission should be mapped, -1 corresponds to no mapping
int bump_index
index of image from which bumps should be mapped, -1 corresponds to no mapping
int diffuse_index
index of image from which diffuse_reflectance should be mapped, -1 corresponds to no mapping
base class for all drawables, which is independent of the used rendering API.
virtual void error(const std::string &message, const render_component *rc=0) const
error handling
bool is_shader_file_cache_enabled() const
whether the shader file caches are enabled
virtual bool make_current() const =0
make the current context current if possible
virtual bool is_created() const
return whether component has been created
const context * ctx_ptr
keep pointer to my context
std::string last_error
a string that contains the last error
a shader code object holds a code fragment of a geometry vertex or fragment shader and can be added t...
static std::string find_file(const std::string &file_name, bool search_exhaustive=false)
Find the full path to a shader by its file name.
ShaderType get_shader_type() const
return the shader type of this code
bool is_compiled() const
return whether shader has been compiled successfully
static void decode_if_base64(std::string &content)
decode a string if it is base64 encoded
bool compile(const context &ctx)
compile attached source; returns true if successful
bool set_code(const context &ctx, const std::string &source, ShaderType st)
set shader code from string
bool read_and_compile(const context &ctx, const std::string &file_name, ShaderType st=ST_DETECT, const shader_compile_options &options={}, bool show_error=true)
read shader code with read_code and compile.
Stores preprocessor options used for conditionally compiling shader programs.
void define_macro(const std::string &identifier)
Define a macro as identifier and no replacement text.
bool enable(context &ctx)
enable the shader program
bool disable(context &ctx)
disable shader program and restore fixed functionality
static bool collect_file(const std::string &file_name, bool use_cache, std::vector< std::string > &file_names)
resolve file name with shader_code::find_file and add file to list if found
shader_program(bool _show_code_errors=false)
create empty shader program and set the option whether errors during shader code attachment should be...
static std::map< std::string, std::string > program_file_cache
maps used to cache program file contents and valid file names indexed by their respective file name
bool set_uniform(const context &ctx, const std::string &name, const T &value, bool generate_error=false)
Set the value of a uniform by name, where the type can be any of int, unsigned, float,...
static unsigned int get_max_nr_geometry_shader_output_vertices(const context &ctx)
return the maximum number of output vertices of a geometry shader
~shader_program()
call destruct method
static bool collect_files_from_cache(const std::string &name, std::vector< std::string > &file_names, bool &added_files)
resolve file name with shader_code::find_file and add file to list if found
bool attach_dir(const context &ctx, const std::string &dir_name, bool recursive, const shader_compile_options &options={})
collect shader code files from directory, compile and attach.
void destruct(const context &ctx)
destruct shader program
bool build_dir(const context &ctx, const std::string &dir_name, bool recursive=false, bool show_error=false)
successively calls create, attach_dir and link.
static bool open_program_file(std::string &file_name, bool use_cache, std::string &content, std::vector< cgv::utils::line > &lines, std::string *last_error_ptr=0)
common code necessary to open file
bool detach_code(const context &ctx, const shader_code &code)
detach a shader code
bool attach_program(const context &ctx, std::string file_name, bool show_error=false, const shader_compile_options &options={})
collect shader code files declared in shader program file, compile and attach them
static bool collect_files(const std::string &base_name, bool use_cache, std::vector< std::string > &file_names)
collect shader code files that extent the given base name.
int get_attribute_location(const context &ctx, const std::string &name) const
query location index of an attribute
bool attach_code(const context &ctx, const shader_code &code)
attach a compiled shader code instance that is managed outside of program
void update_state(const context &ctx)
ensure that the state has been set in the context
void inspect_program_variables(const context &ctx, cgv::render::ProgramVariableKind kind, std::vector< cgv::render::program_variable_info > &Vs, bool get_location=true, bool get_value=true)
retrieve information on all uniform or attribute variables of a shader program
bool create(const context &ctx)
create the shader program
void set_geometry_shader_info(PrimitiveType input_type, PrimitiveType output_type, int max_output_count=0)
configure the geometry shader, if count < 1 set it to get_max_nr_geometry_shader_output_vertices
bool is_linked() const
return whether program is linked
bool link(const context &ctx, bool show_error=false)
link shaders to an executable program
bool build_program(const context &ctx, const std::string &file_name, bool show_error=false)
successively calls create, attach_program and link.
static bool collect_dir(const std::string &dir_name, bool recursive, std::vector< std::string > &file_names)
collect shader code files from directory.
bool is_enabled() const
check whether program is currently enabled
static std::vector< shader_compile_options > extract_instances(std::string file_name)
find and parse all instance definitions in a shader program file
bool attach_file(const context &ctx, const std::string &file_name, ShaderType st=ST_DETECT, const shader_compile_options &options={})
read shader code from file, compile and attach to program
bool set_textured_material_uniform(const context &ctx, const std::string &name, const textured_material &material, bool generate_error=false)
set a uniform of type textured_material
bool set_light_uniform(const context &ctx, const std::string &name, const cgv::media::illum::light_source &light, bool generate_error=false)
set a uniform of type light source
int get_uniform_location(const context &ctx, const std::string &name) const
query location index of an uniform
bool set_material_uniform(const context &ctx, const std::string &name, const cgv::media::illum::surface_material &material, bool generate_error=false)
set a uniform of type material
const std::map< std::string, int > & get_uniform_locations() const
return uniform name and location pairs
bool attach_files(const context &ctx, const std::vector< std::string > &file_names, const shader_compile_options &options={})
attach a list of files
bool build_files(const context &ctx, const std::string &base_name, bool show_error=false)
successively calls create, attach_files and link.
static bool collect_program(const std::string &file_name, bool use_cache, std::vector< std::string > &file_names)
collect shader code files declared in a shader program file.
class that extends obj_material with the management of textures
size_t get_nr_textures() const
virtual method to query number of textures
the tokenizer allows to split text into tokens in a convenient way.
tokenizer & set_ws(const std::string &ws)
set the list of white spaces, that separate tokens and are skipped
bool read_data_file(const std::string &file_name, std::string &content, bool ascii)
read ascii file into a string
shader_config_ptr get_shader_config()
return a reference to the current shader configuration
ProgramVariableKind
enumerates different kinds of shader program variables
ShaderType
different shader types
PrimitiveType
different primitive types
namespace that holds tools that dont fit any other namespace
void split_to_tokens(const char *begin, const char *end, std::vector< token > &tokens, const std::string &separators, bool merge_separators, const std::string &open_parenthesis, const std::string &close_parenthesis, const std::string &whitespaces, unsigned int max_nr_tokens)
this function splits a text range into tokens.
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
bool is_integer(const char *begin, const char *end, int &value)
check if the text range (begin,end( defines an integer value. If yes, store the value in the passed r...
void split_to_lines(const char *global_begin, const char *global_end, std::vector< line > &lines, bool truncate_trailing_spaces)
this function splits a text range at the newline characters into single lines.
bool is_space(char c)
check if char is a whitespace
cgv::math::fvec< float, 2 > vec2
declare type of 2d single precision floating point vectors
Helper functions to process strings.
int max_geometry_shader_output_vertex_count
the maximum supported size for renderbuffers in any dimension
a line in a text is simply represented as a token
representation of a token in a text by two pointers begin and end, that point to the first character ...
const char * begin
pointers that define the range of characters