From e9db7b0570ba8eaf5f22c533b295223b04f36c70 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Tue, 30 Aug 2016 18:42:37 +1000 Subject: [PATCH] Convert subtextures to use hash tables Also clean up and add some block comments to aid code separation mainly in AssetManager. --- src/AssetManager.c | 626 +++++++++++++++-------------- src/Entity.c | 6 +- src/Renderer.c | 15 +- src/WorldTraveller.c | 15 +- src/include/Dengine/AssetManager.h | 33 +- src/include/Dengine/Assets.h | 65 +-- 6 files changed, 396 insertions(+), 364 deletions(-) diff --git a/src/AssetManager.c b/src/AssetManager.c index f5ef8ce..1f7d454 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -51,7 +51,7 @@ INTERNAL HashTableEntry *getFreeHashSlot(HashTable *const table, } /* Check if platform_mem_alloc failed(), otherwise always true if hash table - * entries initialised*/ + * entries initialised, assign key to hash entry */ if (result) { // +1 Null terminator @@ -77,6 +77,205 @@ INTERNAL HashTableEntry *getEntryFromHash(HashTable *const table, return result; } +/* + ********************************* + * Texture Operations + ********************************* + */ +INTERNAL Rect *getFreeAtlasSubTexSlot(TexAtlas *const atlas, + MemoryArena *const arena, + const char *const key) +{ + HashTableEntry *entry = getFreeHashSlot(&atlas->subTex, arena, key); + + if (entry) + { + entry->data = PLATFORM_MEM_ALLOC(arena, 1, Rect); + Rect *result = CAST(Rect *) entry->data; + return result; + } + else + { + return NULL; + } +} + +Rect *asset_getAtlasSubTex(TexAtlas *const atlas, const char *const key) +{ + + HashTableEntry *entry = getEntryFromHash(&atlas->subTex, key); + + Rect *result = NULL; + if (entry) result = CAST(Rect *) entry->data; + + return result; +} + +Texture *asset_getTex(AssetManager *const assetManager, const char *const key) +{ + HashTableEntry *entry = getEntryFromHash(&assetManager->textures, key); + + Texture *result = NULL; + if (entry) result = CAST(Texture *)entry->data; + + return result; +} + +TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, + MemoryArena *arena, const char *const key, + i32 numSubTex) +{ + + HashTableEntry *const entry = + getFreeHashSlot(&assetManager->texAtlas, arena, key); + + if (entry) + { + entry->data = PLATFORM_MEM_ALLOC(arena, 1, TexAtlas); + TexAtlas *result = CAST(TexAtlas *) entry->data; + + if (result) + { + result->subTex.size = numSubTex; + result->subTex.entries = + PLATFORM_MEM_ALLOC(arena, numSubTex, HashTableEntry); + + if (!result->subTex.entries) + { + PLATFORM_MEM_FREE(arena, result, sizeof(TexAtlas)); + result = NULL; + } + } + + return result; + } + else + { + return NULL; + } +} + +TexAtlas *asset_getTexAtlas(AssetManager *const assetManager, + const char *const key) +{ + + HashTableEntry *entry = getEntryFromHash(&assetManager->texAtlas, key); + + TexAtlas *result = NULL; + if (entry) result = CAST(TexAtlas *)entry->data; + + return result; +} + + +Texture *asset_getFreeTexSlot(AssetManager *const assetManager, + MemoryArena *const arena, const char *const key) +{ + + HashTableEntry *const entry = + getFreeHashSlot(&assetManager->textures, arena, key); + + if (entry) + { + entry->data = PLATFORM_MEM_ALLOC(arena, 1, Texture); + Texture *result = CAST(Texture *) entry->data; + return result; + } + else + { + return NULL; + } +} + +Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, + const char *const path, const char *const key) +{ + /* Open the texture image */ + i32 imgWidth, imgHeight, bytesPerPixel; + stbi_set_flip_vertically_on_load(TRUE); + u8 *image = + stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); + +#ifdef DENGINE_DEBUG + if (imgWidth != imgHeight) + { + printf( + "asset_loadTextureImage() warning: Sprite sheet is not square: " + "%dx%dpx\n", imgWidth, imgHeight); + } +#endif + + if (!image) + { + printf("stdbi_load() failed: %s\n", stbi_failure_reason()); + return NULL; + } + + Texture *result = asset_getFreeTexSlot(assetManager, arena, key); + *result = texture_gen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight), + CAST(GLint)(bytesPerPixel), image); + + GL_CHECK_ERROR(); + stbi_image_free(image); + + return result; +} + +/* + ********************************* + * Animation Asset Managing + ********************************* + */ +INTERNAL Animation *getFreeAnimationSlot(AssetManager *assetManager, + MemoryArena *arena, char *key) +{ + HashTableEntry *entry = getFreeHashSlot(&assetManager->anims, arena, key); + + if (entry) + { + entry->data = PLATFORM_MEM_ALLOC(arena, 1, Animation); + Animation *result = CAST(Animation *) entry->data; + return result; + } + else + { + return NULL; + } +} + +void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena, + char *animName, TexAtlas *atlas, char **subTextureNames, + i32 numSubTextures, f32 frameDuration) +{ + 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; + + anim->frameList = PLATFORM_MEM_ALLOC(arena, numSubTextures, char*); + for (i32 i = 0; i < numSubTextures; i++) + { + anim->frameList[i] = subTextureNames[i]; + } + +} + +Animation *asset_getAnim(AssetManager *const assetManager, + const char *const key) +{ + HashTableEntry *entry = getEntryFromHash(&assetManager->anims, key); + + Animation *result = NULL; + if (entry) result = CAST(Animation *)entry->data; + + return result; +} + /* ********************************* * XML Operations @@ -356,89 +555,127 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, XmlNode *node = root; while (node) { + /* + ********************************* + * Branch on node names + ********************************* + */ if (common_strcmp(node->name, "TextureAtlas") == 0) { XmlNode *atlasXmlNode = node; - TexAtlas *atlasEntry = NULL; + TexAtlas *atlas = NULL; if (common_strcmp(node->attribute.name, "imagePath") == 0) { + + /* + ********************************************** + * Create a texture atlas with imageName as key + ********************************************** + */ char *imageName = atlasXmlNode->attribute.value; - atlasEntry = - asset_getFreeTexAtlasSlot(assetManager, arena, imageName); + i32 numSubTex = 1024; + atlas = asset_getFreeTexAtlasSlot(assetManager, arena, + imageName, numSubTex); - char *dataDir = "data/textures/WorldTraveller/"; - char imagePath[512] = {0}; - common_strncat(imagePath, dataDir, common_strlen(dataDir)); - common_strncat(imagePath, imageName, common_strlen(imageName)); + if (!atlas) + { + DEBUG_LOG( + "parseXmlTreeToGame() failed: Could not get free atlas " + "entry"); + return; + } - asset_loadTextureImage(assetManager, arena, imagePath, - imageName); + /* + ************************************************* + * Load a texture to hash, with imageName as key + ************************************************* + */ + char *dataDir = "data/textures/WorldTraveller/"; + i32 dataDirLen = common_strlen(dataDir); + i32 imageNameLen = common_strlen(imageName); + i32 totalPathLen = (dataDirLen + imageNameLen) + 1; - atlasEntry->key = PLATFORM_MEM_ALLOC( - arena, common_strlen(imageName) + 1, char); - common_strncpy(atlasEntry->key, imageName, - common_strlen(imageName)); + char *imagePath = PLATFORM_MEM_ALLOC(arena, totalPathLen, char); + common_strncat(imagePath, dataDir, dataDirLen); + common_strncat(imagePath, imageName, imageNameLen); - atlasEntry->tex = asset_getTex(assetManager, imageName); + Texture *tex = asset_loadTextureImage(assetManager, arena, + imagePath, imageName); + if (!tex) + { + DEBUG_LOG("parseXmlTreeToGame() failed: Could not load image"); + PLATFORM_MEM_FREE(arena, imagePath, + totalPathLen * sizeof(char)); + return; + } + + PLATFORM_MEM_FREE(arena, imagePath, + totalPathLen * sizeof(char)); + atlas->tex = tex; + + /* + ************************************************* + * Iterate over XML attributes + ************************************************* + */ XmlNode *atlasChildNode = atlasXmlNode->child; while (atlasChildNode) { if (common_strcmp(atlasChildNode->name, "SubTexture") == 0) { - XmlAttribute *subTextureAttrib = - &atlasChildNode->attribute; + XmlAttribute *subTexAttrib = &atlasChildNode->attribute; - AtlasSubTexture newSubTexEntry = {0}; - while (subTextureAttrib) + char *key = NULL; + Rect subTex = {0}; + while (subTexAttrib) { // TODO(doyle): Work around for now in xml reading, // reading the last node closing node not being // merged to the parent - if (!subTextureAttrib->name) continue; + if (!subTexAttrib->name) continue; - if (common_strcmp(subTextureAttrib->name, "name") == - 0) + if (common_strcmp(subTexAttrib->name, "name") == 0) { - char *value = subTextureAttrib->value; - newSubTexEntry.key = value; + char *value = subTexAttrib->value; + key = value; } - else if (common_strcmp(subTextureAttrib->name, - "x") == 0) + else if (common_strcmp(subTexAttrib->name, "x") == + 0) { - char *value = subTextureAttrib->value; + char *value = subTexAttrib->value; i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - newSubTexEntry.rect.pos.x = CAST(f32) intValue; + subTex.pos.x = CAST(f32) intValue; } - else if (common_strcmp(subTextureAttrib->name, - "y") == 0) + else if (common_strcmp(subTexAttrib->name, "y") == + 0) { - char *value = subTextureAttrib->value; + char *value = subTexAttrib->value; i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - newSubTexEntry.rect.pos.y = CAST(f32) intValue; + subTex.pos.y = CAST(f32) intValue; } - else if (common_strcmp(subTextureAttrib->name, + else if (common_strcmp(subTexAttrib->name, "width") == 0) { - char *value = subTextureAttrib->value; + char *value = subTexAttrib->value; i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - newSubTexEntry.rect.size.w = CAST(f32) intValue; + subTex.size.w = CAST(f32) intValue; } - else if (common_strcmp(subTextureAttrib->name, + else if (common_strcmp(subTexAttrib->name, "height") == 0) { - char *value = subTextureAttrib->value; + char *value = subTexAttrib->value; i32 valueLen = common_strlen(value); i32 intValue = common_atoi(value, valueLen); - newSubTexEntry.rect.size.h = CAST(f32) intValue; + subTex.size.h = CAST(f32) intValue; } else { @@ -447,53 +684,21 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena, "Unsupported xml attribute in SubTexture"); #endif } - subTextureAttrib = subTextureAttrib->next; + subTexAttrib = subTexAttrib->next; } // TODO(doyle): XML specifies 0,0 top left, we // prefer 0,0 bottom right, so offset by size since 0,0 // is top left and size creates a bounding box below it - newSubTexEntry.rect.pos.y = - 1024 - newSubTexEntry.rect.pos.y; - newSubTexEntry.rect.pos.y -= newSubTexEntry.rect.size.h; + subTex.pos.y = 1024 - subTex.pos.y; + subTex.pos.y -= subTex.size.h; #ifdef DENGINE_DEBUG - ASSERT(newSubTexEntry.key) + ASSERT(key); #endif - - u32 subTexHashIndex = common_murmurHash2( - newSubTexEntry.key, - common_strlen(newSubTexEntry.key), 0xDEADBEEF); - subTexHashIndex = - subTexHashIndex % ARRAY_COUNT(atlasEntry->subTex); - - // NOTE(doyle): Hash collision - AtlasSubTexture *subTexEntry = - &atlasEntry->subTex[subTexHashIndex]; - if (subTexEntry->key) - { -#ifdef DENGINE_DEBUG - - // NOTE(doyle): Two textures have the same access - // name - ASSERT(common_strcmp(subTexEntry->key, - newSubTexEntry.key) != 0); -#endif - while (subTexEntry->next) - subTexEntry = subTexEntry->next; - - subTexEntry->next = - PLATFORM_MEM_ALLOC(arena, 1, AtlasSubTexture); - subTexEntry = subTexEntry->next; - } - - *subTexEntry = newSubTexEntry; - i32 keyLen = common_strlen(newSubTexEntry.key); - - subTexEntry->key = - PLATFORM_MEM_ALLOC(arena, keyLen + 1, char); - common_strncpy(subTexEntry->key, newSubTexEntry.key, - keyLen); + Rect *subTexInHash = + getFreeAtlasSubTexSlot(atlas, arena, key); + *subTexInHash = subTex; } else { @@ -559,6 +764,11 @@ INTERNAL void freeXmlData(MemoryArena *arena, XmlToken *tokens, i32 numTokens, if (tokens) PLATFORM_MEM_FREE(arena, tokens, numTokens * sizeof(XmlToken)); } +/* + ********************************* + * Everything else + ********************************* + */ i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena, PlatformFileRead *fileRead) { @@ -587,73 +797,6 @@ i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena, return result; } -/* - ********************************* - * Texture Operations - ********************************* - */ -INTERNAL AtlasSubTexture *getAtlasSubTex(TexAtlas *atlas, char *key) -{ - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(atlas->subTex)); - AtlasSubTexture *result = &atlas->subTex[hashIndex]; - if (result->key) - { - while (result && common_strcmp(result->key, key) != 0) - result = result->next; - } - - return result; -} - -INTERNAL AtlasSubTexture *getFreeAtlasSubTexSlot(TexAtlas *atlas, - MemoryArena *arena, char *key) -{ - u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(atlas->subTex)); - AtlasSubTexture *result = &atlas->subTex[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, AtlasSubTexture); - result = result->next; - } - - return result; -} - -INTERNAL Animation *getFreeAnimationSlot(AssetManager *assetManager, - MemoryArena *arena, char *key) -{ - HashTableEntry *entry = getFreeHashSlot(&assetManager->anims, arena, key); - - if (entry) - { - entry->data = PLATFORM_MEM_ALLOC(arena, 1, Animation); - Animation *result = CAST(Animation *) entry->data; - return result; - } - else - { - return NULL; - } -} - -Rect asset_getSubTexRect(TexAtlas *atlas, char *key) -{ - AtlasSubTexture *subTex = getAtlasSubTex(atlas, key); - Rect result = subTex->rect; - return result; -} - // TODO(doyle): Switch to hash based lookup // TODO(doyle): Use pointers, so we can forward declare all assets? AudioVorbis *asset_getVorbis(AssetManager *assetManager, @@ -669,77 +812,6 @@ AudioVorbis *asset_getVorbis(AssetManager *assetManager, return NULL; } -Texture *asset_getTex(AssetManager *const assetManager, const char *const key) -{ - HashTableEntry *entry = getEntryFromHash(&assetManager->textures, key); - - Texture *result = NULL; - if (entry) result = CAST(Texture *)entry->data; - - return result; -} - -Texture *asset_getFreeTexSlot(AssetManager *const assetManager, - MemoryArena *const arena, const char *const key) -{ - - HashTableEntry *const entry = - getFreeHashSlot(&assetManager->textures, arena, key); - - if (entry) - { - entry->data = PLATFORM_MEM_ALLOC(arena, 1, Texture); - Texture *result = CAST(Texture *) entry->data; - return result; - } - else - { - return NULL; - } -} - -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) -{ - - HashTableEntry *entry = getEntryFromHash(&assetManager->texAtlas, key); - - TexAtlas *result = NULL; - if (entry) result = CAST(TexAtlas *)entry->data; - - return result; -} - -Animation *asset_getAnim(AssetManager *const assetManager, - const char *const key) -{ - HashTableEntry *entry = getEntryFromHash(&assetManager->anims, key); - - Animation *result = NULL; - if (entry) result = CAST(Animation *)entry->data; - - return result; -} - const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, const char *const path, const enum AudioList type) { @@ -772,52 +844,8 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, return 0; } -const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, - const char *const path, const char *const key) -{ - /* Open the texture image */ - i32 imgWidth, imgHeight, bytesPerPixel; - stbi_set_flip_vertically_on_load(TRUE); - u8 *image = - stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); - -#ifdef DENGINE_DEBUG - if (imgWidth != imgHeight) - { - printf( - "asset_loadTextureImage() warning: Sprite sheet is not square: " - "%dx%dpx\n", imgWidth, imgHeight); - } -#endif - - if (!image) - { - printf("stdbi_load() failed: %s\n", stbi_failure_reason()); - return -1; - } - - Texture *tex = asset_getFreeTexSlot(assetManager, arena, key); - *tex = texture_gen(CAST(GLuint)(imgWidth), CAST(GLuint)(imgHeight), - CAST(GLint)(bytesPerPixel), image); - - GL_CHECK_ERROR(); - stbi_image_free(image); - - return 0; -} - -Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type) -{ - if (type < shaderlist_count) - return &assetManager->shaders[type]; - -#ifdef DENGINE_DEBUG - ASSERT(INVALID_CODE_PATH); -#endif - return NULL; -} - -INTERNAL GLuint createShaderFromPath(MemoryArena *arena, const char *const path, GLuint shadertype) +INTERNAL GLuint createShaderFromPath(MemoryArena *arena, const char *const path, + GLuint shadertype) { PlatformFileRead file = {0}; @@ -869,6 +897,17 @@ INTERNAL i32 shaderLoadProgram(Shader *const shader, const GLuint vertexShader, return 0; } +Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type) +{ + if (type < shaderlist_count) + return &assetManager->shaders[type]; + +#ifdef DENGINE_DEBUG + ASSERT(INVALID_CODE_PATH); +#endif + return NULL; +} + const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena, const char *const vertexPath, const char *const fragmentPath, @@ -906,7 +945,11 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, stbtt_InitFont(&fontInfo, fontFileRead.buffer, stbtt_GetFontOffsetForIndex(fontFileRead.buffer, 0)); - /* Initialise Assetmanager Font */ + /* + **************************************** + * Initialise assetmanager font reference + **************************************** + */ Font *font = &assetManager->font; font->codepointRange = V2i(32, 127); v2 codepointRange = font->codepointRange; @@ -930,7 +973,11 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, font->charMetrics = PLATFORM_MEM_ALLOC(arena, numGlyphs, CharMetrics); - /* Use STB_TrueType to generate a series of bitmap characters */ + /* + ************************************************************ + * Use STB_TrueType to generate a series of bitmap characters + ************************************************************ + */ i32 glyphIndex = 0; for (i32 codepoint = CAST(i32) codepointRange.x; codepoint < CAST(i32) codepointRange.y; codepoint++) @@ -1034,8 +1081,16 @@ 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; + + i32 numSubTex = numGlyphs; TexAtlas *fontAtlas = - asset_getFreeTexAtlasSlot(assetManager, arena, "font"); + asset_getFreeTexAtlasSlot(assetManager, arena, "font", numSubTex); + + /* + ********************************************************* + * Load individual glyph bitmap data into one font bitmap + ********************************************************* + */ for (i32 row = 0; row < MAX_TEXTURE_SIZE; row++) { u32 *destRow = fontBitmap + (row * MAX_TEXTURE_SIZE); @@ -1049,25 +1104,15 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, /* Store the location of glyph into atlas */ if (verticalPixelsBlitted == 0) { -#ifdef DENGINE_DEBUG - ASSERT(activeGlyph.codepoint < ARRAY_COUNT(fontAtlas->subTex)); -#endif - v2 origin = V2(CAST(f32)(glyphIndex * font->maxSize.w), CAST(f32) row); // NOTE(doyle): Since charToEncode starts from 0 and we record // all ascii characters, charToEncode represents the character // 1:1 - char charTmp[2] = {0}; - charTmp[0] = charToEncode; - AtlasSubTexture *subTex = - getFreeAtlasSubTexSlot(fontAtlas, arena, charTmp); - - subTex->key = PLATFORM_MEM_ALLOC(arena, 1, char); - subTex->key[0] = charToEncode; - - subTex->rect = CAST(Rect){origin, font->maxSize}; + const char key[2] = {charToEncode, 0}; + Rect *subTex = getFreeAtlasSubTexSlot(fontAtlas, arena, key); + *subTex = CAST(Rect){origin, font->maxSize}; charToEncode++; } @@ -1115,6 +1160,11 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, } } + /* + ******************************************* + * Generate and store font bitmap to assets + ******************************************* + */ Texture *tex = asset_getFreeTexSlot(assetManager, arena, "font"); *tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, CAST(u8 *) fontBitmap); @@ -1146,28 +1196,6 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, return 0; } -void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena, - char *animName, TexAtlas *atlas, char **subTextureNames, - i32 numSubTextures, f32 frameDuration) -{ - 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; - - anim->frameList = PLATFORM_MEM_ALLOC(arena, numSubTextures, char*); - for (i32 i = 0; i < numSubTextures; i++) - { - AtlasSubTexture *subTex = getAtlasSubTex(atlas, subTextureNames[i]); - anim->frameList[i] = subTex->key; - } - -} v2 asset_stringDimInPixels(const Font *const font, const char *const string) { diff --git a/src/Entity.c b/src/Entity.c index 06972a4..0e576d9 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -55,9 +55,9 @@ void entity_updateAnim(Entity *entity, f32 dt) case entitytype_mob: case entitytype_npc: char *frameName = anim->frameList[currEntityAnim->currFrame]; - Rect texRect = - asset_getSubTexRect(anim->atlas, frameName); - entity->renderSize = texRect.size; + Rect *texRect = + asset_getAtlasSubTex(anim->atlas, frameName); + entity->renderSize = texRect->size; default: break; } diff --git a/src/Renderer.c b/src/Renderer.c index 640efa4..3baf07c 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -210,12 +210,13 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera, pos.x += charMetric.advance; /* Get texture out */ - Rect charTexRect = - asset_getSubTexRect(font->atlas, &CAST(char)codepoint); + Rect *charTexRect = + asset_getAtlasSubTex(font->atlas, &CAST(char)codepoint); v4 deprecatedTexRect = {0}; - deprecatedTexRect.vec2[0] = charTexRect.pos; - deprecatedTexRect.vec2[1] = v2_add(charTexRect.pos, charTexRect.size); + deprecatedTexRect.vec2[0] = charTexRect->pos; + deprecatedTexRect.vec2[1] = + v2_add(charTexRect->pos, charTexRect->size); flipTexCoord(&deprecatedTexRect, FALSE, TRUE); @@ -251,12 +252,12 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity, EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; Animation *anim = entityAnim->anim; char *frameName = anim->frameList[entityAnim->currFrame]; - Rect animRect = asset_getSubTexRect(anim->atlas, frameName); + Rect *animRect = asset_getAtlasSubTex(anim->atlas, frameName); // TODO(doyle): Switch to rect v4 animTexRect = {0}; - animTexRect.vec2[0] = animRect.pos; - animTexRect.vec2[1] = v2_add(animRect.pos, animRect.size); + animTexRect.vec2[0] = animRect->pos; + animTexRect.vec2[1] = v2_add(animRect->pos, animRect->size); if (entity->direction == direction_east) { diff --git a/src/WorldTraveller.c b/src/WorldTraveller.c index e3af02c..a37d080 100644 --- a/src/WorldTraveller.c +++ b/src/WorldTraveller.c @@ -1641,17 +1641,18 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) /* Draw hero avatar */ TexAtlas *heroAtlas = asset_getTexAtlas(assetManager, "ClaudeSprite.png"); - Rect heroAvatarRect = - asset_getSubTexRect(heroAtlas, "ClaudeSprite_Avatar_01"); + Rect *heroAvatarRect = + asset_getAtlasSubTex(heroAtlas, "ClaudeSprite_Avatar_01"); v2 heroAvatarP = - V2(10.0f, (renderer->size.h * 0.5f) - (0.5f * heroAvatarRect.size.h)); + V2(10.0f, (renderer->size.h * 0.5f) - (0.5f * heroAvatarRect->size.h)); + // TODO(doyle): Use rect in rendering not V4 v4 heroAvatarTexRect = {0}; - heroAvatarTexRect.vec2[0] = heroAvatarRect.pos; - heroAvatarTexRect.vec2[1] = v2_add(heroAvatarRect.pos, heroAvatarRect.size); + heroAvatarTexRect.vec2[0] = heroAvatarRect->pos; + heroAvatarTexRect.vec2[1] = v2_add(heroAvatarRect->pos, heroAvatarRect->size); RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect}; - renderer_staticRect(renderer, heroAvatarP, heroAvatarRect.size, V2(0, 0), 0, + renderer_staticRect(renderer, heroAvatarP, heroAvatarRect->size, V2(0, 0), 0, heroRenderTex, V4(1, 1, 1, 1)); char heroAvatarStr[20]; @@ -1660,7 +1661,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) f32 strLenInPixels = CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); v2 strPos = - V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect.size.h)); + V2(heroAvatarP.x, heroAvatarP.y - (0.5f * heroAvatarRect->size.h)); renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr, strPos, V2(0, 0), 0, V4(0, 0, 1, 1)); diff --git a/src/include/Dengine/AssetManager.h b/src/include/Dengine/AssetManager.h index 000dcaf..b0eb1fa 100644 --- a/src/include/Dengine/AssetManager.h +++ b/src/include/Dengine/AssetManager.h @@ -9,20 +9,6 @@ typedef struct MemoryArena MemoryArena; typedef struct PlatformFileRead PlatformFileRead; -typedef struct HashTableEntry -{ - void *data; - char *key; - - void *next; -} HashTableEntry; - -typedef struct HashTable -{ - HashTableEntry *entries; - i32 size; -} HashTable; - typedef struct AssetManager { /* Hash Tables */ @@ -37,23 +23,22 @@ typedef struct AssetManager } AssetManager; #define MAX_TEXTURE_SIZE 1024 - /* ********************************* - * Texture Asset Managing + * Texture Operations ********************************* */ -Rect asset_getSubTexRect(TexAtlas *atlas, char *key); +Rect *asset_getAtlasSubTex(TexAtlas *const atlas, const char *const key); Texture *asset_getTex(AssetManager *const assetManager, const char *const key); TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, - MemoryArena *arena, const char *const key); + MemoryArena *arena, const char *const key, + i32 numSubTex); TexAtlas *asset_getTexAtlas(AssetManager *const assetManager, 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); +Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, + const char *const path, const char *const key); /* ********************************* @@ -73,18 +58,22 @@ Animation *asset_getAnim(AssetManager *const assetManager, */ i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena, PlatformFileRead *fileRead); + AudioVorbis *asset_getVorbis(AssetManager *assetManager, const enum AudioList type); -Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type); const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, const char *const path, const enum AudioList type); + +Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type); const i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena, const char *const vertexPath, const char *const fragmentPath, const enum ShaderList type); + const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, const char *filePath); v2 asset_stringDimInPixels(const Font *const font, const char *const string); + void asset_unitTest(MemoryArena *arena); #endif diff --git a/src/include/Dengine/Assets.h b/src/include/Dengine/Assets.h index 715e13d..521baa0 100644 --- a/src/include/Dengine/Assets.h +++ b/src/include/Dengine/Assets.h @@ -10,6 +10,12 @@ /* Forward Declaration */ typedef struct Texture Texture; +/* + ********************************* + * XML + ********************************* + */ +// TODO(doyle): We only expose this to for debug.h to print out xml trees typedef struct XmlAttribute { b32 init; @@ -36,28 +42,17 @@ typedef struct XmlNode } XmlNode; -enum TexList -{ - texlist_empty, - texlist_hero, - texlist_claude, - texlist_terrain, - texlist_font, - texlist_count, -}; - enum ShaderList { shaderlist_sprite, shaderlist_count, }; -enum TerrainRects -{ - terrainrects_ground, - terrainrects_count, -}; - +/* + ********************************* + * Audio + ********************************* + */ enum AudioList { audiolist_battle, @@ -80,23 +75,36 @@ typedef struct AudioVorbis i32 size; } AudioVorbis; -typedef struct AtlasSubTexture +/* + ********************************* + * Hash Table + ********************************* + */ +typedef struct HashTableEntry { - // NOTE(doyle): Key used to arrive to hash entry + void *data; char *key; - Rect rect; - - // NOTE(doyle): For hashing collisions - struct AtlasSubTexture *next; -} AtlasSubTexture; + void *next; +} HashTableEntry; + +typedef struct HashTable +{ + HashTableEntry *entries; + i32 size; +} HashTable; + +/* + ********************************* + * Texture Assets + ********************************* + */ typedef struct TexAtlas { - char *key; Texture *tex; - AtlasSubTexture subTex[512]; - struct TexAtlas *next; + HashTable subTex; + i32 numSubTex; } TexAtlas; typedef struct Animation @@ -113,6 +121,11 @@ typedef struct Animation f32 frameDuration; } Animation; +/* + ********************************* + * Font + ********************************* + */ // TODO(doyle): We only use the offset and advance metric at the moment, remove? typedef struct FontMetrics {