From 8b0f2f93e3c12725dc2bcff79340515be3c5d808 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Tue, 30 Aug 2016 14:19:18 +1000 Subject: [PATCH] Use better generic hashtable implement. for assets --- src/AssetManager.c | 235 ++++++++++++++++------------- src/WorldTraveller.c | 23 ++- src/include/Dengine/AssetManager.h | 28 ++-- src/include/Dengine/Assets.h | 2 - 4 files changed, 154 insertions(+), 134 deletions(-) diff --git a/src/AssetManager.c b/src/AssetManager.c index dba1e1e..f5ef8ce 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -22,6 +22,61 @@ #include "Dengine/OpenGL.h" #include "Dengine/Platform.h" +/* + ********************************* + * Hash Table Operations + ********************************* + */ +INTERNAL HashTableEntry *getFreeHashSlot(HashTable *const table, + MemoryArena *arena, + const char *const key) +{ + u32 hashIndex = common_getHashIndex(key, table->size); + HashTableEntry *result = &table->entries[hashIndex]; + if (result->key) + { + while (result->next) + { + if (common_strcmp(result->key, key) == 0) + { + // TODO(doyle): Error hash item already exists + ASSERT(INVALID_CODE_PATH); + } + result = result->next; + } + + result->next = PLATFORM_MEM_ALLOC(arena, 1, HashTableEntry); + result = result->next; + + } + + /* Check if platform_mem_alloc failed(), otherwise always true if hash table + * entries initialised*/ + if (result) + { + // +1 Null terminator + i32 keyLen = common_strlen(key) + 1; + result->key = PLATFORM_MEM_ALLOC(arena, keyLen, char); + common_strncpy(result->key, key, keyLen); + } + + return result; +} + +INTERNAL HashTableEntry *getEntryFromHash(HashTable *const table, + const char *const key) +{ + u32 hashIndex = common_getHashIndex(key, table->size); + HashTableEntry *result = &table->entries[hashIndex]; + if (result->key) + { + while (result && common_strcmp(result->key, key) != 0) + result = result->next; + } + + return result; +} + /* ********************************* * XML Operations @@ -308,7 +363,8 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, if (common_strcmp(node->attribute.name, "imagePath") == 0) { char *imageName = atlasXmlNode->attribute.value; - atlasEntry = asset_makeTexAtlas(assetManager, arena, imageName); + atlasEntry = + asset_getFreeTexAtlasSlot(assetManager, arena, imageName); char *dataDir = "data/textures/WorldTraveller/"; char imagePath[512] = {0}; @@ -574,29 +630,21 @@ INTERNAL AtlasSubTexture *getFreeAtlasSubTexSlot(TexAtlas *atlas, return result; } -INTERNAL Animation *getFreeAnimationSlot(Animation *table, u32 tableSize, +INTERNAL Animation *getFreeAnimationSlot(AssetManager *assetManager, MemoryArena *arena, char *key) { - u32 hashIndex = common_getHashIndex(key, tableSize); - Animation *result = &table[hashIndex]; - if (result->key) + HashTableEntry *entry = getFreeHashSlot(&assetManager->anims, arena, key); + + if (entry) { - while (result->next) - { - if (common_strcmp(result->key, key) == 0) - { - // TODO(doyle): Error correction whereby if a tex atlas already - // exists - ASSERT(INVALID_CODE_PATH); - } - result = result->next; - } - - result->next = PLATFORM_MEM_ALLOC(arena, 1, Animation); - result = result->next; + entry->data = PLATFORM_MEM_ALLOC(arena, 1, Animation); + Animation *result = CAST(Animation *) entry->data; + return result; + } + else + { + return NULL; } - - return result; } Rect asset_getSubTexRect(TexAtlas *atlas, char *key) @@ -623,73 +671,71 @@ AudioVorbis *asset_getVorbis(AssetManager *assetManager, Texture *asset_getTex(AssetManager *const assetManager, const char *const key) { - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->textures)); - Texture *result = &assetManager->textures[hashIndex]; - if (result->key) - { - while (result && common_strcmp(result->key, key) != 0) - result = result->next; - } + HashTableEntry *entry = getEntryFromHash(&assetManager->textures, key); + + Texture *result = NULL; + if (entry) result = CAST(Texture *)entry->data; return result; } -TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager, - MemoryArena *arena, const char *const key) +Texture *asset_getFreeTexSlot(AssetManager *const assetManager, + MemoryArena *const arena, const char *const key) { - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas)); - TexAtlas *result = &assetManager->texAtlas[hashIndex]; - if (result->key) + + HashTableEntry *const entry = + getFreeHashSlot(&assetManager->textures, arena, key); + + if (entry) { - while (result->next) - { - if (common_strcmp(result->key, key) == 0) - { - // TODO(doyle): Error correction whereby if a tex atlas already - // exists - ASSERT(INVALID_CODE_PATH); - } - result = result->next; - } - - result->next = PLATFORM_MEM_ALLOC(arena, 1, TexAtlas); - result = result->next; + entry->data = PLATFORM_MEM_ALLOC(arena, 1, Texture); + Texture *result = CAST(Texture *) entry->data; + return result; } + else + { + return NULL; + } +} - return result; +TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, + MemoryArena *arena, const char *const key) +{ + + HashTableEntry *const entry = + getFreeHashSlot(&assetManager->texAtlas, arena, key); + + if (entry) + { + entry->data = PLATFORM_MEM_ALLOC(arena, 1, TexAtlas); + TexAtlas *result = CAST(TexAtlas *) entry->data; + return result; + } + else + { + return NULL; + } } TexAtlas *asset_getTexAtlas(AssetManager *const assetManager, const char *const key) { - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas)); - TexAtlas *result = &assetManager->texAtlas[hashIndex]; - if (result->key) - { - while (result && common_strcmp(result->key, key) != 0) - result = result->next; - } - else - { - return NULL; - } + + HashTableEntry *entry = getEntryFromHash(&assetManager->texAtlas, key); + + TexAtlas *result = NULL; + if (entry) result = CAST(TexAtlas *)entry->data; return result; } -Animation *asset_getAnim(AssetManager *assetManager, char *key) +Animation *asset_getAnim(AssetManager *const assetManager, + const char *const key) { - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->anims)); - Animation *result = &assetManager->anims[hashIndex]; - if (result->key) - { - while (result && common_strcmp(result->key, key) != 0) - result = result->next; - } - else - { - return NULL; - } + HashTableEntry *entry = getEntryFromHash(&assetManager->anims, key); + + Animation *result = NULL; + if (entry) result = CAST(Animation *)entry->data; return result; } @@ -726,33 +772,6 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, return 0; } -// TODO(doyle): Revise passing in the assetmanager -Texture *asset_getAndAllocFreeTexSlot(AssetManager *assetManager, - MemoryArena *arena, const char *const key) -{ - i32 texListSize = ARRAY_COUNT(assetManager->textures); - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->textures)); - Texture *result = &assetManager->textures[hashIndex]; - if (result->key) - { - while (result->next) - { - if (common_strcmp(result->key, key) == 0) - { - // TODO(doyle): Error correction whereby if a tex atlas already - // exists - ASSERT(INVALID_CODE_PATH); - } - result = result->next; - } - - result->next = PLATFORM_MEM_ALLOC(arena, 1, Texture); - result = result->next; - } - - return result; -} - const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, const char *const path, const char *const key) { @@ -777,7 +796,7 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, return -1; } - Texture *tex = asset_getAndAllocFreeTexSlot(assetManager, arena, key); + Texture *tex = asset_getFreeTexSlot(assetManager, arena, key); *tex = texture_gen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight), CAST(GLint)(bytesPerPixel), image); @@ -1015,7 +1034,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, // align the baselines up so we don't need to do baseline adjusting at // render? char charToEncode = CAST(char)codepointRange.x; - TexAtlas *fontAtlas = asset_makeTexAtlas(assetManager, arena, "font"); + TexAtlas *fontAtlas = + asset_getFreeTexAtlasSlot(assetManager, arena, "font"); for (i32 row = 0; row < MAX_TEXTURE_SIZE; row++) { u32 *destRow = fontBitmap + (row * MAX_TEXTURE_SIZE); @@ -1095,9 +1115,9 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, } } - Texture tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, - CAST(u8 *) fontBitmap); - assetManager->textures[texlist_font] = tex; + Texture *tex = asset_getFreeTexSlot(assetManager, arena, "font"); + *tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, + CAST(u8 *) fontBitmap); #ifdef WT_RENDER_FONT_FILE /* save out a 4 channel image */ @@ -1106,7 +1126,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, #endif PLATFORM_MEM_FREE(arena, fontBitmap, bitmapSize); - fontAtlas->tex = &assetManager->textures[texlist_font]; + fontAtlas->tex = tex; font->atlas = fontAtlas; // NOTE(doyle): Formula derived from STB Font @@ -1130,17 +1150,16 @@ void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena, char *animName, TexAtlas *atlas, char **subTextureNames, i32 numSubTextures, f32 frameDuration) { - Animation *anim = getFreeAnimationSlot( - assetManager->anims, ARRAY_COUNT(assetManager->anims), arena, animName); + Animation *anim = getFreeAnimationSlot(assetManager, arena, animName); + + /* Use same animation ptr for name from entry key */ + HashTableEntry *entry = getEntryFromHash(&assetManager->anims, animName); + anim->name = entry->key; anim->atlas = atlas; anim->frameDuration = frameDuration; anim->numFrames = numSubTextures; - // NOTE(doyle): +1 for the null terminator - anim->name = PLATFORM_MEM_ALLOC(arena, common_strlen(animName) + 1, char); - common_strncpy(anim->name, animName, common_strlen(animName)); - anim->frameList = PLATFORM_MEM_ALLOC(arena, numSubTextures, char*); for (i32 i = 0; i < numSubTextures; i++) { diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index 1317013..e3af02c 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -116,12 +116,25 @@ INTERNAL void assetInit(GameState *state) AssetManager *assetManager = &state->assetManager; MemoryArena *arena = &state->arena; - /* Create empty 1x1 4bpp black texture */ - u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); - Texture *tex = asset_getAndAllocFreeTexSlot(assetManager, arena, "nullTex"); - *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); + i32 texAtlasEntries = 8; + assetManager->texAtlas.size = texAtlasEntries; + assetManager->texAtlas.entries = + PLATFORM_MEM_ALLOC(arena, texAtlasEntries, HashTableEntry); - //assetManager->texAtlas.type = hashtabletype_textureAtlas; + i32 texEntries = 32; + assetManager->textures.size = texEntries; + assetManager->textures.entries = + PLATFORM_MEM_ALLOC(arena, texEntries, HashTableEntry); + + i32 animEntries = 1024; + assetManager->anims.size = animEntries; + assetManager->anims.entries = + PLATFORM_MEM_ALLOC(arena, animEntries, HashTableEntry); + + /* Create empty 1x1 4bpp black texture */ + u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); + Texture *tex = asset_getFreeTexSlot(assetManager, arena, "nullTex"); + *tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); /* ********************************* diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 36ca04a..000dcaf 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -9,15 +9,6 @@ typedef struct MemoryArena MemoryArena; typedef struct PlatformFileRead PlatformFileRead; -enum HashTableType -{ - hashtabletype_unknown, - hashtabletype_texture, - hashtabletype_textureAtlas, - hashtabletype_animation, - hashtabletype_count, -}; - typedef struct HashTableEntry { void *data; @@ -30,15 +21,14 @@ typedef struct HashTable { HashTableEntry *entries; i32 size; - enum HashTableType type; } HashTable; typedef struct AssetManager { /* Hash Tables */ - TexAtlas texAtlas[8]; - Texture textures[32]; - Animation anims[1024]; + HashTable texAtlas; + HashTable textures; + HashTable anims; /* Primitive Array */ Shader shaders[32]; @@ -55,13 +45,12 @@ typedef struct AssetManager */ Rect asset_getSubTexRect(TexAtlas *atlas, char *key); Texture *asset_getTex(AssetManager *const assetManager, const char *const key); -TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager, - MemoryArena *arena, const char *const key); +TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, + MemoryArena *arena, const char *const key); TexAtlas *asset_getTexAtlas(AssetManager *const assetManager, const char *const key); -Texture *asset_getAndAllocFreeTexSlot(AssetManager *assetManager, - MemoryArena *arena, - const char *const key); +Texture *asset_getFreeTexSlot(AssetManager *const assetManager, + MemoryArena *const arena, const char *const key); const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, const char *const path, const char *const key); @@ -74,7 +63,8 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena, char *animName, TexAtlas *atlas, char **subTextureNames, i32 numSubTextures, f32 frameDuration); -Animation *asset_getAnim(AssetManager *assetManager, char *key); +Animation *asset_getAnim(AssetManager *const assetManager, + const char *const key); /* ********************************* diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h index 55a16b9..715e13d 100644 --- a/src/include/Dengine/Assets.h +++ b/src/include/Dengine/Assets.h @@ -111,8 +111,6 @@ typedef struct Animation i32 numFrames; f32 frameDuration; - - struct Animation *next; } Animation; // TODO(doyle): We only use the offset and advance metric at the moment, remove?