Cogs.Core
RenderPipelineReader.cpp
1#include "RenderPipelineReader.h"
2
3#include "JsonParser.h"
4
5#include "Foundation/Logging/Logger.h"
6
7#include <glm/fwd.hpp>
8
9#include "Context.h"
10#include "Bridge/Bridge.h"
11
12#include "Resources/ResourceStore.h"
13
14#include "Utilities/Parsing.h"
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("PipelineParser");
19}
20
21namespace Cogs
22{
23 namespace Core
24 {
25 RenderResourceType parseResourceType(const std::string & str)
26 {
27 if (str == "RenderList") {
28 return RenderResourceType::RenderList;
29 } else if (str == "Texture2D") {
30 return RenderResourceType::RenderTexture;
31 } else if (str == "RenderTarget") {
32 return RenderResourceType::RenderTarget;
33 } else if (str == "RenderBuffer") {
34 return RenderResourceType::RenderBuffer;
35 }
36
37 return RenderResourceType::Unknown;
38 }
39
40 void parseOptions(const Value & jsonOptions, RenderPipelineDefinition & definition)
41 {
42 for (auto & o : jsonOptions.GetObject()) {
43 auto name = toKey(o.name);
44
45 ParsedOption option;
46 option.key = name.to_string();
47
48 if (!o.value.IsObject()) {
49 LOG_ERROR(logger, "Option %.*s must be object type.", StringViewFormat(name));
50 continue;
51 }
52
53 for (auto & v : o.value.GetObject()) {
54 auto key = toKey(v.name);
55
56 if (key == "values" && v.value.IsArray()) {
57 for (auto & vv : v.value.GetArray()) {
58 option.values.push_back(vv.GetString());
59 }
60 } else if (key == "setting") {
61 option.setting = v.value.GetString();
62 }
63 }
64
65 definition.options.push_back(option);
66 }
67 }
68
69 void parseValue(const StringView & key, const Value & value, ParsedValue & v)
70 {
71 v.key = key.to_string();
72
73 switch (value.GetType())
74 {
75 case kStringType:
76 {
77 parseStringValue(toKey(value), v);
78 }
79 break;
80 case kObjectType:
81 {
82 v.type = ParsedDataType::Object;
83
84 for (auto & m : value.GetObject()) {
85 v.values.emplace_back();
86 parseValue(toKey(m.name), m.value, v.values.back());
87 }
88 }
89 break;
90 case kNumberType:
91 if (value.IsInt()) {
92 v.type = ParsedDataType::Int;
93 v.intValue = static_cast<int>(value.GetInt());
94 } else {
95 v.type = ParsedDataType::Float;
96 v.floatValue = static_cast<float>(value.GetFloat());
97 }
98 break;
99 case kArrayType:
100 {
101 auto arr = value.GetArray();
102
103 if (arr.Size() < 1) {
104 LOG_ERROR(logger, "Cannot deduce type from empty array.");
105 break;
106 }
107
108 auto arrayType = arr[0].GetType();
109
110 if (arr.Size() > 4) {
111 LOG_ERROR(logger, "Too many array members.");
112 break;
113 }
114
115 if (arrayType == kStringType) {
116 v.type = ParsedDataType::String;
117 v.dimension = arr.Size();
118
119 for (auto & a : arr) {
120 ParsedValue p;
121 p.value = a.GetString();
122 v.values.push_back(p);
123 }
124 } else {
125 v.type = (ParsedDataType)((size_t)ParsedDataType::Float + arr.Size() - 1);
126 for (uint32_t i = 0; i < arr.Size(); ++i) {
127 switch (arr[i].GetType())
128 {
129 case kNumberType:
130 v.float4Value[static_cast<glm::length_t>(i)] = arr[i].GetFloat();
131 break;
132 default:
133 LOG_ERROR(logger, "Unknown vector type.");
134 break;
135 }
136 }
137 }
138 }
139 break;
140 case kTrueType:
141 v.type = ParsedDataType::Bool;
142 v.boolValue = true;
143 break;
144 case kFalseType:
145 v.type = ParsedDataType::Bool;
146 v.boolValue = false;
147 break;
148 default:
149 break;
150 }
151 }
152
153 void parseResource(const Value & value, RenderResourceDefinition & resource, const std::string & /*condition*/)
154 {
155 if (value.IsString()) {
156 std::string str = value.GetString();
157
158 auto space = str.find(' ');
159 if (space != std::string::npos) {
160 resource.type = parseResourceType(str.substr(0, space));
161 resource.alias = str.substr(space + 1);
162 } else {
163 resource.type = parseResourceType(str);
164 }
165 } else if (value.IsObject()) {
166 for (auto & m : value.GetObject()) {
167 auto key = toKey(m.name);
168
169 if (key == "type") {
170 resource.type = parseResourceType(m.value.GetString());
171 } else if (key == "textures") {
172 for (auto & t : m.value.GetArray()) {
173 resource.textures.push_back(t.GetString());
174 }
175 } else {
176 ParsedValue p;
177 parseValue(key, m.value, p);
178 resource.parameters.push_back(p);
179 }
180 }
181 }
182 }
183
184 bool parseResources(const Value & jsonResources, RenderPipelineDefinition & definition, const std::string & condition = "")
185 {
186 for (auto & m : jsonResources.GetObject()) {
187 auto key = toString(m.name);
188
189 if (key[0] == '$') {
190 parseResources(m.value, definition, condition.size() ? condition + key : key);
191 continue;
192 }
193
194 RenderResourceDefinition resource;
195 resource.name = key;
196 resource.condition = condition;
197
198 parseResource(m.value, resource, condition);
199
200 definition.resources.push_back(resource);
201 }
202
203 return true;
204 }
205
206 void parseSlots(const Value & value, std::vector<RenderTaskSlot> & slots)
207 {
208 if (value.IsArray()) {
209 for (auto & v : value.GetArray()) {
210 slots.push_back(toString(v));
211 }
212 } else if (value.IsString()) {
213 slots.push_back(toString(value));
214 } else if (value.IsObject()) {
215 for (auto & m : value.GetObject()) {
216 slots.push_back({ toString(m.name), toString(m.value) });
217 }
218 }
219 }
220
221 void parseTask(const Value & jsonTask, RenderTaskDefinition & task, const std::string & /*condition*/)
222 {
223 for (auto & m : jsonTask.GetObject()) {
224 auto key = toString(m.name);
225 auto & value = m.value;
226
227 if (key == "type" && value.IsString()) {
228 task.type = toString(value);
229 } else if (key == "dependencies" || key == "depends") {
230 if (value.IsArray()) {
231 for (auto & a : value.GetArray()) {
232 task.dependencies.push_back(toString(a));
233 }
234 } else if (value.IsString()) {
235 task.dependencies.push_back(toString(value));
236 }
237 } else if (key == "options") {
238 for (auto & m_ : value.GetObject()) {
239 task.options.push_back({ toString(m_.name), toString(m_.value), {} });
240 }
241 } else if (key == "inputs" || key == "input") {
242 parseSlots(value, task.inputs);
243 } else if (key == "outputs" || key == "output") {
244 parseSlots(value, task.outputs);
245 } else {
246 ParsedValue p;
247 parseValue(key, value, p);
248 task.parameters.push_back(p);
249 }
250 }
251 }
252
253 bool parseTasks(const Value & jsonTasks, RenderPipelineDefinition & definition, const std::string & condition = "")
254 {
255 for (auto & m : jsonTasks.GetObject()) {
256 auto key = toString(m.name);
257 auto & value = m.value;
258
259 if (key[0] == '$') {
260 parseTasks(value, definition, condition.size() ? condition + key : key);
261 continue;
262 }
263
264 RenderTaskDefinition task;
265 task.name = key;
266 task.condition = condition;
267
268 parseTask(value, task, condition);
269
270 definition.tasks.push_back(task);
271 }
272
273 return true;
274 }
275
276 bool parseDefinition(Context * context, const Value & jsonDefinition, RenderPipelineDefinition & definition)
277 {
278 for (auto & m : jsonDefinition.GetObject()) {
279 auto key = toString(m.name);
280 auto & value = m.value;
281
282 if (key == "name") {
283 definition.name = toString(value);
284 } else if (key == "permutations") {
285 auto val = toString(value);
286 loadPermutations(context, val.c_str());
287 } else if (key == "options") {
288 parseOptions(value, definition);
289 } if (key == "resources") {
290 parseResources(value, definition);
291 } else if (key == "tasks") {
292 parseTasks(value, definition);
293 } else if (key == "generators") {
294 for (auto & g : value.GetObject()) {
295 RenderPipelineDefinition generator;
296 generator.name = toString(g.name);
297 parseDefinition(context, g.value, generator);
298 definition.generators.push_back(generator);
299 }
300 } else if (key == "imports" || key == "import") {
301 for (auto & import : value.GetObject()) {
302 definition.imports.push_back({ toString(import.name), toString(import.value), {} });
303 }
304 } else if (key == "input" || key == "inputs") {
305 parseSlots(value, definition.inputs);
306 } else if (key == "outputs" || key == "output") {
307 parseSlots(value, definition.outputs);
308 } else if (key == "useVariables") {
309 if (value.IsObject()) {
310 for (auto & m_ : value.GetObject()) {
311 ParsedValue p;
312 auto key_ = toKey(m_.name);
313 parseValue(key_, m_.value, p);
314 definition.useVariables.push_back(p);
315 }
316 }
317 } else if (key == "setVariables") {
318 if (value.IsObject()) {
319 for (auto & m_ : value.GetObject()) {
320 ParsedValue p;
321 auto key_ = toKey(m_.name);
322 parseValue(key_, m_.value, p);
323 definition.setVariables.push_back(p);
324 }
325 }
326 } else if (key == "useComponentFields") {
327 if (value.IsObject()) {
328 for (auto & m_ : value.GetObject()) {
329 ParsedValue p;
330 auto key_ = toKey(m_.name);
331 parseValue(key_, m_.value, p);
332 definition.useComponentFields.push_back(p);
333 }
334 }
335 }
336
337 }
338
339 return true;
340 }
341 }
342}
343
344Cogs::Core::RenderPipelineDefinition Cogs::Core::parsePipeline(Context * context, const StringView & resource, bool isContent)
345{
346 auto document = isContent ? parseJson(resource, JsonParseFlags::None) : parseJson(context, resource);
347
348 if (!document.IsObject()) {
349 LOG_ERROR(logger, "Cannot read pipeline from non-object JSON.");
350 return RenderPipelineDefinition{};
351 }
352
353 for (auto & m : document.GetObject()) {
354 auto key = toKey(m.name);
355
356 if (key == "Pipeline") {
357 RenderPipelineDefinition definition;
358 parseDefinition(context, m.value, definition);
359 return definition;
360 }
361 }
362
363 return RenderPipelineDefinition{};
364}
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains all Cogs related functionality.
Definition: FieldSetter.h:23