gs_asset.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*==============================================================================================================
  2. * Copyright (c) 2020 John Jackson
  3. * GSAsset: Asset Manager Util for Gunslinger
  4. * File: gs_asset.h
  5. * Github: https://github.com/MrFrenik/gunslinger
  6. * All Rights Reserved
  7. * MIT License
  8. * May all those that this source may reach be blessed by the LORD and find peace and joy in life.
  9. * Everyone who drinks of this water will be thirsty again; but whoever drinks of the water
  10. * that I will give him shall never thirst; John 4:13-14
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  12. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
  13. * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
  14. * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  15. * The above copyright, blessing, biblical verse, notice and this permission notice shall be included in all
  16. * copies or substantial portions of the Software.
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  18. * TO THE WARRANTIES OF MECHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  20. * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. =================================================================================================================*/
  23. #ifndef GS_ASSET_H
  24. #define GS_ASSET_H
  25. /*
  26. USAGE: (IMPORTANT)
  27. =================================================================================================================
  28. Before including, define the gunslinger asset manager implementation like this:
  29. #define GS_ASSET_IMPL
  30. in EXACTLY ONE C or C++ file that includes this header, BEFORE the
  31. include, like this:
  32. #define GS_ASSET_IMPL
  33. #include "gs_asset.h"
  34. All other files should just #include "gs_asset.h" without the #define.
  35. MUST include "gs.h" and declare GS_IMPL BEFORE this file, since this file relies on that:
  36. #define GS_IMPL
  37. #include "gs.h"
  38. #define GS_ASSET_IMPL
  39. #include "gs_asset.h"
  40. ================================================================================================================
  41. */
  42. /*==== Interface ====*/
  43. /** @defgroup gs_asset_util Asset Util
  44. * Gunslinger Asset Util
  45. * @{
  46. */
  47. // Asset handle
  48. typedef struct gs_asset_s
  49. {
  50. uint64_t type_id;
  51. uint32_t asset_id;
  52. uint32_t importer_id; // 'Unique' id of importer, used for type safety
  53. } gs_asset_t;
  54. GS_API_DECL gs_asset_t __gs_asset_handle_create_impl(uint64_t type_id, uint32_t asset_id, uint32_t importer_id);
  55. #define gs_asset_handle_create(T, ID, IMPID)\
  56. __gs_asset_handle_create_impl(gs_hash_str64(gs_to_str(T)), ID, IMPID)
  57. typedef void (* gs_asset_load_func)(const char *,void *,...);
  58. typedef gs_asset_t (* gs_asset_default_func)(void *);
  59. typedef struct gs_asset_importer_desc_t {
  60. void (* load_from_file)(const char* path, void* out, ...);
  61. gs_asset_t (* default_asset)(void* out);
  62. } gs_asset_importer_desc_t;
  63. typedef struct gs_asset_importer_t
  64. {
  65. void* slot_array;
  66. void* slot_array_data_ptr;
  67. void* slot_array_indices_ptr;
  68. void* tmp_ptr;
  69. uint32_t tmpid;
  70. size_t data_size;
  71. gs_asset_importer_desc_t desc;
  72. uint32_t importer_id;
  73. gs_asset_t default_asset;
  74. } gs_asset_importer_t;
  75. GS_API_DECL void gs_asset_default_load_from_file( const char* path, void* out );
  76. GS_API_DECL gs_asset_t gs_asset_default_asset();
  77. GS_API_DECL void gs_asset_importer_set_desc(gs_asset_importer_t* imp, gs_asset_importer_desc_t* desc);
  78. #define gs_assets_get_importerp(AM, T)\
  79. (gs_hash_table_getp((AM)->importers, gs_hash_str64(gs_to_str(T))))
  80. #ifdef __cplusplus
  81. #define gsa_imsa(IMPORTER, T)\
  82. (decltype(gs_slot_array(T))(IMPORTER)->slot_array)
  83. #else
  84. #define gsa_imsa(IMPORTER, T)\
  85. ((gs_slot_array(T))(IMPORTER)->slot_array)
  86. #endif
  87. #define gs_assets_register_importer(AM, T, DESC)\
  88. do {\
  89. gs_asset_importer_t ai = gs_default_val();\
  90. ai.data_size = sizeof(T);\
  91. ai.importer_id = (AM)->free_importer_id++;\
  92. gs_asset_importer_set_desc(&ai, (gs_asset_importer_desc_t*)DESC);\
  93. size_t sz = 2 * sizeof(void*) + sizeof(T);\
  94. gs_slot_array(T) sa = NULL;\
  95. gs_slot_array_init((void**)&sa, sizeof(*sa));\
  96. gs_dyn_array_init((void**)&sa->indices, sizeof(uint32_t));\
  97. gs_dyn_array_init((void**)&sa->data, sizeof(T));\
  98. ai.slot_array = (void*)sa;\
  99. ai.tmp_ptr = (void*)&sa->tmp;\
  100. ai.slot_array_indices_ptr = (void*)sa->indices;\
  101. ai.slot_array_data_ptr = (void*)sa->data;\
  102. if (!ai.desc.load_from_file) {ai.desc.load_from_file = (gs_asset_load_func)&gs_asset_default_load_from_file;}\
  103. gs_hash_table_insert((AM)->importers, gs_hash_str64(gs_to_str(T)), ai);\
  104. } while(0)
  105. // Need a way to be able to print upon assert
  106. #define gs_assets_load_from_file(AM, T, PATH, ...)\
  107. (\
  108. /*gs_assert(gs_hash_table_key_exists((AM)->importers, gs_hash_str64(gs_to_str(T)))),*/\
  109. (AM)->tmpi = gs_hash_table_getp((AM)->importers, gs_hash_str64(gs_to_str(T))),\
  110. (AM)->tmpi->desc.load_from_file(PATH, (AM)->tmpi->tmp_ptr, ## __VA_ARGS__),\
  111. (AM)->tmpi->tmpid = gs_slot_array_insert_func(&(AM)->tmpi->slot_array_indices_ptr, &(AM)->tmpi->slot_array_data_ptr, (AM)->tmpi->tmp_ptr, (AM)->tmpi->data_size, NULL),\
  112. gs_asset_handle_create(T, (AM)->tmpi->tmpid, (AM)->tmpi->importer_id)\
  113. )
  114. #define gs_assets_create_asset(AM, T, DATA)\
  115. (\
  116. /*gs_assert(gs_hash_table_key_exists((AM)->importers, gs_hash_str64(gs_to_str(T)))),*/\
  117. (AM)->tmpi = gs_hash_table_getp((AM)->importers, gs_hash_str64(gs_to_str(T))),\
  118. (AM)->tmpi->tmp_ptr = (DATA),\
  119. (AM)->tmpi->tmpid = gs_slot_array_insert_func(&(AM)->tmpi->slot_array_indices_ptr, &(AM)->tmpi->slot_array_data_ptr, (AM)->tmpi->tmp_ptr, (AM)->tmpi->data_size, NULL),\
  120. gs_asset_handle_create(T, (AM)->tmpi->tmpid, (AM)->tmpi->importer_id)\
  121. )
  122. typedef struct gs_asset_manager_t
  123. {
  124. gs_hash_table(uint64_t, gs_asset_importer_t) importers; // Maps hashed types to importer
  125. gs_asset_importer_t* tmpi; // Temporary importer for caching
  126. uint32_t free_importer_id;
  127. } gs_asset_manager_t;
  128. GS_API_DECL gs_asset_manager_t gs_asset_manager_new();
  129. GS_API_DECL void gs_asset_manager_free(gs_asset_manager_t* am);
  130. GS_API_DECL void* __gs_assets_getp_impl(gs_asset_manager_t* am, uint64_t type_id, gs_asset_t hndl);
  131. #define gs_assets_getp(AM, T, HNDL)\
  132. (T*)(__gs_assets_getp_impl(AM, gs_hash_str64(gs_to_str(T)), HNDL))
  133. #define gs_assets_get(AM, T, HNDL)\
  134. *(gs_assets_getp(AM, T, HNDL));
  135. /** @} */ // end of gs_asset_util
  136. /*==== Implementation ====*/
  137. #ifdef GS_ASSET_IMPL
  138. gs_asset_t __gs_asset_handle_create_impl(uint64_t type_id, uint32_t asset_id, uint32_t importer_id)
  139. {
  140. gs_asset_t asset = gs_default_val();
  141. asset.type_id = type_id;
  142. asset.asset_id = asset_id;
  143. asset.importer_id = importer_id;
  144. return asset;
  145. }
  146. gs_asset_manager_t gs_asset_manager_new()
  147. {
  148. gs_asset_manager_t assets = gs_default_val();
  149. // Register default asset importers
  150. gs_asset_importer_desc_t tex_desc = gs_default_val();
  151. gs_asset_importer_desc_t font_desc = gs_default_val();
  152. gs_asset_importer_desc_t audio_desc = gs_default_val();
  153. gs_asset_importer_desc_t mesh_desc = gs_default_val();
  154. gs_asset_importer_desc_t asset_desc = gs_default_val();
  155. tex_desc.load_from_file = (gs_asset_load_func)&gs_asset_texture_load_from_file;
  156. font_desc.load_from_file = (gs_asset_load_func)&gs_asset_font_load_from_file;
  157. audio_desc.load_from_file = (gs_asset_load_func)&gs_asset_audio_load_from_file;
  158. mesh_desc.load_from_file = (gs_asset_load_func)&gs_asset_mesh_load_from_file;
  159. gs_assets_register_importer(&assets, gs_asset_t, &asset_desc);
  160. gs_assets_register_importer(&assets, gs_asset_texture_t, &tex_desc);
  161. gs_assets_register_importer(&assets, gs_asset_font_t, &font_desc);
  162. gs_assets_register_importer(&assets, gs_asset_audio_t, &audio_desc);
  163. gs_assets_register_importer(&assets, gs_asset_mesh_t, &mesh_desc);
  164. return assets;
  165. }
  166. void gs_asset_manager_free(gs_asset_manager_t* am)
  167. {
  168. // Free all data
  169. }
  170. void* __gs_assets_getp_impl(gs_asset_manager_t* am, uint64_t type_id, gs_asset_t hndl)
  171. {
  172. if (type_id != hndl.type_id) {
  173. gs_println("Warning: Type id: %zu doesn't match handle type id: %zu.", type_id, hndl.type_id);
  174. gs_assert(false);
  175. return NULL;
  176. }
  177. // Need to grab the appropriate importer based on type
  178. if (!gs_hash_table_key_exists(am->importers, type_id)) {
  179. gs_println("Warning: Importer type %zu does not exist.", type_id);
  180. gs_assert(false);
  181. return NULL;
  182. }
  183. gs_asset_importer_t* imp = gs_hash_table_getp(am->importers, type_id);
  184. // Vertify that importer id and handle importer id align
  185. if (imp->importer_id != hndl.importer_id) {
  186. gs_println("Warning: Importer id: %zu does not match handle importer id: %zu.",
  187. imp->importer_id, hndl.importer_id);
  188. gs_assert(false);
  189. return NULL;
  190. }
  191. // Need to get data index from slot array using hndl asset id
  192. size_t offset = (((sizeof(uint32_t) * hndl.asset_id) + 3) & (~3));
  193. uint32_t idx = *(uint32_t*)((char*)(imp->slot_array_indices_ptr) + offset);
  194. // Then need to return pointer to data at index
  195. size_t data_sz = imp->data_size;
  196. size_t s = data_sz == 8 ? 7 : 3;
  197. offset = (((data_sz * idx) + s) & (~s));
  198. return ((char*)(imp->slot_array_data_ptr) + offset);
  199. }
  200. void gs_asset_importer_set_desc(gs_asset_importer_t* imp, gs_asset_importer_desc_t* desc)
  201. {
  202. imp->desc = desc ? *desc : imp->desc;
  203. imp->desc.load_from_file = imp->desc.load_from_file ? (gs_asset_load_func)imp->desc.load_from_file
  204. : (gs_asset_load_func)&gs_asset_default_load_from_file;
  205. imp->desc.default_asset = imp->desc.default_asset ? (gs_asset_default_func)imp->desc.default_asset
  206. : (gs_asset_default_func)&gs_asset_default_asset;
  207. }
  208. gs_asset_t gs_asset_default_asset()
  209. {
  210. gs_asset_t a = gs_default_val();
  211. return a;
  212. }
  213. void gs_asset_default_load_from_file(const char* path, void* out)
  214. {
  215. // Nothing...
  216. }
  217. #undef GS_ASSET_IMPL
  218. #endif // GS_ASSET_IMPL
  219. #endif // GS_ASSET_H