Convert subtextures to use hash tables

Also clean up and add some block comments to aid code separation mainly in
AssetManager.
This commit is contained in:
Doyle Thai 2016-08-30 18:42:37 +10:00
parent 8b0f2f93e3
commit e9db7b0570
6 changed files with 396 additions and 364 deletions

View File

@ -51,7 +51,7 @@ INTERNAL HashTableEntry *getFreeHashSlot(HashTable *const table,
} }
/* Check if platform_mem_alloc failed(), otherwise always true if hash table /* Check if platform_mem_alloc failed(), otherwise always true if hash table
* entries initialised*/ * entries initialised, assign key to hash entry */
if (result) if (result)
{ {
// +1 Null terminator // +1 Null terminator
@ -77,6 +77,205 @@ INTERNAL HashTableEntry *getEntryFromHash(HashTable *const table,
return result; 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 * XML Operations
@ -356,89 +555,127 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena,
XmlNode *node = root; XmlNode *node = root;
while (node) while (node)
{ {
/*
*********************************
* Branch on node names
*********************************
*/
if (common_strcmp(node->name, "TextureAtlas") == 0) if (common_strcmp(node->name, "TextureAtlas") == 0)
{ {
XmlNode *atlasXmlNode = node; XmlNode *atlasXmlNode = node;
TexAtlas *atlasEntry = NULL; TexAtlas *atlas = NULL;
if (common_strcmp(node->attribute.name, "imagePath") == 0) if (common_strcmp(node->attribute.name, "imagePath") == 0)
{ {
/*
**********************************************
* Create a texture atlas with imageName as key
**********************************************
*/
char *imageName = atlasXmlNode->attribute.value; char *imageName = atlasXmlNode->attribute.value;
atlasEntry = i32 numSubTex = 1024;
asset_getFreeTexAtlasSlot(assetManager, arena, imageName); atlas = asset_getFreeTexAtlasSlot(assetManager, arena,
imageName, numSubTex);
if (!atlas)
{
DEBUG_LOG(
"parseXmlTreeToGame() failed: Could not get free atlas "
"entry");
return;
}
/*
*************************************************
* Load a texture to hash, with imageName as key
*************************************************
*/
char *dataDir = "data/textures/WorldTraveller/"; char *dataDir = "data/textures/WorldTraveller/";
char imagePath[512] = {0}; i32 dataDirLen = common_strlen(dataDir);
common_strncat(imagePath, dataDir, common_strlen(dataDir)); i32 imageNameLen = common_strlen(imageName);
common_strncat(imagePath, imageName, common_strlen(imageName)); i32 totalPathLen = (dataDirLen + imageNameLen) + 1;
asset_loadTextureImage(assetManager, arena, imagePath, char *imagePath = PLATFORM_MEM_ALLOC(arena, totalPathLen, char);
imageName); common_strncat(imagePath, dataDir, dataDirLen);
common_strncat(imagePath, imageName, imageNameLen);
atlasEntry->key = PLATFORM_MEM_ALLOC( Texture *tex = asset_loadTextureImage(assetManager, arena,
arena, common_strlen(imageName) + 1, char); imagePath, imageName);
common_strncpy(atlasEntry->key, imageName,
common_strlen(imageName));
atlasEntry->tex = asset_getTex(assetManager, 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; XmlNode *atlasChildNode = atlasXmlNode->child;
while (atlasChildNode) while (atlasChildNode)
{ {
if (common_strcmp(atlasChildNode->name, "SubTexture") == 0) if (common_strcmp(atlasChildNode->name, "SubTexture") == 0)
{ {
XmlAttribute *subTextureAttrib = XmlAttribute *subTexAttrib = &atlasChildNode->attribute;
&atlasChildNode->attribute;
AtlasSubTexture newSubTexEntry = {0}; char *key = NULL;
while (subTextureAttrib) Rect subTex = {0};
while (subTexAttrib)
{ {
// TODO(doyle): Work around for now in xml reading, // TODO(doyle): Work around for now in xml reading,
// reading the last node closing node not being // reading the last node closing node not being
// merged to the parent // merged to the parent
if (!subTextureAttrib->name) continue; if (!subTexAttrib->name) continue;
if (common_strcmp(subTextureAttrib->name, "name") == if (common_strcmp(subTexAttrib->name, "name") == 0)
{
char *value = subTexAttrib->value;
key = value;
}
else if (common_strcmp(subTexAttrib->name, "x") ==
0) 0)
{ {
char *value = subTextureAttrib->value; char *value = subTexAttrib->value;
newSubTexEntry.key = value;
}
else if (common_strcmp(subTextureAttrib->name,
"x") == 0)
{
char *value = subTextureAttrib->value;
i32 valueLen = common_strlen(value); i32 valueLen = common_strlen(value);
i32 intValue = common_atoi(value, valueLen); 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, else if (common_strcmp(subTexAttrib->name, "y") ==
"y") == 0) 0)
{ {
char *value = subTextureAttrib->value; char *value = subTexAttrib->value;
i32 valueLen = common_strlen(value); i32 valueLen = common_strlen(value);
i32 intValue = common_atoi(value, valueLen); 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) "width") == 0)
{ {
char *value = subTextureAttrib->value; char *value = subTexAttrib->value;
i32 valueLen = common_strlen(value); i32 valueLen = common_strlen(value);
i32 intValue = common_atoi(value, valueLen); 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) "height") == 0)
{ {
char *value = subTextureAttrib->value; char *value = subTexAttrib->value;
i32 valueLen = common_strlen(value); i32 valueLen = common_strlen(value);
i32 intValue = common_atoi(value, valueLen); i32 intValue = common_atoi(value, valueLen);
newSubTexEntry.rect.size.h = CAST(f32) intValue; subTex.size.h = CAST(f32) intValue;
} }
else else
{ {
@ -447,53 +684,21 @@ INTERNAL void parseXmlTreeToGame(AssetManager *assetManager, MemoryArena *arena,
"Unsupported xml attribute in SubTexture"); "Unsupported xml attribute in SubTexture");
#endif #endif
} }
subTextureAttrib = subTextureAttrib->next; subTexAttrib = subTexAttrib->next;
} }
// TODO(doyle): XML specifies 0,0 top left, we // TODO(doyle): XML specifies 0,0 top left, we
// prefer 0,0 bottom right, so offset by size since 0,0 // prefer 0,0 bottom right, so offset by size since 0,0
// is top left and size creates a bounding box below it // is top left and size creates a bounding box below it
newSubTexEntry.rect.pos.y = subTex.pos.y = 1024 - subTex.pos.y;
1024 - newSubTexEntry.rect.pos.y; subTex.pos.y -= subTex.size.h;
newSubTexEntry.rect.pos.y -= newSubTexEntry.rect.size.h;
#ifdef DENGINE_DEBUG #ifdef DENGINE_DEBUG
ASSERT(newSubTexEntry.key) ASSERT(key);
#endif #endif
Rect *subTexInHash =
u32 subTexHashIndex = common_murmurHash2( getFreeAtlasSubTexSlot(atlas, arena, key);
newSubTexEntry.key, *subTexInHash = subTex;
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);
} }
else else
{ {
@ -559,6 +764,11 @@ INTERNAL void freeXmlData(MemoryArena *arena, XmlToken *tokens, i32 numTokens,
if (tokens) PLATFORM_MEM_FREE(arena, tokens, numTokens * sizeof(XmlToken)); if (tokens) PLATFORM_MEM_FREE(arena, tokens, numTokens * sizeof(XmlToken));
} }
/*
*********************************
* Everything else
*********************************
*/
i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena, i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena,
PlatformFileRead *fileRead) PlatformFileRead *fileRead)
{ {
@ -587,73 +797,6 @@ i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena,
return result; 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): Switch to hash based lookup
// TODO(doyle): Use pointers, so we can forward declare all assets? // TODO(doyle): Use pointers, so we can forward declare all assets?
AudioVorbis *asset_getVorbis(AssetManager *assetManager, AudioVorbis *asset_getVorbis(AssetManager *assetManager,
@ -669,77 +812,6 @@ AudioVorbis *asset_getVorbis(AssetManager *assetManager,
return NULL; 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 i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
const char *const path, const enum AudioList type) const char *const path, const enum AudioList type)
{ {
@ -772,52 +844,8 @@ const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
return 0; return 0;
} }
const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, INTERNAL GLuint createShaderFromPath(MemoryArena *arena, const char *const path,
const char *const path, const char *const key) GLuint shadertype)
{
/* 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)
{ {
PlatformFileRead file = {0}; PlatformFileRead file = {0};
@ -869,6 +897,17 @@ INTERNAL i32 shaderLoadProgram(Shader *const shader, const GLuint vertexShader,
return 0; 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 i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena,
const char *const vertexPath, const char *const vertexPath,
const char *const fragmentPath, const char *const fragmentPath,
@ -906,7 +945,11 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
stbtt_InitFont(&fontInfo, fontFileRead.buffer, stbtt_InitFont(&fontInfo, fontFileRead.buffer,
stbtt_GetFontOffsetForIndex(fontFileRead.buffer, 0)); stbtt_GetFontOffsetForIndex(fontFileRead.buffer, 0));
/* Initialise Assetmanager Font */ /*
****************************************
* Initialise assetmanager font reference
****************************************
*/
Font *font = &assetManager->font; Font *font = &assetManager->font;
font->codepointRange = V2i(32, 127); font->codepointRange = V2i(32, 127);
v2 codepointRange = font->codepointRange; v2 codepointRange = font->codepointRange;
@ -930,7 +973,11 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
font->charMetrics = PLATFORM_MEM_ALLOC(arena, numGlyphs, CharMetrics); 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; i32 glyphIndex = 0;
for (i32 codepoint = CAST(i32) codepointRange.x; for (i32 codepoint = CAST(i32) codepointRange.x;
codepoint < CAST(i32) codepointRange.y; codepoint++) 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 // 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;
i32 numSubTex = numGlyphs;
TexAtlas *fontAtlas = 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++) for (i32 row = 0; row < MAX_TEXTURE_SIZE; row++)
{ {
u32 *destRow = fontBitmap + (row * MAX_TEXTURE_SIZE); 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 */ /* Store the location of glyph into atlas */
if (verticalPixelsBlitted == 0) if (verticalPixelsBlitted == 0)
{ {
#ifdef DENGINE_DEBUG
ASSERT(activeGlyph.codepoint < ARRAY_COUNT(fontAtlas->subTex));
#endif
v2 origin = v2 origin =
V2(CAST(f32)(glyphIndex * font->maxSize.w), CAST(f32) row); V2(CAST(f32)(glyphIndex * font->maxSize.w), CAST(f32) row);
// NOTE(doyle): Since charToEncode starts from 0 and we record // NOTE(doyle): Since charToEncode starts from 0 and we record
// all ascii characters, charToEncode represents the character // all ascii characters, charToEncode represents the character
// 1:1 // 1:1
char charTmp[2] = {0}; const char key[2] = {charToEncode, 0};
charTmp[0] = charToEncode; Rect *subTex = getFreeAtlasSubTexSlot(fontAtlas, arena, key);
AtlasSubTexture *subTex = *subTex = CAST(Rect){origin, font->maxSize};
getFreeAtlasSubTexSlot(fontAtlas, arena, charTmp);
subTex->key = PLATFORM_MEM_ALLOC(arena, 1, char);
subTex->key[0] = charToEncode;
subTex->rect = CAST(Rect){origin, font->maxSize};
charToEncode++; 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"); Texture *tex = asset_getFreeTexSlot(assetManager, arena, "font");
*tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4, *tex = texture_gen(MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, 4,
CAST(u8 *) fontBitmap); CAST(u8 *) fontBitmap);
@ -1146,28 +1196,6 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
return 0; 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) v2 asset_stringDimInPixels(const Font *const font, const char *const string)
{ {

View File

@ -55,9 +55,9 @@ void entity_updateAnim(Entity *entity, f32 dt)
case entitytype_mob: case entitytype_mob:
case entitytype_npc: case entitytype_npc:
char *frameName = anim->frameList[currEntityAnim->currFrame]; char *frameName = anim->frameList[currEntityAnim->currFrame];
Rect texRect = Rect *texRect =
asset_getSubTexRect(anim->atlas, frameName); asset_getAtlasSubTex(anim->atlas, frameName);
entity->renderSize = texRect.size; entity->renderSize = texRect->size;
default: default:
break; break;
} }

View File

@ -210,12 +210,13 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
pos.x += charMetric.advance; pos.x += charMetric.advance;
/* Get texture out */ /* Get texture out */
Rect charTexRect = Rect *charTexRect =
asset_getSubTexRect(font->atlas, &CAST(char)codepoint); asset_getAtlasSubTex(font->atlas, &CAST(char)codepoint);
v4 deprecatedTexRect = {0}; v4 deprecatedTexRect = {0};
deprecatedTexRect.vec2[0] = charTexRect.pos; deprecatedTexRect.vec2[0] = charTexRect->pos;
deprecatedTexRect.vec2[1] = v2_add(charTexRect.pos, charTexRect.size); deprecatedTexRect.vec2[1] =
v2_add(charTexRect->pos, charTexRect->size);
flipTexCoord(&deprecatedTexRect, FALSE, TRUE); flipTexCoord(&deprecatedTexRect, FALSE, TRUE);
@ -251,12 +252,12 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
EntityAnim *entityAnim = &entity->animList[entity->currAnimId]; EntityAnim *entityAnim = &entity->animList[entity->currAnimId];
Animation *anim = entityAnim->anim; Animation *anim = entityAnim->anim;
char *frameName = anim->frameList[entityAnim->currFrame]; 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 // TODO(doyle): Switch to rect
v4 animTexRect = {0}; v4 animTexRect = {0};
animTexRect.vec2[0] = animRect.pos; animTexRect.vec2[0] = animRect->pos;
animTexRect.vec2[1] = v2_add(animRect.pos, animRect.size); animTexRect.vec2[1] = v2_add(animRect->pos, animRect->size);
if (entity->direction == direction_east) if (entity->direction == direction_east)
{ {

View File

@ -1641,17 +1641,18 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
/* Draw hero avatar */ /* Draw hero avatar */
TexAtlas *heroAtlas = TexAtlas *heroAtlas =
asset_getTexAtlas(assetManager, "ClaudeSprite.png"); asset_getTexAtlas(assetManager, "ClaudeSprite.png");
Rect heroAvatarRect = Rect *heroAvatarRect =
asset_getSubTexRect(heroAtlas, "ClaudeSprite_Avatar_01"); asset_getAtlasSubTex(heroAtlas, "ClaudeSprite_Avatar_01");
v2 heroAvatarP = 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}; v4 heroAvatarTexRect = {0};
heroAvatarTexRect.vec2[0] = heroAvatarRect.pos; heroAvatarTexRect.vec2[0] = heroAvatarRect->pos;
heroAvatarTexRect.vec2[1] = v2_add(heroAvatarRect.pos, heroAvatarRect.size); heroAvatarTexRect.vec2[1] = v2_add(heroAvatarRect->pos, heroAvatarRect->size);
RenderTex heroRenderTex = {hero->tex, heroAvatarTexRect}; 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)); heroRenderTex, V4(1, 1, 1, 1));
char heroAvatarStr[20]; char heroAvatarStr[20];
@ -1660,7 +1661,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
f32 strLenInPixels = f32 strLenInPixels =
CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr)); CAST(f32)(font->maxSize.w * common_strlen(heroAvatarStr));
v2 strPos = 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, renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
strPos, V2(0, 0), 0, V4(0, 0, 1, 1)); strPos, V2(0, 0), 0, V4(0, 0, 1, 1));

View File

@ -9,20 +9,6 @@
typedef struct MemoryArena MemoryArena; typedef struct MemoryArena MemoryArena;
typedef struct PlatformFileRead PlatformFileRead; 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 typedef struct AssetManager
{ {
/* Hash Tables */ /* Hash Tables */
@ -37,23 +23,22 @@ typedef struct AssetManager
} AssetManager; } AssetManager;
#define MAX_TEXTURE_SIZE 1024 #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); Texture *asset_getTex(AssetManager *const assetManager, const char *const key);
TexAtlas *asset_getFreeTexAtlasSlot(AssetManager *const assetManager, 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, TexAtlas *asset_getTexAtlas(AssetManager *const assetManager,
const char *const key); const char *const key);
Texture *asset_getFreeTexSlot(AssetManager *const assetManager, Texture *asset_getFreeTexSlot(AssetManager *const assetManager,
MemoryArena *const arena, const char *const key); MemoryArena *const arena, const char *const key);
const i32 asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena, Texture *asset_loadTextureImage(AssetManager *assetManager, MemoryArena *arena,
const char *const path, const char *const path, const char *const key);
const char *const key);
/* /*
********************************* *********************************
@ -73,18 +58,22 @@ Animation *asset_getAnim(AssetManager *const assetManager,
*/ */
i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena, i32 asset_loadXmlFile(AssetManager *assetManager, MemoryArena *arena,
PlatformFileRead *fileRead); PlatformFileRead *fileRead);
AudioVorbis *asset_getVorbis(AssetManager *assetManager, AudioVorbis *asset_getVorbis(AssetManager *assetManager,
const enum AudioList type); const enum AudioList type);
Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type);
const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena, const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
const char *const path, const enum AudioList type); 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 i32 asset_loadShaderFiles(AssetManager *assetManager, MemoryArena *arena,
const char *const vertexPath, const char *const vertexPath,
const char *const fragmentPath, const char *const fragmentPath,
const enum ShaderList type); const enum ShaderList type);
const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena, const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
const char *filePath); const char *filePath);
v2 asset_stringDimInPixels(const Font *const font, const char *const string); v2 asset_stringDimInPixels(const Font *const font, const char *const string);
void asset_unitTest(MemoryArena *arena); void asset_unitTest(MemoryArena *arena);
#endif #endif

