Unravel Engine C++ Reference
Loading...
Searching...
No Matches
asset_dependencies.cpp
Go to the documentation of this file.
2#include "asset_extensions.h"
3
4#include <engine/ui/ui_tree.h>
5#include <graphics/shader.h>
7
8#include <algorithm>
9#include <fstream>
10#include <unordered_set>
11
12namespace unravel
13{
14namespace asset_compiler
15{
16
17namespace
18{
20auto normalize_dependency_path_string(std::string path) -> std::string
21{
22 string_utils::replace(path, "\\", "/");
23 return path;
24}
25
26auto extract_href_from_link_tag(hpp::string_view link_tag) -> hpp::string_view
27{
28 size_t href_pos = link_tag.find("href=");
29 if(href_pos == std::string::npos)
30 {
31 return {};
32 }
33 href_pos += 5;
34 char quote_char = link_tag[href_pos];
35 if(quote_char != '"' && quote_char != '\'')
36 {
37 return {};
38 }
39 href_pos++;
40 size_t href_end = link_tag.find(quote_char, href_pos);
41 if(href_end == std::string::npos)
42 {
43 return {};
44 }
45 return link_tag.substr(href_pos, href_end - href_pos);
46}
47
48auto resolve_ui_tree_dependency_path(const fs::path& href_value, const fs::path& base_file_path) -> fs::path
49{
50 if(fs::has_known_protocol(href_value))
51 {
52 return fs::resolve_protocol(href_value);
53 }
54 return fs::absolute(base_file_path.parent_path() / href_value);
55}
56
57auto visit_key_for_path(const fs::path& file_path) -> std::string
58{
59 return fs::absolute(file_path).string();
60}
61
62void append_shader_varying_dependency(const fs::path& file_path, std::vector<fs::path>& processed_files)
63{
64 const std::string file_name = file_path.stem().string();
65 const fs::path dir = file_path.parent_path();
66 fs::path varying = dir / (file_name + ".io");
67 fs::error_code err;
68 if(!fs::exists(varying, err))
69 {
70 varying = dir / "varying.def.io";
71 }
72 if(!fs::exists(varying, err))
73 {
74 varying = dir / "varying.def.sc";
75 }
76 if(fs::exists(varying, err))
77 {
78 processed_files.push_back(varying);
79 }
80}
81
82void resolve_shader_dependencies(const fs::path& file_path,
83 std::vector<fs::path>& processed_files,
84 std::unordered_set<std::string>& visited,
85 bool is_root)
86{
87 if(!visited.insert(visit_key_for_path(file_path)).second)
88 {
89 return;
90 }
91
92 // Root source is watched separately; only emit external deps here.
93 if(is_root)
94 {
95 append_shader_varying_dependency(file_path, processed_files);
96 }
97 else
98 {
99 processed_files.push_back(file_path);
100 }
101
102 std::ifstream file(file_path);
103 if(!file.is_open())
104 {
105 return;
106 }
107
108 const std::string include_keyword = "#include";
109 std::string line;
110 while(std::getline(file, line))
111 {
112 line.erase(0, line.find_first_not_of(" \t"));
113 if(line.compare(0, include_keyword.length(), include_keyword) != 0)
114 {
115 continue;
116 }
117 size_t start = line.find_first_of("\"<") + 1;
118 size_t end = line.find_last_of("\">");
119 if(start == std::string::npos || end == std::string::npos || start >= end)
120 {
121 continue;
122 }
123 if(line[start - 1] == '<' && line[end] == '>')
124 {
125 continue;
126 }
127 const std::string include_path = normalize_dependency_path_string(line.substr(start, end - start));
128 const fs::path resolved_path = fs::absolute(file_path.parent_path() / fs::path(include_path));
129 resolve_shader_dependencies(resolved_path, processed_files, visited, false);
130 }
131}
132
133void resolve_ui_tree_dependencies(const fs::path& file_path,
134 std::vector<fs::path>& processed_files,
135 std::unordered_set<std::string>& visited,
136 bool is_root)
137{
138 if(!visited.insert(visit_key_for_path(file_path)).second)
139 {
140 return;
141 }
142
143 // Root source is watched separately; only emit linked deps here.
144 if(!is_root)
145 {
146 processed_files.push_back(file_path);
147 }
148
149 std::ifstream file(file_path);
150 if(!file.is_open())
151 {
152 return;
153 }
154
155 std::string content_str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
156 hpp::string_view content(content_str);
157 size_t pos = 0;
158 while((pos = content.find("<link", pos)) != std::string::npos)
159 {
160 size_t tag_end = content.find('>', pos);
161 if(tag_end == std::string::npos)
162 {
163 break;
164 }
165 hpp::string_view link_tag = content.substr(pos, tag_end - pos + 1);
166 hpp::string_view href_value = extract_href_from_link_tag(link_tag);
167 if(!href_value.empty())
168 {
169 fs::path resolved_path = resolve_ui_tree_dependency_path(fs::path(href_value), file_path);
170 const auto& supported_deps = ex::get_suported_dependencies_formats<ui_tree>();
171 auto extension = resolved_path.extension().string();
172 if(std::find(supported_deps.begin(), supported_deps.end(), extension) != supported_deps.end())
173 {
174 resolve_ui_tree_dependencies(resolved_path, processed_files, visited, false);
175 }
176 }
177 pos = tag_end + 1;
178 }
179}
180
181} // namespace
182
183template<>
184void resolve_dependencies<gfx::shader>(const fs::path& file_path, std::vector<fs::path>& processed_files)
185{
186 std::unordered_set<std::string> visited;
187 resolve_shader_dependencies(file_path, processed_files, visited, true);
188}
189
190template<>
191void resolve_dependencies<ui_tree>(const fs::path& file_path, std::vector<fs::path>& processed_files)
192{
193 std::unordered_set<std::string> visited;
194 resolve_ui_tree_dependencies(file_path, processed_files, visited, true);
195}
196
197} // namespace asset_compiler
198} // namespace unravel
auto get_suported_dependencies_formats() -> const std::vector< std::string > &
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
bool has_known_protocol(const path &_path)
Checks whether the path has a known protocol.
void end(encoder *_encoder)
Definition graphics.cpp:427
auto replace(const std::string &str, const std::string &search, const std::string &replace) -> std::string
Definition utils.cpp:28
void resolve_dependencies< ui_tree >(const fs::path &file_path, std::vector< fs::path > &processed_files)
void resolve_dependencies< gfx::shader >(const fs::path &file_path, std::vector< fs::path > &processed_files)
std::vector< math::vec3 > start