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",
"glts",
"glms",
"pglvs",
"pglfs",
"pglgs",
"pglcs",
"pgltc",
"pglte",
"pglts",
"pglms", 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);
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, 10) ==
"task_file:")
161 added_file =
collect_file(l.substr(10), use_cache, file_names) || added_file;
162 else if(l.substr(0, 10) ==
"mesh_file:")
163 added_file =
collect_file(l.substr(10), use_cache, file_names) || added_file;
164 else if (l.substr(0, 14) ==
"geometry_file:")
165 added_file =
collect_file(l.substr(14), use_cache, file_names) || added_file;
166 else if (l.substr(0, 26) ==
"tessellation_control_file:")
167 added_file =
collect_file(l.substr(26), use_cache, file_names) || added_file;
168 else if (l.substr(0, 29) ==
"tessellation_evaluation_file:")
169 added_file =
collect_file(l.substr(29), use_cache, file_names) || added_file;
170 else if (l.substr(0,14) ==
"fragment_file:")
171 added_file =
collect_file(l.substr(14), use_cache, file_names) || added_file;
172 else if (l.substr(0,6) ==
"files:")
173 added_file =
collect_files(l.substr(6), use_cache, file_names) || added_file;
174 else if (l.substr(0,4) ==
"dir:")
175 added_file =
collect_dir(l.substr(4),
false, file_names) || added_file;
176 else if (l.substr(0,8) ==
"rec_dir:")
177 added_file =
collect_dir(l.substr(8),
true, file_names) || added_file;
178 else if (l.substr(0,8) ==
"program:")
179 added_file =
collect_program(l.substr(8), use_cache, file_names) || added_file;
189 show_code_errors = _show_code_errors;
191 state_out_of_date =
true;
192 nr_attached_geometry_shaders = 0;
202 std::cerr <<
"could not destruct shader program properly" << std::endl;
208 state_out_of_date =
true;
209 nr_attached_geometry_shaders = 0;
216 return ctx.shader_program_create(*
this);
223 last_error =
"attach_code to shader program that was not created";
227 last_error =
"attempt to attach_code that is not created to shader program";
231 last_error =
"attempt to attach_code that is not compiled to shader program";
234 ctx.shader_program_attach(*
this, code);
236 ++nr_attached_geometry_shaders;
243 last_error =
"detach_code from shader program that was not created";
247 last_error =
"attempt to detach_code that is not created to shader program";
250 ctx.shader_program_detach(*
this, code);
252 --nr_attached_geometry_shaders;
298 std::vector<std::string> file_names;
305 std::vector<std::string> file_names;
329 *last_error_ptr =
"could not find shader program file " + file_name;
334 *last_error_ptr =
"could not read shader program file " + file_name;
345 std::vector<line> lines;
346 std::vector<shader_compile_options> result;
349 for (
unsigned int i = 0; i < lines.size(); ++i) {
350 token tok = lines[i];
354 if (l.empty() || l[0] ==
'/')
356 if (l.substr(0, 9) !=
"instance:")
358 std::string defs=l.substr(9);
359 std::vector<token> toks;
362 for (
const auto& t : toks) {
363 std::vector<token> sides;
365 std::vector<std::string> S;
366 for (
auto& s : sides) {
367 while (s.begin < s.end &&
is_space(*s.begin))
369 while (s.begin < s.end &&
is_space(s.end[-1]))
377 result.push_back(options);
385 std::vector<line> lines;
391 std::cout <<
"read shader program <" << file_name <<
">" << std::endl;
393 std::string path = file::get_path(file_name);
397 bool no_error =
true;
398 std::string error =
"2 : attach command failed";
399 for (
unsigned int i=0; i<lines.size(); ++i) {
400 token tok = lines[i];
412 if (l.substr(0,5) ==
"file:")
413 success =
attach_file(ctx, l.substr(5), ST_DETECT, options);
414 else if (l.substr(0,12) ==
"vertex_file:")
415 success =
attach_file(ctx, l.substr(12), ST_VERTEX, options);
416 else if(l.substr(0, 10) ==
"task_file:")
417 success =
attach_file(ctx, l.substr(10), ST_TASK, options);
418 else if(l.substr(0, 10) ==
"mesh_file:")
419 success =
attach_file(ctx, l.substr(10), ST_MESH, options);
420 else if (l.substr(0,14) ==
"geometry_file:")
421 success =
attach_file(ctx, l.substr(14), ST_GEOMETRY, options);
422 else if (l.substr(0, 26) ==
"tessellation_control_file:")
423 success =
attach_file(ctx, l.substr(26), ST_TESS_CONTROL, options);
424 else if (l.substr(0, 29) ==
"tessellation_evaluation_file:")
425 success =
attach_file(ctx, l.substr(29), ST_TESS_EVALUATION, options);
426 else if (l.substr(0,14) ==
"fragment_file:")
427 success =
attach_file(ctx, l.substr(14), ST_FRAGMENT, options);
428 else if(l.substr(0, 13) ==
"compute_file:")
429 success =
attach_file(ctx, l.substr(13), ST_COMPUTE, options);
430 else if (l.substr(0,6) ==
"files:")
432 else if (l.substr(0,4) ==
"dir:")
433 success =
attach_dir(ctx, l.substr(4),
false);
434 else if (l.substr(0,8) ==
"rec_dir:")
436 else if (l.substr(0,8) ==
"program:")
438 else if (l.substr(0,21) ==
"geometry_shader_info:") {
439 std::vector<token> toks;
440 std::string l1 = l.substr(21);
442 if (toks.size() == 3) {
445 for (pi = PT_UNDEF+1; pi < PT_LAST; ++pi) {
453 if (i_pt == PT_UNDEF) {
454 error =
"4 : unknown input_type for geometry shader <";
458 else if (o_pt == PT_UNDEF) {
459 error =
"5 : unknown ouput_type for geometry shader <";
463 else if (!
is_integer(toks[2].begin,toks[2].end,count)) {
464 error =
"6 : max_output_count of geometry shader must be an integer but received <";
474 error =
"3 : geometry_shader_info takes three arguments separated by colons";
477 else if (l.substr(0, 9) ==
"instance:") {
479 else if (show_error) {
480 std::cerr << file_name.c_str() <<
" (" << i + 1
481 <<
"): warning G0001 : syntax error in line '"
482 << l.c_str() <<
"'" << std::endl;
486 std::cerr << file_name.c_str() <<
" (" << i+1
487 <<
"): error G000" << error.c_str() << std::endl;
494 if (show_error && !no_error)
501 return build_files(ctx, base_name, {}, show_error);
506 return build_dir(ctx, dir_name, {}, recursive, show_error);
522 attach_dir(ctx, dir_name, recursive, options) &&
link(ctx, show_error);
533 if(!
link(ctx, show_error)) {
536 std::vector<line> lines;
538 std::string formated_error;
539 for(
unsigned int i = 0; i < lines.size(); ++i) {
540 formated_error += fn +
"(1) : error G0002: " +
to_string(lines[i]) +
"\n";
542 std::cerr << formated_error.c_str() << std::endl;
559 if (state_out_of_date) {
560 if (nr_attached_geometry_shaders > 0) {
561 if (geometry_shader_output_count < 1)
563 ctx.shader_program_set_state(*
this);
565 state_out_of_date =
false;
573 if (ctx.shader_program_link(*
this)) {
574 ctx.shader_program_set_uniform_locations(*
this);
581 std::cerr <<
"link error:\n" <<
last_error.c_str() << std::endl;
594 geometry_shader_input_type = input_type;
595 geometry_shader_output_type = output_type;
596 geometry_shader_output_count = max_output_count;
597 state_out_of_date =
true;
604 ctx.
error(
"attempt to enable shader_program that is not created",
this);
608 ctx.
error(
"attempt to enable shader_program that is not linked",
this);
612 ctx.
error(
"attempt to enable shader_program that is already enabled or was not disabled properly",
this);
616 bool res = ctx.shader_program_enable(*
this);
618 shader_program_base::is_enabled =
true;
626 ctx.
error(
"attempt to disable shader_program that is not enabled",
this);
629 bool res = ctx.shader_program_disable(*
this);
630 shader_program_base::is_enabled =
false;
637 return uniform_locations;
647 auto it = uniform_locations.find(name);
648 return it != uniform_locations.end() ? it->second : -1;
653 bool res =
set_uniform(ctx, name +
".brdf_type",
static_cast<int>(material.
brdf_type), generate_error);
670 const char* texture_names[] = {
671 "tex0",
"tex1",
"tex2",
"tex3",
"tex4",
"tex5"
674 if (!
set_uniform(ctx, texture_names[i], i, generate_error))
694 if (!
set_uniform(ctx, name +
".light_source_type",
static_cast<int>(L.get_type()), generate_error))
696 if (!
set_uniform(ctx, name +
".position", L.get_position(), generate_error))
698 if (!
set_uniform(ctx, name +
".emission", L.get_emission(), generate_error))
700 if (!
set_uniform(ctx, name +
".ambient_scale", L.get_ambient_scale(), generate_error))
702 if (!
set_uniform(ctx, name +
".spot_direction", L.get_spot_direction(), generate_error))
704 if (!
set_uniform(ctx, name +
".spot_exponent", L.get_spot_exponent(), generate_error))
706 if (!
set_uniform(ctx, name +
".spot_cos_cutoff", cos(0.01745329252f*L.get_spot_cutoff()), generate_error))
708 if (!
set_uniform(ctx, name +
".constant_attenuation", L.get_constant_attenuation(), generate_error))
710 if (!
set_uniform(ctx, name +
".linear_attenuation", L.get_linear_attenuation(), generate_error))
712 if (!
set_uniform(ctx, name +
".quadratic_attenuation", L.get_quadratic_attenuation(), generate_error))
717int shader_program::get_uniform_block_index(
const context& ctx,
const std::string& name)
const
719 return ctx.get_uniform_block_index(*
this, name);
722bool shader_program::set_uniform_block_binding(
const context& ctx,
int index,
int binding)
724 return ctx.set_uniform_block_binding(*
this, index, binding);
727bool shader_program::set_uniform_block_binding(
const context& ctx,
const std::string& name,
int binding)
729 int index = ctx.get_uniform_block_index(*
this, name);
731 ctx.error(std::string(
"shader_program::set_uniform_block_binding() block <") + name +
"> not found",
this);
734 return ctx.set_uniform_block_binding(*
this, index, binding);
740 return ctx.get_attribute_location(*
this, name);
753 ctx.shader_program_destruct(*
this);
757 state_out_of_date =
true;
758 auto_detect_uniforms =
true;
759 auto_detect_vertex_attributes =
true;
760 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 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
namespace for api independent GPU programming
shader_config_ptr get_shader_config()
return a reference to the current shader configuration
ProgramVariableKind
enumerates different kinds of shader program variables
std::string to_string(TextureWrap wrap)
convert texture wrap to string
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.
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
this header is dependency free
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