Use better generic hashtable implement. for assets

This commit is contained in:
Doyle Thai 2016-08-30 14:19:18 +10:00
parent c93e6ca37c
commit 8b0f2f93e3
4 changed files with 154 additions and 134 deletions

View File

@ -22,6 +22,61 @@
#include "Dengine/OpenGL.h" #include "Dengine/OpenGL.h"
#include "Dengine/Platform.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 * XML Operations
@ -308,7 +363,8 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena,
if (common_strcmp(node->attribute.name, "imagePath") == 0) if (common_strcmp(node->attribute.name, "imagePath") == 0)
{ {
char *imageName = atlasXmlNode->attribute.value; char *imageName = atlasXmlNode->attribute.value;
atlasEntry = asset_makeTexAtlas(assetManager, arena, imageName); atlasEntry =
asset_getFreeTexAtlasSlot(assetManager, arena, imageName);
char *dataDir = "data/textures/WorldTraveller/"; char *dataDir = "data/textures/WorldTraveller/";
char imagePath[512] = {0}; char imagePath[512] = {0};
@ -574,29 +630,21 @@ INTERNAL AtlasSubTexture *getFreeAtlasSubTexSlot(TexAtlas *atlas,
return result; return result;
} }
INTERNAL Animation *getFreeAnimationSlot(Animation *table, u32 tableSize, INTERNAL Animation *getFreeAnimationSlot(AssetManager *assetManager,
MemoryArena *arena, char *key) MemoryArena *arena, char *key)
{ {
u32 hashIndex = common_getHashIndex(key, tableSize); HashTableEntry *entry = getFreeHashSlot(&assetManager->anims, arena, key);
Animation *result = &table[hashIndex];
if (result->key) if (entry)
{ {
while (result->next) entry->data = PLATFORM_MEM_ALLOC(arena, 1, Animation);
{ Animation *result = CAST(Animation *) entry->data;
if (common_strcmp(result->key, key) == 0) return result;
{ }
// TODO(doyle): Error correction whereby if a tex atlas already else
// exists {
ASSERT(INVALID_CODE_PATH); return NULL;
}
result = result->next;
}
result->next = PLATFORM_MEM_ALLOC(arena, 1, Animation);
result = result->next;
} }
return result;
} }
Rect asset_getSubTexRect(TexAtlas *atlas, char *key) 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) Texture *asset_getTex(AssetManager *const assetManager, const char *const key)
{ {
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->textures)); HashTableEntry *entry = getEntryFromHash(&assetManager->textures, key);
Texture *result = &assetManager->textures[hashIndex];
if (result->key) Texture *result = NULL;
{ if (entry) result = CAST(Texture *)entry->data;
while (result && common_strcmp(result->key, key) != 0)
result = result->next;
}
return result; return result;
} }
TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager, Texture *asset_getFreeTexSlot(AssetManager *const assetManager,
MemoryArena *arena, const char *const key) MemoryArena *const arena, const char *const key)
{ {
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas));
TexAtlas *result = &assetManager->texAtlas[hashIndex]; HashTableEntry *const entry =
if (result->key) getFreeHashSlot(&assetManager->textures, arena, key);
if (entry)
{ {
while (result->next) entry->data = PLATFORM_MEM_ALLOC(arena, 1, Texture);
{ Texture *result = CAST(Texture *) entry->data;
if (common_strcmp(result->key, key) == 0) return result;
{
// 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;
} }
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, TexAtlas *asset_getTexAtlas(AssetManager *const assetManager,
const char *const key) const char *const key)
{ {
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas));
TexAtlas *result = &assetManager->texAtlas[hashIndex]; HashTableEntry *entry = getEntryFromHash(&assetManager->texAtlas, key);
if (result->key)
{ TexAtlas *result = NULL;
while (result && common_strcmp(result->key, key) != 0) if (entry) result = CAST(TexAtlas *)entry->data;
result = result->next;
}
else
{
return NULL;
}
return result; 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)); HashTableEntry *entry = getEntryFromHash(&assetManager->anims, key);
Animation *result = &assetManager->anims[hashIndex];
if (result->key) Animation *result = NULL;
{ if (entry) result = CAST(Animation *)entry->data;
while (result && common_strcmp(result->key, key) != 0)
result = result->next;
}
else
{
return NULL;
}
return result; return result;
} }
@ -726,33 +772,6 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
return 0; 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 i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena,
const char *const path, const char *const key) const char *const path, const char *const key)
{ {
@ -777,7 +796,7 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena,
return -1; 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), *tex = texture_gen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight),
CAST(GLint)(bytesPerPixel), image); 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 // align the baselines up so we don't need to do baseline adjusting at
// render? // render?
char charToEncode = CAST(char)codepointRange.x; 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++) for (i32 row = 0; row < MAX_TEXTURE_SIZE; row++)
{ {
u32 *destRow = fontBitmap + (row * MAX_TEXTURE_SIZE); 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, Texture *tex = asset_getFreeTexSlot(assetManager, arena, "font");
CAST(u8 *) fontBitmap); *tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4,
assetManager->textures[texlist_font] = tex; CAST(u8 *) fontBitmap);
#ifdef WT_RENDER_FONT_FILE #ifdef WT_RENDER_FONT_FILE
/* save out a 4 channel image */ /* save out a 4 channel image */
@ -1106,7 +1126,7 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
#endif #endif
PLATFORM_MEM_FREE(arena, fontBitmap, bitmapSize); PLATFORM_MEM_FREE(arena, fontBitmap, bitmapSize);
fontAtlas->tex = &assetManager->textures[texlist_font]; fontAtlas->tex = tex;
font->atlas = fontAtlas; font->atlas = fontAtlas;
// NOTE(doyle): Formula derived from STB Font // NOTE(doyle): Formula derived from STB Font
@ -1130,17 +1150,16 @@ void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
char *animName, TexAtlas *atlas, char **subTextureNames, char *animName, TexAtlas *atlas, char **subTextureNames,
i32 numSubTextures, f32 frameDuration) i32 numSubTextures, f32 frameDuration)
{ {
Animation *anim = getFreeAnimationSlot( Animation *anim = getFreeAnimationSlot(assetManager, arena, animName);
assetManager->anims, ARRAY_COUNT(assetManager->anims), 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->atlas = atlas;
anim->frameDuration = frameDuration; anim->frameDuration = frameDuration;
anim->numFrames = numSubTextures; 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*); anim->frameList = PLATFORM_MEM_ALLOC(arena, numSubTextures, char*);
for (i32 i = 0; i < numSubTextures; i++) for (i32 i = 0; i < numSubTextures; i++)
{ {

View File

@ -116,12 +116,25 @@ INTERNAL void assetInit(GameState *state)
AssetManager *assetManager = &state->assetManager; AssetManager *assetManager = &state->assetManager;
MemoryArena *arena = &state->arena; MemoryArena *arena = &state->arena;
/* Create empty 1x1 4bpp black texture */ i32 texAtlasEntries = 8;
u32 bitmap = (0xFF << 24) | (0xFF << 16) | (0xFF << 8) | (0xFF << 0); assetManager->texAtlas.size = texAtlasEntries;
Texture *tex = asset_getAndAllocFreeTexSlot(assetManager, arena, "nullTex"); assetManager->texAtlas.entries =
*tex = texture_gen(1, 1, 4, CAST(u8 *)(&bitmap)); 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));
/* /*
********************************* *********************************

View File

@ -9,15 +9,6 @@
typedef struct MemoryArena MemoryArena; typedef struct MemoryArena MemoryArena;
typedef struct PlatformFileRead PlatformFileRead; typedef struct PlatformFileRead PlatformFileRead;
enum HashTableType
{
hashtabletype_unknown,
hashtabletype_texture,
hashtabletype_textureAtlas,
hashtabletype_animation,
hashtabletype_count,
};
typedef struct HashTableEntry typedef struct HashTableEntry
{ {
void *data; void *data;
@ -30,15 +21,14 @@ typedef struct HashTable
{ {
HashTableEntry *entries; HashTableEntry *entries;
i32 size; i32 size;
enum HashTableType type;
} HashTable; } HashTable;
typedef struct AssetManager typedef struct AssetManager
{ {
/* Hash Tables */ /* Hash Tables */
TexAtlas texAtlas[8]; HashTable texAtlas;
Texture textures[32]; HashTable textures;
Animation anims[1024]; HashTable anims;
/* Primitive Array */ /* Primitive Array */
Shader shaders[32]; Shader shaders[32];
@ -55,13 +45,12 @@ typedef struct AssetManager
*/ */
Rect asset_getSubTexRect(TexAtlas *atlas, char *key); Rect asset_getSubTexRect(TexAtlas *atlas, char *key);
Texture *asset_getTex(AssetManager *const assetManager, const char *const key); Texture *asset_getTex(AssetManager *const assetManager, const char *const key);
TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager, TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager,
MemoryArena *arena, const char *const key); MemoryArena *arena, const char *const key);
TexAtlas *asset_getTexAtlas(AssetManager *const assetManager, TexAtlas *asset_getTexAtlas(AssetManager *const assetManager,
const char *const key); const char *const key);
Texture *asset_getAndAllocFreeTexSlot(AssetManager *assetManager, Texture *asset_getFreeTexSlot(AssetManager *const assetManager,
MemoryArena *arena, MemoryArena *const arena, const char *const key);
const char *const key);
const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena,
const char *const path, const char *const path,
const char *const key); const char *const key);
@ -74,7 +63,8 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena,
void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena, void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
char *animName, TexAtlas *atlas, char **subTextureNames, char *animName, TexAtlas *atlas, char **subTextureNames,
i32 numSubTextures, f32 frameDuration); i32 numSubTextures, f32 frameDuration);
Animation *asset_getAnim(AssetManager *assetManager, char *key); Animation *asset_getAnim(AssetManager *const assetManager,
const char *const key);
/* /*
********************************* *********************************

View File

@ -111,8 +111,6 @@ typedef struct Animation
i32 numFrames; i32 numFrames;
f32 frameDuration; f32 frameDuration;
struct Animation *next;
} Animation; } Animation;
// TODO(doyle): We only use the offset and advance metric at the moment, remove? // TODO(doyle): We only use the offset and advance metric at the moment, remove?