View File

@ -10,6 +10,12 @@
/* Forward Declaration */ /* Forward Declaration */
typedef struct Texture Texture; typedef struct Texture Texture;
/*
*********************************
* XML
*********************************
*/
// TODO(doyle): We only expose this to for debug.h to print out xml trees
typedef struct XmlAttribute typedef struct XmlAttribute
{ {
b32 init; b32 init;
@ -36,28 +42,17 @@ typedef struct XmlNode
} XmlNode; } XmlNode;
enum TexList
{
texlist_empty,
texlist_hero,
texlist_claude,
texlist_terrain,
texlist_font,
texlist_count,
};
enum ShaderList enum ShaderList
{ {
shaderlist_sprite, shaderlist_sprite,
shaderlist_count, shaderlist_count,
}; };
enum TerrainRects /*
{ *********************************
terrainrects_ground, * Audio
terrainrects_count, *********************************
}; */
enum AudioList enum AudioList
{ {
audiolist_battle, audiolist_battle,
@ -80,23 +75,36 @@ typedef struct AudioVorbis
i32 size; i32 size;
} AudioVorbis; } AudioVorbis;
typedef struct AtlasSubTexture /*
*********************************
* Hash Table
*********************************
*/
typedef struct HashTableEntry
{ {
// NOTE(doyle): Key used to arrive to hash entry void *data;
char *key; char *key;
Rect rect;
// NOTE(doyle): For hashing collisions void *next;
struct AtlasSubTexture *next; } HashTableEntry;
} AtlasSubTexture;
typedef struct HashTable
{
HashTableEntry *entries;
i32 size;
} HashTable;
/*
*********************************
* Texture Assets
*********************************
*/
typedef struct TexAtlas typedef struct TexAtlas
{ {
char *key;
Texture *tex; Texture *tex;
AtlasSubTexture subTex[512];
struct TexAtlas *next; HashTable subTex;
i32 numSubTex;
} TexAtlas; } TexAtlas;
typedef struct Animation typedef struct Animation
@ -113,6 +121,11 @@ typedef struct Animation
f32 frameDuration; f32 frameDuration;
} Animation; } Animation;
/*
*********************************
* Font
*********************************
*/
// 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?
typedef struct FontMetrics typedef struct FontMetrics
{ {