material_resource.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "core/containers/array.inl"
  6. #include "core/containers/vector.inl"
  7. #include "core/filesystem/filesystem.h"
  8. #include "core/filesystem/reader_writer.h"
  9. #include "core/json/json_object.inl"
  10. #include "core/json/sjson.h"
  11. #include "core/memory/temp_allocator.inl"
  12. #include "core/strings/dynamic_string.inl"
  13. #include "core/strings/string.inl"
  14. #include "core/strings/string_id.inl"
  15. #include "core/strings/string_view.inl"
  16. #include "device/device.h"
  17. #include "resource/compile_options.inl"
  18. #include "resource/material_resource.h"
  19. #include "resource/resource_manager.h"
  20. #include "world/material_manager.h"
  21. namespace crown
  22. {
  23. namespace material_resource
  24. {
  25. UniformData *uniform_data_array(const MaterialResource *mr)
  26. {
  27. return (UniformData *)((char *)mr + mr->uniform_data_offset);
  28. }
  29. u32 uniform_data_index(const MaterialResource *mr, const UniformData *ud, StringId32 name)
  30. {
  31. for (u32 i = 0, n = mr->num_uniforms; i < n; ++i) {
  32. if (ud[i].name == name)
  33. return i;
  34. }
  35. CE_FATAL("Unknown uniform");
  36. return UINT32_MAX;
  37. }
  38. const char *uniform_name(const MaterialResource *mr, const UniformData *ud, u32 i)
  39. {
  40. return (const char *)mr + mr->names_data_offset + ud[i].name_offset;
  41. }
  42. TextureData *texture_data_array(const MaterialResource *mr)
  43. {
  44. return (TextureData *)((char *)mr + mr->texture_data_offset);
  45. }
  46. u32 texture_data_index(const MaterialResource *mr, const TextureData *td, StringId32 name)
  47. {
  48. for (u32 i = 0, n = mr->num_textures; i < n; ++i) {
  49. if (td[i].name == name)
  50. return i;
  51. }
  52. CE_FATAL("Unknown texture");
  53. return UINT32_MAX;
  54. }
  55. const char *texture_name(const MaterialResource *mr, const TextureData *td, u32 i)
  56. {
  57. return (const char *)mr + mr->names_data_offset + td[i].sampler_name_offset;
  58. }
  59. UniformHandle *uniform_handle(const UniformData *ud, u32 i, char *dynamic)
  60. {
  61. return (UniformHandle *)(dynamic + ud[i].data_offset);
  62. }
  63. TextureHandle *texture_handle(const TextureData *td, u32 i, char *dynamic)
  64. {
  65. return (TextureHandle *)(dynamic + td[i].data_offset);
  66. }
  67. } // namespace material_resource
  68. namespace material_resource_internal
  69. {
  70. void online(StringId64 id, ResourceManager &rm)
  71. {
  72. device()->_material_manager->online(id, rm);
  73. }
  74. void offline(StringId64 id, ResourceManager &rm)
  75. {
  76. device()->_material_manager->offline(id, rm);
  77. }
  78. } // namespace material_resource_internal
  79. #if CROWN_CAN_COMPILE
  80. namespace material_resource_internal
  81. {
  82. struct UniformTypeInfo
  83. {
  84. const char *name;
  85. UniformType::Enum type;
  86. };
  87. static const UniformTypeInfo s_uniform_type_info[] =
  88. {
  89. { "float", UniformType::FLOAT },
  90. { "vector2", UniformType::VECTOR2 },
  91. { "vector3", UniformType::VECTOR3 },
  92. { "vector4", UniformType::VECTOR4 },
  93. { "matrix4x4", UniformType::MATRIX4X4 }
  94. };
  95. CE_STATIC_ASSERT(countof(s_uniform_type_info) == UniformType::COUNT);
  96. static UniformType::Enum name_to_uniform_type(const char *name)
  97. {
  98. for (u32 i = 0; i < countof(s_uniform_type_info); ++i) {
  99. if (strcmp(s_uniform_type_info[i].name, name) == 0)
  100. return s_uniform_type_info[i].type;
  101. }
  102. return UniformType::COUNT;
  103. }
  104. struct Data
  105. {
  106. Array<TextureData> textures;
  107. Array<UniformData> uniforms;
  108. Array<char> dynamic;
  109. Data()
  110. : textures(default_allocator())
  111. , uniforms(default_allocator())
  112. , dynamic(default_allocator())
  113. {
  114. }
  115. };
  116. // Returns offset to start of data
  117. template<typename T>
  118. static u32 reserve_dynamic_data(Array<char> &dynamic, T data)
  119. {
  120. u32 offt = array::size(dynamic);
  121. array::push(dynamic, (char *)&data, sizeof(data));
  122. return offt;
  123. }
  124. static s32 parse_textures(Array<TextureData> &textures, Array<char> &names, Array<char> &dynamic, const char *json, CompileOptions &opts)
  125. {
  126. TempAllocator4096 ta;
  127. JsonObject obj(ta);
  128. RETURN_IF_ERROR(sjson::parse(obj, json), opts);
  129. auto cur = json_object::begin(obj);
  130. auto end = json_object::end(obj);
  131. for (; cur != end; ++cur) {
  132. JSON_OBJECT_SKIP_HOLE(obj, cur);
  133. const StringView key = cur->first;
  134. const char *value = cur->second;
  135. DynamicString texture(ta);
  136. RETURN_IF_ERROR(sjson::parse_string(texture, value), opts);
  137. RETURN_IF_RESOURCE_MISSING("texture", texture.c_str(), opts);
  138. opts.add_requirement("texture", texture.c_str());
  139. TextureHandle th;
  140. th.sampler_handle = 0;
  141. th.texture_handle = 0;
  142. const u32 sampler_name_offset = array::size(names);
  143. array::push(names, key.data(), key.length());
  144. array::push_back(names, '\0');
  145. TextureData td;
  146. td.sampler_name_offset = sampler_name_offset;
  147. td.name = StringId32(key.data(), key.length());
  148. td.id = RETURN_IF_ERROR(sjson::parse_resource_name(value), opts);
  149. td.data_offset = reserve_dynamic_data(dynamic, th);
  150. td._pad1 = 0;
  151. array::push_back(textures, td);
  152. }
  153. return 0;
  154. }
  155. static s32 parse_uniforms(Array<UniformData> &uniforms, Array<char> &names, Array<char> &dynamic, const char *json, CompileOptions &opts)
  156. {
  157. TempAllocator4096 ta;
  158. JsonObject obj(ta);
  159. RETURN_IF_ERROR(sjson::parse(obj, json), opts);
  160. auto cur = json_object::begin(obj);
  161. auto end = json_object::end(obj);
  162. for (; cur != end; ++cur) {
  163. JSON_OBJECT_SKIP_HOLE(obj, cur);
  164. const StringView key = cur->first;
  165. const char *value = cur->second;
  166. UniformHandle uh;
  167. uh.uniform_handle = 0;
  168. JsonObject uniform(ta);
  169. RETURN_IF_ERROR(sjson::parse_object(uniform, value), opts);
  170. DynamicString type(ta);
  171. RETURN_IF_ERROR(sjson::parse_string(type, uniform["type"]), opts);
  172. const UniformType::Enum ut = name_to_uniform_type(type.c_str());
  173. RETURN_IF_FALSE(ut != UniformType::COUNT
  174. , opts
  175. , "Unknown uniform type: '%s'"
  176. , type.c_str()
  177. );
  178. const u32 name_offset = array::size(names);
  179. array::push(names, key.data(), key.length());
  180. array::push_back(names, '\0');
  181. UniformData ud;
  182. ud.type = ut;
  183. ud.name = StringId32(key.data(), key.length());
  184. ud.name_offset = name_offset;
  185. ud.data_offset = reserve_dynamic_data(dynamic, uh);
  186. switch (ud.type) {
  187. case UniformType::FLOAT: {
  188. const f32 value = RETURN_IF_ERROR(sjson::parse_float(uniform["value"]), opts);
  189. Vector4 data;
  190. data.x = value;
  191. data.y = 0.0f;
  192. data.z = 0.0f;
  193. data.w = 0.0f;
  194. reserve_dynamic_data(dynamic, data);
  195. break;
  196. }
  197. case UniformType::VECTOR2: {
  198. const Vector2 value = RETURN_IF_ERROR(sjson::parse_vector2(uniform["value"]), opts);
  199. Vector4 data;
  200. data.x = value.x;
  201. data.y = value.y;
  202. data.z = 0.0f;
  203. data.w = 0.0f;
  204. reserve_dynamic_data(dynamic, data);
  205. break;
  206. }
  207. case UniformType::VECTOR3: {
  208. const Vector3 value = RETURN_IF_ERROR(sjson::parse_vector3(uniform["value"]), opts);
  209. Vector4 data;
  210. data.x = value.x;
  211. data.y = value.y;
  212. data.z = value.z;
  213. data.w = 0.0f;
  214. reserve_dynamic_data(dynamic, data);
  215. break;
  216. }
  217. case UniformType::VECTOR4: {
  218. auto data = RETURN_IF_ERROR(sjson::parse_vector4(uniform["value"]), opts);
  219. reserve_dynamic_data(dynamic, data);
  220. break;
  221. }
  222. case UniformType::MATRIX4X4: {
  223. auto data = RETURN_IF_ERROR(sjson::parse_matrix4x4(uniform["value"]), opts);
  224. reserve_dynamic_data(dynamic, data);
  225. break;
  226. }
  227. default:
  228. CE_FATAL("Unknown uniform type");
  229. break;
  230. }
  231. array::push_back(uniforms, ud);
  232. }
  233. return 0;
  234. }
  235. s32 compile(CompileOptions &opts)
  236. {
  237. Buffer buf = opts.read();
  238. TempAllocator4096 ta;
  239. JsonObject obj(ta);
  240. RETURN_IF_ERROR(sjson::parse(obj, buf), opts);
  241. Array<TextureData> texdata(default_allocator());
  242. Array<UniformData> unidata(default_allocator());
  243. Array<char> names(default_allocator());
  244. Array<char> dynblob(default_allocator());
  245. opts.add_requirement_glob("*.shader");
  246. DynamicString shader(ta);
  247. RETURN_IF_ERROR(sjson::parse_string(shader, obj["shader"]), opts);
  248. if (json_object::has(obj, "textures")) {
  249. s32 err = parse_textures(texdata, names, dynblob, obj["textures"], opts);
  250. ENSURE_OR_RETURN(err == 0, opts);
  251. }
  252. if (json_object::has(obj, "uniforms")) {
  253. s32 err = parse_uniforms(unidata, names, dynblob, obj["uniforms"], opts);
  254. ENSURE_OR_RETURN(err == 0, opts);
  255. }
  256. MaterialResource mr;
  257. mr.version = RESOURCE_HEADER(RESOURCE_VERSION_MATERIAL);
  258. mr.shader = shader.to_string_id();
  259. mr.num_textures = array::size(texdata);
  260. mr.texture_data_offset = sizeof(mr);
  261. mr.num_uniforms = array::size(unidata);
  262. mr.uniform_data_offset = mr.texture_data_offset + sizeof(TextureData)*array::size(texdata);
  263. mr.names_data_size = array::size(names);
  264. mr.names_data_offset = mr.uniform_data_offset + sizeof(UniformData)*array::size(unidata);
  265. mr.dynamic_data_size = array::size(dynblob);
  266. mr.dynamic_data_offset = mr.names_data_offset + mr.names_data_size;
  267. // Write
  268. opts.write(mr.version);
  269. opts.write(mr.shader);
  270. opts.write(mr.num_textures);
  271. opts.write(mr.texture_data_offset);
  272. opts.write(mr.num_uniforms);
  273. opts.write(mr.uniform_data_offset);
  274. opts.write(mr.names_data_size);
  275. opts.write(mr.names_data_offset);
  276. opts.write(mr.dynamic_data_size);
  277. opts.write(mr.dynamic_data_offset);
  278. for (u32 i = 0; i < array::size(texdata); i++) {
  279. opts.write(texdata[i].sampler_name_offset);
  280. opts.write(texdata[i].name._id);
  281. opts.write(texdata[i].id);
  282. opts.write(texdata[i].data_offset);
  283. opts.write(texdata[i]._pad1);
  284. }
  285. for (u32 i = 0; i < array::size(unidata); i++) {
  286. opts.write(unidata[i].type);
  287. opts.write(unidata[i].name);
  288. opts.write(unidata[i].name_offset);
  289. opts.write(unidata[i].data_offset);
  290. }
  291. opts.write(names);
  292. opts.write(dynblob);
  293. return 0;
  294. }
  295. } // namespace material_resource_internal
  296. #endif // if CROWN_CAN_COMPILE
  297. } // namespace crown