| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- /*
- * Copyright (c) 2012-2025 Daniele Bartolini et al.
- * SPDX-License-Identifier: MIT
- */
- #include "core/containers/array.inl"
- #include "core/containers/vector.inl"
- #include "core/filesystem/filesystem.h"
- #include "core/filesystem/reader_writer.h"
- #include "core/json/json_object.inl"
- #include "core/json/sjson.h"
- #include "core/memory/temp_allocator.inl"
- #include "core/strings/dynamic_string.inl"
- #include "core/strings/string.inl"
- #include "core/strings/string_id.inl"
- #include "core/strings/string_view.inl"
- #include "device/device.h"
- #include "resource/compile_options.inl"
- #include "resource/material_resource.h"
- #include "resource/resource_manager.h"
- #include "world/material_manager.h"
- namespace crown
- {
- namespace material_resource
- {
- UniformData *uniform_data_array(const MaterialResource *mr)
- {
- return (UniformData *)((char *)mr + mr->uniform_data_offset);
- }
- u32 uniform_data_index(const MaterialResource *mr, const UniformData *ud, StringId32 name)
- {
- for (u32 i = 0, n = mr->num_uniforms; i < n; ++i) {
- if (ud[i].name == name)
- return i;
- }
- CE_FATAL("Unknown uniform");
- return UINT32_MAX;
- }
- const char *uniform_name(const MaterialResource *mr, const UniformData *ud, u32 i)
- {
- return (const char *)mr + mr->names_data_offset + ud[i].name_offset;
- }
- TextureData *texture_data_array(const MaterialResource *mr)
- {
- return (TextureData *)((char *)mr + mr->texture_data_offset);
- }
- u32 texture_data_index(const MaterialResource *mr, const TextureData *td, StringId32 name)
- {
- for (u32 i = 0, n = mr->num_textures; i < n; ++i) {
- if (td[i].name == name)
- return i;
- }
- CE_FATAL("Unknown texture");
- return UINT32_MAX;
- }
- const char *texture_name(const MaterialResource *mr, const TextureData *td, u32 i)
- {
- return (const char *)mr + mr->names_data_offset + td[i].sampler_name_offset;
- }
- UniformHandle *uniform_handle(const UniformData *ud, u32 i, char *dynamic)
- {
- return (UniformHandle *)(dynamic + ud[i].data_offset);
- }
- TextureHandle *texture_handle(const TextureData *td, u32 i, char *dynamic)
- {
- return (TextureHandle *)(dynamic + td[i].data_offset);
- }
- } // namespace material_resource
- namespace material_resource_internal
- {
- void online(StringId64 id, ResourceManager &rm)
- {
- device()->_material_manager->online(id, rm);
- }
- void offline(StringId64 id, ResourceManager &rm)
- {
- device()->_material_manager->offline(id, rm);
- }
- } // namespace material_resource_internal
- #if CROWN_CAN_COMPILE
- namespace material_resource_internal
- {
- struct UniformTypeInfo
- {
- const char *name;
- UniformType::Enum type;
- };
- static const UniformTypeInfo s_uniform_type_info[] =
- {
- { "float", UniformType::FLOAT },
- { "vector2", UniformType::VECTOR2 },
- { "vector3", UniformType::VECTOR3 },
- { "vector4", UniformType::VECTOR4 },
- { "matrix4x4", UniformType::MATRIX4X4 }
- };
- CE_STATIC_ASSERT(countof(s_uniform_type_info) == UniformType::COUNT);
- static UniformType::Enum name_to_uniform_type(const char *name)
- {
- for (u32 i = 0; i < countof(s_uniform_type_info); ++i) {
- if (strcmp(s_uniform_type_info[i].name, name) == 0)
- return s_uniform_type_info[i].type;
- }
- return UniformType::COUNT;
- }
- struct Data
- {
- Array<TextureData> textures;
- Array<UniformData> uniforms;
- Array<char> dynamic;
- Data()
- : textures(default_allocator())
- , uniforms(default_allocator())
- , dynamic(default_allocator())
- {
- }
- };
- // Returns offset to start of data
- template<typename T>
- static u32 reserve_dynamic_data(Array<char> &dynamic, T data)
- {
- u32 offt = array::size(dynamic);
- array::push(dynamic, (char *)&data, sizeof(data));
- return offt;
- }
- static s32 parse_textures(Array<TextureData> &textures, Array<char> &names, Array<char> &dynamic, const char *json, CompileOptions &opts)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- RETURN_IF_ERROR(sjson::parse(obj, json), opts);
- auto cur = json_object::begin(obj);
- auto end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const char *value = cur->second;
- DynamicString texture(ta);
- RETURN_IF_ERROR(sjson::parse_string(texture, value), opts);
- RETURN_IF_RESOURCE_MISSING("texture", texture.c_str(), opts);
- opts.add_requirement("texture", texture.c_str());
- TextureHandle th;
- th.sampler_handle = 0;
- th.texture_handle = 0;
- const u32 sampler_name_offset = array::size(names);
- array::push(names, key.data(), key.length());
- array::push_back(names, '\0');
- TextureData td;
- td.sampler_name_offset = sampler_name_offset;
- td.name = StringId32(key.data(), key.length());
- td.id = RETURN_IF_ERROR(sjson::parse_resource_name(value), opts);
- td.data_offset = reserve_dynamic_data(dynamic, th);
- td._pad1 = 0;
- array::push_back(textures, td);
- }
- return 0;
- }
- static s32 parse_uniforms(Array<UniformData> &uniforms, Array<char> &names, Array<char> &dynamic, const char *json, CompileOptions &opts)
- {
- TempAllocator4096 ta;
- JsonObject obj(ta);
- RETURN_IF_ERROR(sjson::parse(obj, json), opts);
- auto cur = json_object::begin(obj);
- auto end = json_object::end(obj);
- for (; cur != end; ++cur) {
- JSON_OBJECT_SKIP_HOLE(obj, cur);
- const StringView key = cur->first;
- const char *value = cur->second;
- UniformHandle uh;
- uh.uniform_handle = 0;
- JsonObject uniform(ta);
- RETURN_IF_ERROR(sjson::parse_object(uniform, value), opts);
- DynamicString type(ta);
- RETURN_IF_ERROR(sjson::parse_string(type, uniform["type"]), opts);
- const UniformType::Enum ut = name_to_uniform_type(type.c_str());
- RETURN_IF_FALSE(ut != UniformType::COUNT
- , opts
- , "Unknown uniform type: '%s'"
- , type.c_str()
- );
- const u32 name_offset = array::size(names);
- array::push(names, key.data(), key.length());
- array::push_back(names, '\0');
- UniformData ud;
- ud.type = ut;
- ud.name = StringId32(key.data(), key.length());
- ud.name_offset = name_offset;
- ud.data_offset = reserve_dynamic_data(dynamic, uh);
- switch (ud.type) {
- case UniformType::FLOAT: {
- const f32 value = RETURN_IF_ERROR(sjson::parse_float(uniform["value"]), opts);
- Vector4 data;
- data.x = value;
- data.y = 0.0f;
- data.z = 0.0f;
- data.w = 0.0f;
- reserve_dynamic_data(dynamic, data);
- break;
- }
- case UniformType::VECTOR2: {
- const Vector2 value = RETURN_IF_ERROR(sjson::parse_vector2(uniform["value"]), opts);
- Vector4 data;
- data.x = value.x;
- data.y = value.y;
- data.z = 0.0f;
- data.w = 0.0f;
- reserve_dynamic_data(dynamic, data);
- break;
- }
- case UniformType::VECTOR3: {
- const Vector3 value = RETURN_IF_ERROR(sjson::parse_vector3(uniform["value"]), opts);
- Vector4 data;
- data.x = value.x;
- data.y = value.y;
- data.z = value.z;
- data.w = 0.0f;
- reserve_dynamic_data(dynamic, data);
- break;
- }
- case UniformType::VECTOR4: {
- auto data = RETURN_IF_ERROR(sjson::parse_vector4(uniform["value"]), opts);
- reserve_dynamic_data(dynamic, data);
- break;
- }
- case UniformType::MATRIX4X4: {
- auto data = RETURN_IF_ERROR(sjson::parse_matrix4x4(uniform["value"]), opts);
- reserve_dynamic_data(dynamic, data);
- break;
- }
- default:
- CE_FATAL("Unknown uniform type");
- break;
- }
- array::push_back(uniforms, ud);
- }
- return 0;
- }
- s32 compile(CompileOptions &opts)
- {
- Buffer buf = opts.read();
- TempAllocator4096 ta;
- JsonObject obj(ta);
- RETURN_IF_ERROR(sjson::parse(obj, buf), opts);
- Array<TextureData> texdata(default_allocator());
- Array<UniformData> unidata(default_allocator());
- Array<char> names(default_allocator());
- Array<char> dynblob(default_allocator());
- opts.add_requirement_glob("*.shader");
- DynamicString shader(ta);
- RETURN_IF_ERROR(sjson::parse_string(shader, obj["shader"]), opts);
- if (json_object::has(obj, "textures")) {
- s32 err = parse_textures(texdata, names, dynblob, obj["textures"], opts);
- ENSURE_OR_RETURN(err == 0, opts);
- }
- if (json_object::has(obj, "uniforms")) {
- s32 err = parse_uniforms(unidata, names, dynblob, obj["uniforms"], opts);
- ENSURE_OR_RETURN(err == 0, opts);
- }
- MaterialResource mr;
- mr.version = RESOURCE_HEADER(RESOURCE_VERSION_MATERIAL);
- mr.shader = shader.to_string_id();
- mr.num_textures = array::size(texdata);
- mr.texture_data_offset = sizeof(mr);
- mr.num_uniforms = array::size(unidata);
- mr.uniform_data_offset = mr.texture_data_offset + sizeof(TextureData)*array::size(texdata);
- mr.names_data_size = array::size(names);
- mr.names_data_offset = mr.uniform_data_offset + sizeof(UniformData)*array::size(unidata);
- mr.dynamic_data_size = array::size(dynblob);
- mr.dynamic_data_offset = mr.names_data_offset + mr.names_data_size;
- // Write
- opts.write(mr.version);
- opts.write(mr.shader);
- opts.write(mr.num_textures);
- opts.write(mr.texture_data_offset);
- opts.write(mr.num_uniforms);
- opts.write(mr.uniform_data_offset);
- opts.write(mr.names_data_size);
- opts.write(mr.names_data_offset);
- opts.write(mr.dynamic_data_size);
- opts.write(mr.dynamic_data_offset);
- for (u32 i = 0; i < array::size(texdata); i++) {
- opts.write(texdata[i].sampler_name_offset);
- opts.write(texdata[i].name._id);
- opts.write(texdata[i].id);
- opts.write(texdata[i].data_offset);
- opts.write(texdata[i]._pad1);
- }
- for (u32 i = 0; i < array::size(unidata); i++) {
- opts.write(unidata[i].type);
- opts.write(unidata[i].name);
- opts.write(unidata[i].name_offset);
- opts.write(unidata[i].data_offset);
- }
- opts.write(names);
- opts.write(dynblob);
- return 0;
- }
- } // namespace material_resource_internal
- #endif // if CROWN_CAN_COMPILE
- } // namespace crown
|