29 #include <unordered_set>
34 m_template_source{source_code}
41 m_template_source{source_code}
48 m_template_source{source_code},
49 m_include_files{include_files}
57 m_template_source = source_code;
58 m_include_files.clear();
65 m_template_source = source_code;
66 m_include_files.clear();
73 replace_stage_directives(stage);
74 replace_define_directives(definitions);
78 for (
const auto& line: m_template_source.
lines)
90 const std::string object_source =
configure(stage, definitions);
93 std::unique_ptr<gl::shader_object>
object = std::make_unique<gl::shader_object>(stage);
96 object->source(object_source);
106 std::unique_ptr<gl::shader_object> vertex_object;
107 std::unique_ptr<gl::shader_object> fragment_object;
108 std::unique_ptr<gl::shader_object> geometry_object;
111 std::unique_ptr<gl::shader_program> program = std::make_unique<gl::shader_program>();
117 program->attach(*vertex_object);
124 program->attach(*fragment_object);
131 program->attach(*geometry_object);
138 program->detach_all();
143 void shader_template::find_directives()
146 m_vertex_directives.clear();
147 m_fragment_directives.clear();
148 m_geometry_directives.clear();
149 m_define_directives.clear();
152 for (std::size_t i = 0; i < m_template_source.
lines.size(); ++i)
154 std::istringstream line_stream(m_template_source.
lines[i]);
158 if (line_stream >> token && token ==
"#pragma")
160 if (line_stream >> token)
163 if (token ==
"define")
165 if (line_stream >> token)
167 m_define_directives.insert({token, i});
170 else if (token ==
"vertex")
172 m_vertex_directives.insert(i);
174 else if (token ==
"fragment")
176 m_fragment_directives.insert(i);
178 else if (token ==
"geometry")
180 m_geometry_directives.insert(i);
187 void shader_template::rehash()
190 for (
const auto& line: m_template_source.
lines)
196 void shader_template::replace_stage_directives(
gl::shader_stage stage)
const
199 const char* vertex_directive = (stage ==
gl::shader_stage::vertex) ?
"#define __VERTEX__" :
"/* #undef __VERTEX__ */";
200 const char* fragment_directive = (stage ==
gl::shader_stage::fragment) ?
"#define __FRAGMENT__" :
"/* #undef __FRAGMENT__ */";
201 const char* geometry_directive = (stage ==
gl::shader_stage::geometry) ?
"#define __GEOMETRY__" :
"/* #undef __GEOMETRY__ */";
204 for (
const auto directive_line: m_vertex_directives)
206 m_template_source.
lines[directive_line] = vertex_directive;
208 for (
const auto directive_line: m_fragment_directives)
210 m_template_source.
lines[directive_line] = fragment_directive;
212 for (
const auto directive_line: m_geometry_directives)
214 m_template_source.
lines[directive_line] = geometry_directive;
218 void shader_template::replace_define_directives(
const dictionary_type& definitions)
const
221 for (
const auto& define_directive: m_define_directives)
224 std::string&
line = m_template_source.
lines[define_directive.second];
227 auto definitions_it = definitions.find(define_directive.first);
228 if (definitions_it != definitions.end())
231 line =
"#define " + define_directive.first;
232 if (!definitions_it->second.empty())
234 line +=
" " + definitions_it->second;
240 line =
"/* #undef " + define_directive.first +
" */";
247 return (m_define_directives.find(key) != m_define_directives.end());
259 static bool has_pragma_once(
const text_file& source)
263 std::istringstream line_stream(
line);
267 if (line_stream >> token && token ==
"#pragma")
269 if (line_stream >> token && token ==
"once")
285 for (std::size_t i = 0;
i < source.
lines.size(); ++
i)
288 std::istringstream line_stream(source.
lines[i]);
291 if (line_stream >> token && token ==
"#pragma" &&
292 line_stream >> token && token ==
"include")
295 if (line_stream >> token && token.size() > 2 &&
296 ((token.front() ==
'\"' && token.back() ==
'\"') ||
297 (token.front() ==
'<' && token.back() ==
'>')))
300 const std::filesystem::path path = token.substr(1, token.length() - 2);
303 if (include_once.contains(path))
305 source.
lines[
i] =
"/* #pragma exclude " + token +
" */";
313 source.
lines[
i] =
"#error file not found: " + path.string();
318 include_files.emplace_back(include_file);
322 if (has_pragma_once(*include_file))
325 include_once.insert(path);
329 text_file include_file_copy = *include_file;
332 handle_includes(include_files, include_file_copy, include_once,
resource_manager);
336 source.
lines.insert(source.
lines.begin() + i, include_file_copy.
lines.begin(), include_file_copy.
lines.end());
337 i += include_file_copy.
lines.size() - 1;
341 source.
lines[
i] =
"#error malformed include directive: \"" + source.
lines[
i] +
"\"";
354 text_file source_file_copy = *source_file;
356 std::vector<std::shared_ptr<text_file>> include_files;
359 std::unordered_set<std::filesystem::path> include_once;
360 include_once.insert(ctx.
path());
361 handle_includes(include_files, source_file_copy, include_once,
resource_manager);
364 return std::make_unique<gl::shader_template>(std::move(source_file_copy), std::move(include_files));
std::string configure(gl::shader_stage stage, const dictionary_type &definitions={}) const
Configures shader object source code for a given shader stage and template dictionary.
std::unique_ptr< gl::shader_program > build(const dictionary_type &definitions={}) const
Configures and compiles shader objects, then links them into a shader program.
std::unordered_map< std::string, std::string > dictionary_type
Container of definitions used to generate #pragma define <key> <value> directives.
bool has_geometry_directive() const noexcept
Returns true if the template source contains one or more #pragma geometry directive.
constexpr shader_template() noexcept=default
Constructs an empty shader template.
bool has_define_directive(const std::string &key) const
Returns true if the template source contains one or more instance of #pragma define <key>.
bool has_vertex_directive() const noexcept
Returns true if the template source contains one or more #pragma vertex directive.
void source(const text_file &source_code)
Replaces the source code of the shader template.
std::unique_ptr< gl::shader_object > compile(gl::shader_stage stage, const dictionary_type &definitions={}) const
Configures and compiles a shader object.
bool has_fragment_directive() const noexcept
Returns true if the template source contains one or more #pragma fragment directive.
static std::unique_ptr< T > load(::resource_manager &resource_manager, deserialize_context &ctx)
Loads a resource.
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
constexpr std::uint32_t hash_combine(std::uint32_t x, std::uint32_t y) noexcept
Combines two hash values.
hyperplane< T, 2 > line
2-dimensional hyperplane.
Graphics library interface.
shader_stage
Enumerates all supported shader stages.
@ fragment
Fragment shader stage.
@ vertex
Vertex shader stage.
@ geometry
Geometry shader stage.
Provides access to a deserialization state.
virtual const std::filesystem::path & path() const noexcept=0
Returns the path associated with this deserialize context.
std::vector< std::string > lines
Text file lines.