1#include "ResourceReader.h"
3#include "Foundation/Logging/Logger.h"
8#include "Resources/MeshManager.h"
9#include "Resources/MaterialManager.h"
10#include "Resources/AssetManager.h"
12#include "Generators/MeshGenerator.h"
14#include "Services/Services.h"
15#include "Services/TaskManager.h"
17#include "Utilities/Parsing.h"
19#include "ReaderCommon.h"
25 std::unordered_map<size_t, Cogs::Core::ReaderExtension> extensions;
32 StringView readMesh(Context * context, ResourceDefinition & definition,
const Value & jsonResource)
37 if (!definition.name.empty()) {
38 existing = context->meshManager->getMesh(definition.name);
43 if (definition.name.empty()) {
45 std::string generatedName =
"GeneratedMesh" + std::to_string(seq++);
53 for (
auto & m : jsonResource.GetObject()) {
54 auto key = toKey(m.name);
56 if (key ==
"positions") {
57 auto arr = m.value.GetArray();
59 std::vector<glm::vec3> v(arr.Size());
62 for (
auto & element : arr) {
63 readArray(element, v[i++],
nullptr);
67 }
else if (key ==
"instancePositions") {
68 auto arr = m.value.GetArray();
70 std::vector<glm::vec3> v(arr.Size());
73 for (
auto & element : arr) {
74 readArray(element, v[i++],
nullptr);
77 mesh->setInstancePositions(v);
78 }
else if (key ==
"instanceColors") {
79 auto arr = m.value.GetArray();
81 std::vector<glm::vec4> v(arr.Size());
84 for (
auto & element : arr) {
85 readArray(element, v[i++],
nullptr);
88 mesh->setInstanceColors(v);
89 }
else if (key ==
"normals") {
90 auto arr = m.value.GetArray();
92 std::vector<glm::vec3> v(arr.Size());
95 for (
auto & element : arr) {
96 readArray(element, v[i++],
nullptr);
100 }
else if (key ==
"bbox") {
101 auto arr = m.value.GetArray();
103 std::vector<glm::vec3> v(arr.Size());
106 for (
auto & element : arr) {
107 readArray(element, v[i++],
nullptr);
113 }
else if (key ==
"generator") {
114 ShapeDefinition definition2;
115 definition2.size = glm::vec3(1, 1, 1);
117 for (
auto & g : m.value.GetObject()) {
118 auto gKey = toKey(g.name);
120 if (gKey ==
"shape") {
122 }
else if (gKey ==
"samples") {
123 if (g.value.IsInt()) {
124 definition2.refinement = g.value.GetInt();
126 definition2.refinement = parseInt(toKey(g.value), 16);
128 }
else if (gKey ==
"size") {
129 readArray(g.value, definition2.size,
nullptr);
133 context->services->getService<MeshGenerator>()->getMesh(mesh.
resolve(), definition2);
140 void readAssetDefinition(ReaderContext* ,
const Value& jsonResource, ResourceDefinition& assetDefinition)
142 assetDefinition.type = ResourceTypes::Asset;
143 assetDefinition.source = toString(jsonResource[
"source"]);
146 void readModelDefinition(ReaderContext *,
const Value & jsonResource, ResourceDefinition & definition)
148 definition.type = ResourceTypes::Model;
149 definition.source = toString(jsonResource[
"source"]);
152 void readTextureDefinition(ReaderContext * ,
const Value & jsonResource, ResourceDefinition & definition)
154 definition.type = ResourceTypes::Texture;
156 auto & textureDescription = definition.textureDescription;
158 for (
auto & m : jsonResource.GetObject()) {
159 auto key = toKey(m.name);
161 if (key ==
"source") {
162 definition.source = toString(m.value);
164 if (jsonResource.HasMember(
"flags")) {
165 auto flags = toKey(jsonResource[
"flags"]);
167 auto splits = split(flags,
"|");
169 for (
auto & s : splits) {
170 if (s ==
"LinearColorSpace") {
175 }
else if (key ==
"generator") {
176 definition.textureGenerator =
true;
177 ImageDefinition& imageDefinition = definition.imageDefinition;
178 for (
auto & g : m.value.GetObject()) {
179 switch (toView(g.name).
hash()) {
181 imageDefinition.type = parseEnum(toKey(g.value), ImageType::None);
184 imageDefinition.width = readValue<int>(g.value, ImageDefinition().width, nullptr);
187 imageDefinition.height = readValue<int>(g.value, ImageDefinition().height, nullptr);
190 imageDefinition.layers = readValue<int>(g.value, ImageDefinition().layers, nullptr);
196 }
else if (key ==
"width") {
197 textureDescription.width = readValue<int>(m.value, 1024,
nullptr);
198 }
else if (key ==
"height") {
199 textureDescription.height = readValue<int>(m.value, 1024,
nullptr);
200 }
else if (key ==
"renderTarget") {
202 }
else if (key ==
"format") {
203 textureDescription.format = parseTextureFormat(toKey(m.value), Cogs::TextureFormat::R8G8B8A8_UNORM_SRGB);
204 }
else if (key ==
"flags") {
206 split(toKey(m.value),
" |", flags);
208 for (
auto & flag : flags) {
209 if (flag ==
"Texture") {
211 }
else if (flag ==
"RenderTarget") {
213 }
else if (flag ==
"GenerateMipMaps") {
221 void parseMaterialInstanceProperty(
const Value & value,
const StringView & key,
const Material * material, FieldValue & propertyValue, ExpressionContext * ec)
223 if (value.IsFloat()) {
224 propertyValue.type = DefaultValueType::Float;
225 propertyValue.floatValue = value.GetFloat();
226 }
else if (value.IsBool()) {
227 propertyValue.type = DefaultValueType::Bool;
228 propertyValue.boolValue = value.GetBool();
229 }
else if (value.IsInt()) {
230 propertyValue.type = DefaultValueType::Int;
231 propertyValue.intValue = value.GetInt();
232 }
else if (value.IsArray()) {
233 auto arr = value.GetArray();
235 if (arr.Size() == 2) {
236 propertyValue.type = DefaultValueType::Vec2;
237 readArray(value, propertyValue.float2, ec);
238 }
else if (arr.Size() == 3) {
239 propertyValue.type = DefaultValueType::Vec3;
240 readArray(value, propertyValue.float3, ec);
241 }
else if (arr.Size() == 4) {
242 propertyValue.type = DefaultValueType::Vec4;
243 readArray(value, propertyValue.float4, ec);
245 LOG_ERROR(logger,
"Unsupported array size for material property %.*s", StringViewFormat(key));
247 }
else if (value.IsString()) {
248 ParsedValue parsedValue;
249 parseStringValue(toKey(value), parsedValue);
251 if (parsedValue.type == ParsedDataType::Unknown) parsedValue.type = ParsedDataType::String;
253 if (parsedValue.type == ParsedDataType::Float) {
254 propertyValue.type = DefaultValueType::Float;
255 propertyValue.floatValue = parsedValue.floatValue;
256 }
else if (parsedValue.type == ParsedDataType::Float2) {
257 propertyValue.type = DefaultValueType::Vec2;
258 propertyValue.float2 = parsedValue.float2Value;
259 }
else if (parsedValue.type == ParsedDataType::Float3) {
260 propertyValue.type = DefaultValueType::Vec3;
261 propertyValue.float3 = parsedValue.float3Value;
262 }
else if (parsedValue.type == ParsedDataType::Float4) {
263 propertyValue.type = DefaultValueType::Vec4;
264 propertyValue.float4 = parsedValue.float4Value;
265 }
else if (parsedValue.type == ParsedDataType::String) {
267 auto texKey = material->getTextureKey(key);
268 if (texKey != NoProperty) {
269 propertyValue.type = DefaultValueType::Texture;
270 propertyValue.value = parsedValue.value;
272 auto floatKey = material->getFloatKey(key);
273 if (floatKey != NoProperty) {
274 propertyValue.type = DefaultValueType::Float;
275 propertyValue.floatValue = ec->eval(parsedValue.value, 0.0f);
279 propertyValue.type = DefaultValueType::Texture;
280 propertyValue.value = parsedValue.value;
284 LOG_ERROR(logger,
"Unsupported material property value for %.*s", StringViewFormat(key));
288 void readMaterialInstanceDefinition(ReaderContext * rc,
const Value & value, ResourceDefinition & resourceDefinition)
290 resourceDefinition.type = ResourceTypes::MaterialInstance;
292 auto & materialInstance = resourceDefinition;
293 auto context = rc->context;
296 auto obj = value.GetObject();
298 MaterialHandle material;
300 for (
auto & m : obj) {
301 auto matKey = toKey(m.name);
303 auto keyCode = StringView(matKey.data(), matKey.length()).hash();
308 materialInstance.material = m.value.GetString();
309 material = context->materialManager->getMaterial(materialInstance.material);
313 materialInstance.material = m.value.GetString();
316 materialInstance.permutation = m.value.GetString();
320 auto optionsObject = m.value.GetObject();
322 for (
auto & option : optionsObject) {
323 materialInstance.options[option.name.GetString()] = option.value.GetString();
329 auto variantsObject = m.value.GetObject();
331 for (
auto & variant : variantsObject) {
332 if (variant.value.IsNumber()) {
333 materialInstance.variants[variant.name.GetString()] = std::to_string(variant.value.GetInt());
334 }
else if (variant.value.IsString()) {
335 materialInstance.variants[variant.name.GetString()] = variant.value.GetString();
336 }
else if (variant.value.IsBool()) {
337 materialInstance.variants[variant.name.GetString()] = variant.value.GetBool() ?
"true" :
"false";
339 LOG_ERROR(logger,
"Unknown variant type.");
346 auto propsObject = m.value.GetObject();
348 for (
auto & prop : propsObject) {
349 auto key = toKey(prop.name);
350 auto & propertyValue = materialInstance.properties[key.to_string()];
352 parseMaterialInstanceProperty(prop.value, key, material.resolve(), propertyValue, rc->ec);
357 auto & propertyValue = materialInstance.properties[matKey.to_string()];
359 parseMaterialInstanceProperty(m.value, matKey, material.resolve(), propertyValue, rc->ec);
366 void readResource(Context * context,
const StringView & name,
const Value & jsonResource)
368 ResourceDefinition definition;
370 if (name.size()) definition.name = name.to_string();
372 if (jsonResource.IsString()) {
373 auto value = toKey(jsonResource);
375 if (value.find(
".material") != StringView::NoPosition) {
376 context->materialManager->loadMaterial(value);
377 context->materialManager->processLoading();
383 rc.context = context;
385 for (
auto & m : jsonResource.GetObject()) {
386 auto key = toKey(m.name);
389 definition.name = toString(m.value);
390 }
else if (key ==
"type") {
391 auto type = toKey(m.value);
393 if (type ==
"Mesh") {
394 readMesh(context, definition, jsonResource);
395 }
else if (type ==
"Asset") {
396 readAssetDefinition(&rc, jsonResource, definition);
397 context->assetManager->instantiateAsset(AssetHandle::NoHandle, definition);
398 }
else if (type ==
"MaterialInstance") {
399 readMaterialInstanceDefinition(&rc, jsonResource, definition);
400 context->assetManager->instantiateMaterialInstance(AssetHandle::NoHandle, definition);
401 }
else if (type ==
"Texture") {
402 readTextureDefinition(&rc, jsonResource, definition);
403 context->assetManager->instantiateTexture(AssetHandle::NoHandle, definition);
404 }
else if (type ==
"Model") {
405 readModelDefinition(&rc, jsonResource, definition);
406 context->assetManager->instantiateModel(AssetHandle::NoHandle, definition);
407 }
else if (type ==
"GuiDocument") {
408 auto * mgr = context->engine->getResourceManagerByValueType((
int)DefaultValueType::Gui);
410 mgr->readSource(context, definition, &jsonResource);
413 LOG_ERROR(logger,
"No manager for DefaultValueType::Gui");
416 auto ext = extensions.find(type.hash());
418 if (ext != extensions.end()) {
419 ext->second.readCallback(definition.name, jsonResource);
426 void readResourceDefinition(Context * context,
const StringView & name,
const Value & jsonResource, ResourceDefinition & definition)
428 if (name.size()) definition.name = name.to_string();
430 if (jsonResource.IsString()) {
431 auto value = toKey(jsonResource);
433 if (value.find(
".material") != StringView::NoPosition) {
434 context->materialManager->loadMaterial(value);
435 context->materialManager->processLoading();
441 rc.context = context;
443 for (
auto & m : jsonResource.GetObject()) {
444 auto key = toKey(m.name);
447 definition.name = toString(m.value);
448 }
else if (key ==
"type") {
449 auto type = toKey(m.value);
451 if (type ==
"Mesh") {
452 readMesh(context, definition, jsonResource);
453 }
else if (type ==
"Asset") {
454 readAssetDefinition(&rc, jsonResource, definition);
455 }
else if (type ==
"MaterialInstance") {
456 readMaterialInstanceDefinition(&rc, jsonResource, definition);
457 }
else if (type ==
"Texture") {
458 readTextureDefinition(&rc, jsonResource, definition);
459 }
else if (type ==
"Model") {
460 readModelDefinition(&rc, jsonResource, definition);
461 }
else if (type ==
"GuiDocument") {
462 auto * mgr = context->engine->getResourceManagerByValueType((
int)DefaultValueType::Gui);
464 mgr->readSource(context, definition, &jsonResource);
467 LOG_ERROR(logger,
"No manager for DefaultValueType::Gui");
470 auto ext = extensions.find(type.hash());
472 if (ext != extensions.end()) {
473 ext->second.readCallback(definition.name, jsonResource);
483 for (
auto & e : extensions) {
484 if (e.second.handleTypeId == code) {
492void Cogs::Core::registerExtensionReader(Context * ,
const StringView & resourceType,
const Reflection::Type & handleType, ReaderExtension extension)
494 extension.handleTypeId = handleType.getTypeId();
496 extensions[resourceType.hash()] = extension;
499void Cogs::Core::readResources(Context * context,
const Value & jsonResources,
int )
501 if (jsonResources.IsObject()) {
502 for (
auto & m : jsonResources.GetObject()) {
503 readResource(context, toKey(m.name), m.value);
507 LOG_ERROR(logger,
"Expected resources section as JSON object");
511void Cogs::Core::readResourceDefinitions(Context * context,
const Value & jsonResources,
int , AssetDefinition & asset)
513 if (jsonResources.IsObject()) {
514 for (
auto & m : jsonResources.GetObject()) {
515 auto & resourceDefinition = asset.resources.emplace_back();
516 readResourceDefinition(context, toKey(m.name), m.value, resourceDefinition);
Log implementation class.
constexpr size_t hash() const noexcept
Get the hash code of the string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
@ LinearColorSpace
For textures with RGBA format without color space information, mark the data as being in linear color...
constexpr Log getLogger(const char(&name)[LEN]) noexcept
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
void setNormals(std::span< const glm::vec3 > normals)
Set the normal data of the Mesh.
void clear()
Clear all data from the Mesh, returning it to its initial non-indexed state with no streams and no su...
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
StringView getName() const
Get the name of the resource.
void setName(const StringView &name)
Set the user friendly name of the resource.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
@ RenderTarget
The texture can be used as a render target and drawn into.
@ GenerateMipMaps
The texture supports automatic mipmap generation performed by the graphics device.
@ Texture
Texture usage, see Default.