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:
parent
8b0f2f93e3
commit
e9db7b0570
@ -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);
|
||||
|
||||
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 imagePath[512] = {0};
|
||||
common_strncat(imagePath, dataDir, common_strlen(dataDir));
|
||||
common_strncat(imagePath, imageName, common_strlen(imageName));
|
||||
i32 dataDirLen = common_strlen(dataDir);
|
||||
i32 imageNameLen = common_strlen(imageName);
|
||||
i32 totalPathLen = (dataDirLen + imageNameLen) + 1;
|
||||
|
||||
asset_loadTextureImage(assetManager, arena, imagePath,
|
||||
imageName);
|
||||
char *imagePath = PLATFORM_MEM_ALLOC(arena, totalPathLen, char);
|
||||
common_strncat(imagePath, dataDir, dataDirLen);
|
||||
common_strncat(imagePath, imageName, imageNameLen);
|
||||
|
||||
atlasEntry->key = PLATFORM_MEM_ALLOC(
|
||||
arena, common_strlen(imageName) + 1, char);
|
||||
common_strncpy(atlasEntry->key, imageName,
|
||||
common_strlen(imageName));
|
||||
Texture *tex = asset_loadTextureImage(assetManager, arena,
|
||||
imagePath, 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;
|
||||
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") ==
|
||||
if (common_strcmp(subTexAttrib->name, "name") == 0)
|
||||
{
|
||||
char *value = subTexAttrib->value;
|
||||
key = value;
|
||||
}
|
||||
else if (common_strcmp(subTexAttrib->name, "x") ==
|
||||
0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
newSubTexEntry.key = value;
|
||||
}
|
||||
else if (common_strcmp(subTextureAttrib->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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user