Start merging hash table access into assets
Basic implementation with many pre-existing features disabled untill all parts of the system that interact with the assets transitions over.
This commit is contained in:
parent
b43754986f
commit
7ca42f781a
@ -21,6 +21,76 @@
|
||||
#include "Dengine/OpenGL.h"
|
||||
#include "Dengine/Platform.h"
|
||||
|
||||
INTERNAL AtlasSubTexture *getAtlasSubTexture(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 *makeAtlasSubTexture(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 *getFreeAnimSlot(Animation *table, u32 tableSize,
|
||||
MemoryArena *arena, char *key)
|
||||
{
|
||||
u32 hashIndex = common_getHashIndex(key, tableSize);
|
||||
Animation *result = &table[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, Animation);
|
||||
result = result->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect asset_getAtlasSubTexRect(TexAtlas *atlas, char *key)
|
||||
{
|
||||
AtlasSubTexture *subTex = getAtlasSubTexture(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,
|
||||
@ -49,27 +119,64 @@ Texture *asset_getTexture(AssetManager *const assetManager,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TexAtlas *asset_getTextureAtlas(AssetManager *assetManager, const enum TexList type)
|
||||
TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager,
|
||||
MemoryArena *arena, const char *const key)
|
||||
{
|
||||
if (type < texlist_count)
|
||||
return &assetManager->texAtlas[type];
|
||||
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas));
|
||||
TexAtlas *result = &assetManager->texAtlas[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;
|
||||
}
|
||||
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(INVALID_CODE_PATH);
|
||||
#endif
|
||||
return NULL;
|
||||
result->next = PLATFORM_MEM_ALLOC(arena, 1, TexAtlas);
|
||||
result = result->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Animation *asset_getAnim(AssetManager *assetManager, const enum AnimList type)
|
||||
TexAtlas *asset_getTexAtlas(AssetManager *const assetManager,
|
||||
const char *const key)
|
||||
{
|
||||
if (type < animlist_count)
|
||||
return &assetManager->anims[type];
|
||||
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->texAtlas));
|
||||
TexAtlas *result = &assetManager->texAtlas[hashIndex];
|
||||
if (result->key)
|
||||
{
|
||||
while (result && common_strcmp(result->key, key) != 0)
|
||||
result = result->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(INVALID_CODE_PATH);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
Animation *asset_getAnim(AssetManager *assetManager, char *key)
|
||||
{
|
||||
u32 hashIndex = common_getHashIndex(key, ARRAY_COUNT(assetManager->anims));
|
||||
Animation *result = &assetManager->anims[hashIndex];
|
||||
if (result->key)
|
||||
{
|
||||
while (result && common_strcmp(result->key, key) != 0)
|
||||
result = result->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
|
||||
@ -364,7 +471,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||
// TODO(doyle): We copy over the bitmap direct to the font sheet, should we
|
||||
// align the baselines up so we don't need to do baseline adjusting at
|
||||
// render?
|
||||
i32 atlasIndex = 0;
|
||||
char charToEncode = CAST(char)codepointRange.x;
|
||||
TexAtlas *fontAtlas = asset_makeTexAtlas(assetManager, arena, "font");
|
||||
for (i32 row = 0; row < MAX_TEXTURE_SIZE; row++)
|
||||
{
|
||||
u32 *destRow = fontBitmap + (row * MAX_TEXTURE_SIZE);
|
||||
@ -378,23 +486,26 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||
/* Store the location of glyph into atlas */
|
||||
if (verticalPixelsBlitted == 0)
|
||||
{
|
||||
TexAtlas *fontAtlas = &assetManager->texAtlas[texlist_font];
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(activeGlyph.codepoint < ARRAY_COUNT(fontAtlas->texRect));
|
||||
ASSERT(activeGlyph.codepoint < ARRAY_COUNT(fontAtlas->subTex));
|
||||
#endif
|
||||
|
||||
v2 origin =
|
||||
V2(CAST(f32)(glyphIndex * font->maxSize.w), CAST(f32) row);
|
||||
#if 1
|
||||
fontAtlas->texRect[atlasIndex++] =
|
||||
math_getRect(origin, V2(CAST(f32) font->maxSize.w,
|
||||
CAST(f32) font->maxSize.h));
|
||||
#else
|
||||
v2i fontSize =
|
||||
font->charMetrics[activeGlyph.codepoint - 32].trueSize;
|
||||
fontAtlas->texRect[atlasIndex++] = math_getRect(
|
||||
origin, V2(CAST(f32) fontSize.x, CAST(f32) fontSize.y));
|
||||
#endif
|
||||
|
||||
// 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 =
|
||||
makeAtlasSubTexture(fontAtlas, arena, charTmp);
|
||||
|
||||
subTex->key = PLATFORM_MEM_ALLOC(arena, 1, char);
|
||||
subTex->key[0] = charToEncode;
|
||||
|
||||
subTex->rect = CAST(Rect){origin, font->maxSize};
|
||||
charToEncode++;
|
||||
}
|
||||
|
||||
/* Copy over exactly one row of pixels */
|
||||
@ -452,8 +563,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||
#endif
|
||||
PLATFORM_MEM_FREE(arena, fontBitmap, bitmapSize);
|
||||
|
||||
font->tex = &assetManager->textures[texlist_font];
|
||||
font->atlas = &assetManager->texAtlas[texlist_font];
|
||||
fontAtlas->tex = &assetManager->textures[texlist_font];
|
||||
font->atlas = fontAtlas;
|
||||
|
||||
// NOTE(doyle): Formula derived from STB Font
|
||||
font->verticalSpacing =
|
||||
@ -472,26 +583,28 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
|
||||
i32 texId, i32 animId, i32 *frameIndex, i32 numFrames,
|
||||
f32 frameDuration)
|
||||
char *animName, TexAtlas *atlas, char **subTextureNames,
|
||||
i32 numSubTextures, f32 frameDuration)
|
||||
{
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(assetManager && frameIndex)
|
||||
ASSERT(!assetManager->anims[animId].frameIndex);
|
||||
#endif
|
||||
Animation *anim = getFreeAnimSlot(
|
||||
assetManager->anims, ARRAY_COUNT(assetManager->anims), arena, animName);
|
||||
|
||||
Animation anim = {0};
|
||||
anim.atlas = asset_getTextureAtlas(assetManager, texId);
|
||||
anim->atlas = atlas;
|
||||
anim->frameDuration = frameDuration;
|
||||
anim->numFrames = numSubTextures;
|
||||
|
||||
anim.frameIndex = PLATFORM_MEM_ALLOC(arena, numFrames, i32);
|
||||
for (i32 i = 0; i < numFrames; i++) anim.frameIndex[i] = frameIndex[i];
|
||||
// NOTE(doyle): +1 for the null terminator
|
||||
anim->name = PLATFORM_MEM_ALLOC(arena, common_strlen(animName) + 1, char);
|
||||
common_strncpy(anim->name, animName, common_strlen(animName));
|
||||
|
||||
anim.numFrames = numFrames;
|
||||
anim.frameDuration = frameDuration;
|
||||
anim->frameList = PLATFORM_MEM_ALLOC(arena, numSubTextures, char*);
|
||||
for (i32 i = 0; i < numSubTextures; i++)
|
||||
{
|
||||
AtlasSubTexture *subTex = getAtlasSubTexture(atlas, subTextureNames[i]);
|
||||
anim->frameList[i] = subTex->key;
|
||||
}
|
||||
|
||||
assetManager->anims[animId] = anim;
|
||||
}
|
||||
|
||||
v2 asset_stringDimInPixels(const Font *const font, const char *const string)
|
||||
|
79
src/Entity.c
79
src/Entity.c
@ -3,20 +3,28 @@
|
||||
#include "Dengine/Platform.h"
|
||||
#include "Dengine/WorldTraveller.h"
|
||||
|
||||
void entity_setActiveAnim(Entity *entity, enum AnimList animId)
|
||||
void entity_setActiveAnim(Entity *entity, char *animName)
|
||||
{
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(animId < animlist_count);
|
||||
ASSERT(entity->anim[animId].anim);
|
||||
#endif
|
||||
|
||||
/* Reset current anim data */
|
||||
EntityAnim_ *currAnim = &entity->anim[entity->currAnimId];
|
||||
currAnim->currDuration = currAnim->anim->frameDuration;
|
||||
currAnim->currFrame = 0;
|
||||
EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId];
|
||||
currEntityAnim->currDuration = currEntityAnim->anim->frameDuration;
|
||||
currEntityAnim->currFrame = 0;
|
||||
|
||||
/* Set entity active animation */
|
||||
entity->currAnimId = animId;
|
||||
for (i32 i = 0; i < ARRAY_COUNT(entity->animList); i++)
|
||||
{
|
||||
Animation *anim = entity->animList[i].anim;
|
||||
if (anim)
|
||||
{
|
||||
if (common_strcmp(anim->key, animName) == 0)
|
||||
{
|
||||
entity->currAnimId = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("Entity does not have access to desired anim");
|
||||
}
|
||||
|
||||
void entity_updateAnim(Entity *entity, f32 dt)
|
||||
@ -24,20 +32,15 @@ void entity_updateAnim(Entity *entity, f32 dt)
|
||||
if (!entity->tex)
|
||||
return;
|
||||
|
||||
// TODO(doyle): Recheck why we have this twice
|
||||
EntityAnim_ *entityAnim = &entity->anim[entity->currAnimId];
|
||||
Animation anim = *entityAnim->anim;
|
||||
i32 frameIndex = anim.frameIndex[entityAnim->currFrame];
|
||||
v4 texRect = anim.atlas->texRect[frameIndex];
|
||||
EntityAnim *currEntityAnim = &entity->animList[entity->currAnimId];
|
||||
Animation *anim = currEntityAnim->anim;
|
||||
|
||||
entityAnim->currDuration -= dt;
|
||||
if (entityAnim->currDuration <= 0.0f)
|
||||
currEntityAnim->currDuration -= dt;
|
||||
if (currEntityAnim->currDuration <= 0.0f)
|
||||
{
|
||||
entityAnim->currFrame++;
|
||||
entityAnim->currFrame = entityAnim->currFrame % anim.numFrames;
|
||||
frameIndex = entityAnim->anim->frameIndex[entityAnim->currFrame];
|
||||
texRect = anim.atlas->texRect[frameIndex];
|
||||
entityAnim->currDuration = anim.frameDuration;
|
||||
currEntityAnim->currFrame++;
|
||||
currEntityAnim->currFrame = currEntityAnim->currFrame % anim->numFrames;
|
||||
currEntityAnim->currDuration = anim->frameDuration;
|
||||
}
|
||||
|
||||
// NOTE(doyle): If humanoid entity, let animation dictate render size which
|
||||
@ -47,18 +50,31 @@ void entity_updateAnim(Entity *entity, f32 dt)
|
||||
case entitytype_hero:
|
||||
case entitytype_mob:
|
||||
case entitytype_npc:
|
||||
entity->renderSize = math_getRectSize(texRect);
|
||||
char *frameName = anim->frameList[currEntityAnim->currFrame];
|
||||
Rect texRect =
|
||||
asset_getAtlasSubTexRect(anim->atlas, frameName);
|
||||
entity->renderSize = texRect.size;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void entity_addAnim(AssetManager *assetManager, Entity *entity, i32 animId)
|
||||
void entity_addAnim(AssetManager *assetManager, Entity *entity, char *animName)
|
||||
{
|
||||
Animation *anim = asset_getAnim(assetManager, animId);
|
||||
entity->anim[animId].anim = anim;
|
||||
entity->anim[animId].currFrame = 0;
|
||||
entity->anim[animId].currDuration = anim->frameDuration;
|
||||
i32 freeAnimIndex = 0;
|
||||
for (i32 i = 0; i < ARRAY_COUNT(entity->animList); i++)
|
||||
{
|
||||
EntityAnim *entityAnim = &entity->animList[i];
|
||||
if (!entityAnim->anim)
|
||||
{
|
||||
entityAnim->anim = asset_getAnim(assetManager, animName);
|
||||
entityAnim->currFrame = 0;
|
||||
entityAnim->currDuration = entityAnim->anim->frameDuration;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("No more free entity animation slots");
|
||||
}
|
||||
|
||||
void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager,
|
||||
@ -81,12 +97,7 @@ void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager,
|
||||
mob->audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED;
|
||||
|
||||
/* Populate mob animation references */
|
||||
entity_addAnim(assetManager, mob, animlist_hero_idle);
|
||||
entity_addAnim(assetManager, mob, animlist_hero_walk);
|
||||
entity_addAnim(assetManager, mob, animlist_hero_wave);
|
||||
entity_addAnim(assetManager, mob, animlist_hero_battlePose);
|
||||
entity_addAnim(assetManager, mob, animlist_hero_tackle);
|
||||
mob->currAnimId = animlist_hero_idle;
|
||||
entity_addAnim(assetManager, mob, "Claude idle");
|
||||
}
|
||||
|
||||
Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size,
|
||||
|
@ -175,16 +175,13 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
||||
v2 pivotPoint, f32 rotate, v4 color)
|
||||
{
|
||||
i32 strLen = common_strlen(string);
|
||||
// TODO(doyle): Scale, not too important .. but rudimentary infrastructure
|
||||
// laid out here
|
||||
f32 scale = 1.0f;
|
||||
|
||||
// TODO(doyle): Slightly incorrect string length in pixels calculation,
|
||||
// because we use the advance metric of each character for length not
|
||||
// maximum character size in rendering
|
||||
v2 rightAlignedP =
|
||||
v2_add(pos, V2(scale *(CAST(f32) font->maxSize.w * CAST(f32) strLen),
|
||||
scale * CAST(f32) font->maxSize.h));
|
||||
v2_add(pos, V2((CAST(f32) font->maxSize.w * CAST(f32) strLen),
|
||||
CAST(f32) font->maxSize.h));
|
||||
v2 leftAlignedP = pos;
|
||||
if (math_pointInRect(camera, leftAlignedP) ||
|
||||
math_pointInRect(camera, rightAlignedP))
|
||||
@ -197,27 +194,32 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
||||
pos = posInCameraSpace;
|
||||
|
||||
// TODO(doyle): Find why font is 1px off, might be arial font semantics
|
||||
Texture *tex = font->atlas->tex;
|
||||
f32 baseline = pos.y - font->verticalSpacing + 1;
|
||||
for (i32 i = 0; i < strLen; i++)
|
||||
{
|
||||
// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint
|
||||
// to its actual atlas index, i.e. we skip the first 31 glyphs
|
||||
i32 codepoint = string[i];
|
||||
i32 relativeIndex = CAST(i32)(codepoint - font->codepointRange.x);
|
||||
CharMetrics charMetric = font->charMetrics[relativeIndex];
|
||||
pos.y = baseline - (scale * charMetric.offset.y);
|
||||
pos.y = baseline - (charMetric.offset.y);
|
||||
|
||||
const v4 charRectOnScreen =
|
||||
math_getRect(pos, V2(scale * CAST(f32) font->maxSize.w,
|
||||
scale * CAST(f32) font->maxSize.h));
|
||||
math_getRect(pos, V2(CAST(f32) font->maxSize.w,
|
||||
CAST(f32) font->maxSize.h));
|
||||
|
||||
pos.x += scale * charMetric.advance;
|
||||
pos.x += charMetric.advance;
|
||||
|
||||
/* Get texture out */
|
||||
v4 charTexRect = font->atlas->texRect[relativeIndex];
|
||||
flipTexCoord(&charTexRect, FALSE, TRUE);
|
||||
RenderTex renderTex = {font->tex, charTexRect};
|
||||
Rect charTexRect =
|
||||
asset_getAtlasSubTexRect(font->atlas, &CAST(char)codepoint);
|
||||
|
||||
v4 deprecatedTexRect = {0};
|
||||
deprecatedTexRect.vec2[0] = charTexRect.pos;
|
||||
deprecatedTexRect.vec2[1] = v2_add(charTexRect.pos, charTexRect.size);
|
||||
|
||||
flipTexCoord(&deprecatedTexRect, FALSE, TRUE);
|
||||
|
||||
RenderTex renderTex = {tex, deprecatedTexRect};
|
||||
RenderQuad charQuad =
|
||||
createTexQuad(renderer, charRectOnScreen, renderTex);
|
||||
stringQuads[quadIndex++] = charQuad;
|
||||
@ -228,7 +230,7 @@ void renderer_string(Renderer *const renderer, MemoryArena *arena, Rect camera,
|
||||
// we're rendering a window sized buffer
|
||||
updateBufferObject(renderer, stringQuads, quadIndex);
|
||||
renderObject(renderer, V2(0.0f, 0.0f), renderer->size, pivotPoint,
|
||||
rotate, color, font->tex);
|
||||
rotate, color, tex);
|
||||
PLATFORM_MEM_FREE(arena, stringQuads, strLen * sizeof(RenderQuad));
|
||||
}
|
||||
}
|
||||
@ -246,12 +248,17 @@ void renderer_entity(Renderer *renderer, Rect camera, Entity *entity,
|
||||
if (math_pointInRect(camera, leftAlignedP) ||
|
||||
math_pointInRect(camera, rightAlignedP))
|
||||
{
|
||||
EntityAnim_ *entityAnim = &entity->anim[entity->currAnimId];
|
||||
Animation *anim = entityAnim->anim;
|
||||
i32 frameIndex = anim->frameIndex[entityAnim->currFrame];
|
||||
v4 animTexRect = anim->atlas->texRect[frameIndex];
|
||||
EntityAnim *entityAnim = &entity->animList[entity->currAnimId];
|
||||
Animation *anim = entityAnim->anim;
|
||||
char *frameName = anim->frameList[entityAnim->currFrame];
|
||||
Rect animRect = asset_getAtlasSubTexRect(anim->atlas, frameName);
|
||||
|
||||
if (entity->direction == direction_east)
|
||||
// TODO(doyle): Switch to rect
|
||||
v4 animTexRect = {0};
|
||||
animTexRect.vec2[0] = animRect.pos;
|
||||
animTexRect.vec2[1] = v2_add(animRect.pos, animRect.size);
|
||||
|
||||
if (entity->direction == direction_east)
|
||||
{
|
||||
flipTexCoord(&animTexRect, TRUE, FALSE);
|
||||
}
|
||||
|
@ -420,9 +420,6 @@ INTERNAL void assetInit(GameState *state)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(doyle): Use a proper random seed
|
||||
#define RANDOM_SEED 0xDEADBEEF
|
||||
|
||||
#if 1
|
||||
DEBUG_RECURSIVE_PRINT_XML_TREE(&root);
|
||||
#endif
|
||||
@ -433,31 +430,11 @@ INTERNAL void assetInit(GameState *state)
|
||||
if(common_strcmp(node->name, "TextureAtlas") == 0)
|
||||
{
|
||||
XmlNode *atlasXmlNode = node;
|
||||
TexAtlasEntry *atlasEntry = NULL;
|
||||
TexAtlas *atlasEntry = NULL;
|
||||
if (common_strcmp(node->attribute.name, "imagePath") == 0)
|
||||
{
|
||||
char *imageName = atlasXmlNode->attribute.value;
|
||||
u32 atlasHashIndex = common_murmurHash2(
|
||||
imageName, common_strlen(imageName), RANDOM_SEED);
|
||||
atlasHashIndex =
|
||||
atlasHashIndex % ARRAY_COUNT(assetManager->texAtlas_);
|
||||
|
||||
atlasEntry = &assetManager->texAtlas_[atlasHashIndex];
|
||||
if (atlasEntry->name)
|
||||
{
|
||||
#ifdef DENGINE_DEBUG
|
||||
|
||||
// NOTE(doyle): Two atlas textures have the same access name
|
||||
ASSERT(common_strcmp(atlasEntry->name, imageName) != 0);
|
||||
#endif
|
||||
|
||||
while (atlasEntry->next)
|
||||
atlasEntry = atlasEntry->next;
|
||||
|
||||
atlasEntry->next =
|
||||
PLATFORM_MEM_ALLOC(arena, 1, TexAtlasEntry);
|
||||
atlasEntry = atlasEntry->next;
|
||||
}
|
||||
atlasEntry = asset_makeTexAtlas(assetManager, arena, imageName);
|
||||
|
||||
char *dataDir = "data/textures/WorldTraveller/";
|
||||
char imagePath[512] = {0};
|
||||
@ -466,9 +443,9 @@ INTERNAL void assetInit(GameState *state)
|
||||
|
||||
asset_loadTextureImage(assetManager, imagePath, texlist_claude);
|
||||
|
||||
atlasEntry->name =
|
||||
PLATFORM_MEM_ALLOC(arena, common_strlen(imageName), char);
|
||||
common_strncpy(atlasEntry->name, imageName,
|
||||
atlasEntry->key =
|
||||
PLATFORM_MEM_ALLOC(arena, common_strlen(imageName)+1, char);
|
||||
common_strncpy(atlasEntry->key, imageName,
|
||||
common_strlen(imageName));
|
||||
|
||||
atlasEntry->tex =
|
||||
@ -495,39 +472,43 @@ INTERNAL void assetInit(GameState *state)
|
||||
0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
newSubTexEntry.name = value;
|
||||
newSubTexEntry.key = value;
|
||||
}
|
||||
else if (common_strcmp(subTextureAttrib->name,
|
||||
"x") == 0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
i32 valueLen = common_strlen(value);
|
||||
newSubTexEntry.rect.pos.x =
|
||||
CAST(f32) common_atoi(value, valueLen);
|
||||
i32 intValue = common_atoi(value, valueLen);
|
||||
|
||||
newSubTexEntry.rect.pos.x = CAST(f32) intValue;
|
||||
}
|
||||
else if (common_strcmp(subTextureAttrib->name,
|
||||
"y") == 0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
i32 valueLen = common_strlen(value);
|
||||
newSubTexEntry.rect.pos.y =
|
||||
CAST(f32) common_atoi(value, valueLen);
|
||||
|
||||
i32 intValue = common_atoi(value, valueLen);
|
||||
newSubTexEntry.rect.pos.y = CAST(f32) intValue;
|
||||
}
|
||||
else if (common_strcmp(subTextureAttrib->name,
|
||||
"width") == 0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
i32 valueLen = common_strlen(value);
|
||||
newSubTexEntry.rect.size.w =
|
||||
CAST(f32) common_atoi(value, valueLen);
|
||||
i32 intValue = common_atoi(value, valueLen);
|
||||
|
||||
newSubTexEntry.rect.size.w = CAST(f32) intValue;
|
||||
}
|
||||
else if (common_strcmp(subTextureAttrib->name,
|
||||
"height") == 0)
|
||||
{
|
||||
char *value = subTextureAttrib->value;
|
||||
i32 valueLen = common_strlen(value);
|
||||
newSubTexEntry.rect.size.h =
|
||||
CAST(f32) common_atoi(value, valueLen);
|
||||
i32 intValue = common_atoi(value, valueLen);
|
||||
|
||||
newSubTexEntry.rect.size.h = CAST(f32) intValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -536,32 +517,37 @@ INTERNAL void assetInit(GameState *state)
|
||||
"Unsupported xml attribute in SubTexture");
|
||||
#endif
|
||||
}
|
||||
|
||||
subTextureAttrib = subTextureAttrib->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;
|
||||
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(newSubTexEntry.name)
|
||||
ASSERT(newSubTexEntry.key)
|
||||
#endif
|
||||
|
||||
|
||||
u32 subTexHashIndex = common_murmurHash2(
|
||||
newSubTexEntry.name, common_strlen(newSubTexEntry.name),
|
||||
RANDOM_SEED);
|
||||
newSubTexEntry.key,
|
||||
common_strlen(newSubTexEntry.key), 0xDEADBEEF);
|
||||
subTexHashIndex =
|
||||
subTexHashIndex % ARRAY_COUNT(atlasEntry->subTex);
|
||||
|
||||
// NOTE(doyle): Hash collision
|
||||
AtlasSubTexture *subTexEntry =
|
||||
&atlasEntry->subTex[subTexHashIndex];
|
||||
if (subTexEntry->name)
|
||||
if (subTexEntry->key)
|
||||
{
|
||||
#ifdef DENGINE_DEBUG
|
||||
|
||||
// NOTE(doyle): Two textures have the same access
|
||||
// name
|
||||
ASSERT(common_strcmp(subTexEntry->name,
|
||||
newSubTexEntry.name) != 0);
|
||||
ASSERT(common_strcmp(subTexEntry->key,
|
||||
newSubTexEntry.key) != 0);
|
||||
#endif
|
||||
while (subTexEntry->next)
|
||||
subTexEntry = subTexEntry->next;
|
||||
@ -572,8 +558,12 @@ INTERNAL void assetInit(GameState *state)
|
||||
}
|
||||
|
||||
*subTexEntry = newSubTexEntry;
|
||||
common_strncpy(subTexEntry->name, newSubTexEntry.name,
|
||||
common_strlen(newSubTexEntry.name));
|
||||
i32 keyLen = common_strlen(newSubTexEntry.key);
|
||||
|
||||
subTexEntry->key =
|
||||
PLATFORM_MEM_ALLOC(arena, keyLen+1, char);
|
||||
common_strncpy(subTexEntry->key, newSubTexEntry.key,
|
||||
keyLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -601,34 +591,6 @@ INTERNAL void assetInit(GameState *state)
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
/* Load textures */
|
||||
asset_loadTextureImage(assetManager,
|
||||
"data/textures/WorldTraveller/TerraSprite1024.png",
|
||||
texlist_hero);
|
||||
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);
|
||||
heroAtlas->texRect[herorects_idle] = V4(746, 920, 804, 1018);
|
||||
heroAtlas->texRect[herorects_walkA] = V4(641, 920, 699, 1018);
|
||||
heroAtlas->texRect[herorects_walkB] = V4(849, 920, 904, 1018);
|
||||
heroAtlas->texRect[herorects_head] = V4(108, 975, 159, 1024);
|
||||
heroAtlas->texRect[herorects_waveA] = V4(944, 816, 1010, 918);
|
||||
heroAtlas->texRect[herorects_waveB] = V4(944, 710, 1010, 812);
|
||||
heroAtlas->texRect[herorects_battlePose] = V4(8, 814, 71, 910);
|
||||
heroAtlas->texRect[herorects_castA] = V4(428, 814, 493, 910);
|
||||
heroAtlas->texRect[herorects_castB] = V4(525, 816, 590, 919);
|
||||
heroAtlas->texRect[herorects_castC] = V4(640, 816, 698, 916);
|
||||
|
||||
asset_loadTextureImage(assetManager,
|
||||
"data/textures/WorldTraveller/Terrain.png",
|
||||
texlist_terrain);
|
||||
TexAtlas *terrainAtlas =
|
||||
asset_getTextureAtlas(assetManager, texlist_terrain);
|
||||
f32 atlasTileSize = 128.0f;
|
||||
const i32 texSize = 1024;
|
||||
v2 texOrigin = V2(0, 768);
|
||||
terrainAtlas->texRect[terrainrects_ground] =
|
||||
V4(texOrigin.x, texOrigin.y, texOrigin.x + atlasTileSize,
|
||||
texOrigin.y + atlasTileSize);
|
||||
|
||||
/* Load shaders */
|
||||
asset_loadShaderFiles(assetManager, arena, "data/shaders/sprite.vert.glsl",
|
||||
"data/shaders/sprite.frag.glsl",
|
||||
@ -643,6 +605,7 @@ INTERNAL void assetInit(GameState *state)
|
||||
DEBUG_LOG("Assets loaded");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Load animations */
|
||||
f32 duration = 1.0f;
|
||||
i32 numRects = 1;
|
||||
@ -660,7 +623,20 @@ INTERNAL void assetInit(GameState *state)
|
||||
i32 idleAnimAtlasIndexes[1] = {herorects_idle};
|
||||
asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_idle,
|
||||
idleAnimAtlasIndexes, numRects, duration);
|
||||
#else
|
||||
f32 duration = 1.0f;
|
||||
i32 numRects = 1;
|
||||
TexAtlas *claudeAtlas =
|
||||
asset_getTexAtlas(assetManager, "ClaudeSpriteSheet.png");
|
||||
|
||||
duration = 1.0f;
|
||||
numRects = 1;
|
||||
char *subTextureNames = {"ClaudeSprite_001"};
|
||||
asset_addAnimation(assetManager, arena, "Claude_idle", claudeAtlas,
|
||||
&subTextureNames, 1, 1.0f);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Walk animation
|
||||
duration = 0.10f;
|
||||
numRects = 3;
|
||||
@ -690,6 +666,8 @@ INTERNAL void assetInit(GameState *state)
|
||||
herorects_castC};
|
||||
asset_addAnimation(assetManager, arena, texlist_hero, animlist_hero_tackle,
|
||||
tackleAnimAtlasIndexes, numRects, duration);
|
||||
#endif
|
||||
|
||||
#ifdef DENGINE_DEBUG
|
||||
DEBUG_LOG("Animations created");
|
||||
#endif
|
||||
@ -739,6 +717,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||
CAST(f32) state->tileSize));
|
||||
world->uniqueIdAccumulator = 0;
|
||||
|
||||
#if 0
|
||||
TexAtlas *const atlas =
|
||||
asset_getTextureAtlas(assetManager, world->texType);
|
||||
|
||||
@ -765,6 +744,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||
tile->currAnimId = animlist_terrain;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
World *const world = &state->world[state->currWorldIndex];
|
||||
@ -790,7 +770,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||
pos = V2(size.x, CAST(f32) state->tileSize);
|
||||
type = entitytype_hero;
|
||||
dir = direction_east;
|
||||
tex = asset_getTexture(assetManager, texlist_hero);
|
||||
tex = asset_getTexture(assetManager, texlist_claude);
|
||||
collides = TRUE;
|
||||
Entity *hero =
|
||||
entity_add(arena, world, pos, size, type, dir, tex, collides);
|
||||
@ -801,13 +781,10 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||
world->cameraFollowingId = hero->id;
|
||||
|
||||
/* Populate hero animation references */
|
||||
entity_addAnim(assetManager, hero, animlist_hero_idle);
|
||||
entity_addAnim(assetManager, hero, animlist_hero_walk);
|
||||
entity_addAnim(assetManager, hero, animlist_hero_wave);
|
||||
entity_addAnim(assetManager, hero, animlist_hero_battlePose);
|
||||
entity_addAnim(assetManager, hero, animlist_hero_tackle);
|
||||
hero->currAnimId = animlist_hero_idle;
|
||||
entity_addAnim(assetManager, hero, "Claude_idle");
|
||||
entity_setActiveAnim(hero, "Claude_idle");
|
||||
|
||||
#if 0
|
||||
/* Create a NPC */
|
||||
pos = V2(hero->pos.x * 3, CAST(f32) state->tileSize);
|
||||
size = hero->hitboxSize;
|
||||
@ -825,6 +802,7 @@ INTERNAL void entityInit(GameState *state, v2 windowSize)
|
||||
pos = V2(renderer->size.w - (renderer->size.w / 3.0f),
|
||||
CAST(f32) state->tileSize);
|
||||
entity_addGenericMob(arena, assetManager, world, pos);
|
||||
#endif
|
||||
|
||||
#ifdef DENGINE_DEBUG
|
||||
DEBUG_LOG("World populated");
|
||||
@ -1152,7 +1130,7 @@ INTERNAL inline void updateWorldBattleEntities(World *world, Entity *entity,
|
||||
INTERNAL inline void resetEntityState(World *world, Entity *entity)
|
||||
{
|
||||
updateWorldBattleEntities(world, entity, ENTITY_NOT_IN_BATTLE);
|
||||
entity_setActiveAnim(entity, animlist_hero_idle);
|
||||
entity_setActiveAnim(entity, "Claude_idle");
|
||||
entity->stats->busyDuration = 0;
|
||||
entity->stats->actionTimer = entity->stats->actionRate;
|
||||
entity->stats->queuedAttack = entityattack_invalid;
|
||||
@ -1196,7 +1174,7 @@ INTERNAL void entityStateSwitch(EventQueue *eventQueue, World *world,
|
||||
// or not (i.e. has moved out of frame last frame).
|
||||
case entitystate_dead:
|
||||
registerEvent(eventQueue, eventtype_entity_died, CAST(void *)entity);
|
||||
entity_setActiveAnim(entity, animlist_hero_idle);
|
||||
entity_setActiveAnim(entity, "Claude_idle");
|
||||
entity->stats->busyDuration = 0;
|
||||
entity->stats->actionTimer = entity->stats->actionRate;
|
||||
entity->stats->queuedAttack = entityattack_invalid;
|
||||
@ -1236,7 +1214,7 @@ INTERNAL void entityStateSwitch(EventQueue *eventQueue, World *world,
|
||||
switch (newState)
|
||||
{
|
||||
case entitystate_battle:
|
||||
entity_setActiveAnim(entity, animlist_hero_battlePose);
|
||||
entity_setActiveAnim(entity, "Claude_idle");
|
||||
entity->stats->actionTimer = entity->stats->actionRate;
|
||||
entity->stats->busyDuration = 0;
|
||||
break;
|
||||
@ -1288,6 +1266,7 @@ typedef struct AttackSpec
|
||||
INTERNAL void beginAttack(EventQueue *eventQueue, World *world,
|
||||
Entity *attacker)
|
||||
{
|
||||
#if 0
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
|
||||
ASSERT(attacker->state == entitystate_battle);
|
||||
@ -1313,6 +1292,7 @@ INTERNAL void beginAttack(EventQueue *eventQueue, World *world,
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO(doyle): MemArena here is temporary until we incorporate AttackSpec to
|
||||
@ -1320,6 +1300,7 @@ INTERNAL void beginAttack(EventQueue *eventQueue, World *world,
|
||||
INTERNAL void endAttack(MemoryArena *arena, EventQueue *eventQueue,
|
||||
World *world, Entity *attacker)
|
||||
{
|
||||
#if 0
|
||||
#ifdef DENGINE_DEBUG
|
||||
ASSERT(attacker->stats->entityIdToAttack != ENTITY_NULL_ID);
|
||||
#endif
|
||||
@ -1398,6 +1379,7 @@ INTERNAL void endAttack(MemoryArena *arena, EventQueue *eventQueue,
|
||||
entityStateSwitch(eventQueue, world, attacker, entitystate_idle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
INTERNAL void sortWorldEntityList(World *world)
|
||||
@ -1735,12 +1717,12 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||
hero->dPos = V2(0.0f, 0.0f);
|
||||
if (hero->currAnimId == animlist_hero_walk)
|
||||
{
|
||||
entity_setActiveAnim(hero, animlist_hero_idle);
|
||||
entity_setActiveAnim(hero, "Claude_idle");
|
||||
}
|
||||
}
|
||||
else if (hero->currAnimId == animlist_hero_idle)
|
||||
{
|
||||
entity_setActiveAnim(hero, animlist_hero_walk);
|
||||
entity_setActiveAnim(hero, "Claude_idle");
|
||||
}
|
||||
|
||||
f32 heroSpeed = 6.2f * METERS_TO_PIXEL;
|
||||
@ -1978,7 +1960,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||
{
|
||||
hero->state = entitystate_idle;
|
||||
world->entityIdInBattle[hero->id] = FALSE;
|
||||
entity_setActiveAnim(hero, animlist_hero_idle);
|
||||
entity_setActiveAnim(hero, "Claude_idle");
|
||||
}
|
||||
hero->stats->entityIdToAttack = -1;
|
||||
hero->stats->actionTimer = hero->stats->actionRate;
|
||||
@ -2058,6 +2040,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||
state->uiState.keyChar = keycode_null;
|
||||
|
||||
/* Draw hero avatar */
|
||||
#if 0
|
||||
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);
|
||||
v4 heroAvatarTexRect = heroAtlas->texRect[herorects_head];
|
||||
v2 heroAvatarSize = math_getRectSize(heroAvatarTexRect);
|
||||
@ -2079,6 +2062,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||
|
||||
renderer_staticString(&state->renderer, &state->arena, font, heroAvatarStr,
|
||||
strPos, V2(0, 0), 0, V4(0, 0, 1, 1));
|
||||
#endif
|
||||
|
||||
for (i32 i = 0; i < world->maxEntities; i++)
|
||||
{
|
||||
|
@ -11,25 +11,33 @@ typedef struct MemoryArena MemoryArena;
|
||||
typedef struct AssetManager
|
||||
{
|
||||
Texture textures[32];
|
||||
TexAtlas texAtlas[32];
|
||||
Shader shaders[32];
|
||||
Animation anims[32];
|
||||
Animation anims[1024];
|
||||
AudioVorbis audio[32];
|
||||
Font font;
|
||||
|
||||
TexAtlasEntry texAtlas_[8];
|
||||
TexAtlas texAtlas[8];
|
||||
} AssetManager;
|
||||
|
||||
#define MAX_TEXTURE_SIZE 1024
|
||||
|
||||
Rect asset_getAtlasSubTexRect(TexAtlas *atlas, char *key);
|
||||
|
||||
AudioVorbis *asset_getVorbis(AssetManager *assetManager,
|
||||
const enum AudioList type);
|
||||
|
||||
Texture *asset_getTexture(AssetManager *const assetManager,
|
||||
const enum TexList type);
|
||||
|
||||
TexAtlas *asset_makeTexAtlas(AssetManager *const assetManager,
|
||||
MemoryArena *arena, const char *const key);
|
||||
|
||||
Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type);
|
||||
TexAtlas *asset_getTextureAtlas(AssetManager *assetManager,
|
||||
const enum TexList type);
|
||||
Animation *asset_getAnim(AssetManager *assetManager, i32 type);
|
||||
|
||||
TexAtlas *asset_getTexAtlas(AssetManager *const assetManager,
|
||||
const char *const key);
|
||||
|
||||
Animation *asset_getAnim(AssetManager *assetManager, char *key);
|
||||
|
||||
const i32 asset_loadVorbis(AssetManager *assetManager, MemoryArena *arena,
|
||||
const char *const path, const enum AudioList type);
|
||||
@ -46,8 +54,8 @@ const i32 asset_loadTTFont(AssetManager *assetManager, MemoryArena *arena,
|
||||
const char *filePath);
|
||||
|
||||
void asset_addAnimation(AssetManager *assetManager, MemoryArena *arena,
|
||||
i32 texId, i32 animId, i32 *atlasIndexes, i32 numFrames,
|
||||
f32 frameDuration);
|
||||
char *animName, TexAtlas *atlas, char **subTextureNames,
|
||||
i32 numSubTextures, f32 frameDuration);
|
||||
|
||||
v2 asset_stringDimInPixels(const Font *const font, const char *const string);
|
||||
|
||||
|
@ -83,36 +83,37 @@ typedef struct AudioVorbis
|
||||
|
||||
typedef struct AtlasSubTexture
|
||||
{
|
||||
char *name;
|
||||
// NOTE(doyle): Key used to arrive to hash entry
|
||||
char *key;
|
||||
Rect rect;
|
||||
|
||||
// NOTE(doyle): For hashing collisions
|
||||
struct AtlasSubTexture *next;
|
||||
} AtlasSubTexture;
|
||||
|
||||
typedef struct TexAtlasEntry
|
||||
{
|
||||
char *name;
|
||||
Texture *tex;
|
||||
AtlasSubTexture subTex[1024];
|
||||
|
||||
// NOTE(doyle): For hashing collisions
|
||||
struct TexAtlasEntry *next;
|
||||
} TexAtlasEntry;
|
||||
|
||||
typedef struct TexAtlas
|
||||
{
|
||||
// TODO(doyle): String hash based lookup
|
||||
v4 texRect[128];
|
||||
char *key;
|
||||
Texture *tex;
|
||||
AtlasSubTexture subTex[512];
|
||||
|
||||
struct TexAtlas *next;
|
||||
} TexAtlas;
|
||||
|
||||
typedef struct Animation
|
||||
{
|
||||
union {
|
||||
char *name;
|
||||
char *key;
|
||||
};
|
||||
|
||||
TexAtlas *atlas;
|
||||
i32 *frameIndex;
|
||||
char **frameList;
|
||||
|
||||
i32 numFrames;
|
||||
f32 frameDuration;
|
||||
|
||||
struct Animation *next;
|
||||
} Animation;
|
||||
|
||||
// TODO(doyle): We only use the offset and advance metric at the moment, remove?
|
||||
@ -136,8 +137,6 @@ typedef struct CharMetrics
|
||||
typedef struct Font
|
||||
{
|
||||
TexAtlas *atlas;
|
||||
Texture *tex;
|
||||
|
||||
FontMetrics metrics;
|
||||
|
||||
// NOTE(doyle): Array of character's by ASCII value starting from
|
||||
|
@ -54,4 +54,14 @@ i32 common_atoi(const char *string, const i32 len);
|
||||
// machines.
|
||||
u32 common_murmurHash2(const void *key, i32 len, u32 seed);
|
||||
|
||||
// TODO(doyle): Use a proper random seed
|
||||
#define RANDOM_SEED 0xDEADBEEF
|
||||
inline u32 common_getHashIndex(const char *const key, u32 tableSize)
|
||||
{
|
||||
u32 result = common_murmurHash2(key, common_strlen(key), RANDOM_SEED);
|
||||
result = result % tableSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -63,12 +63,12 @@ typedef struct EntityStats
|
||||
enum EntityAttack queuedAttack;
|
||||
} EntityStats;
|
||||
|
||||
typedef struct EntityAnim_
|
||||
typedef struct EntityAnim
|
||||
{
|
||||
Animation *anim;
|
||||
i32 currFrame;
|
||||
f32 currDuration;
|
||||
} EntityAnim_;
|
||||
} EntityAnim;
|
||||
|
||||
typedef struct Entity
|
||||
{
|
||||
@ -86,22 +86,17 @@ typedef struct Entity
|
||||
Texture *tex;
|
||||
b32 collides;
|
||||
|
||||
// TODO(doyle): String based access
|
||||
// TODO(doyle): Separate animation refs from curr animation state, entity
|
||||
// only ever has one active current animation. ATM every entity animation
|
||||
// has a currframe and duration .. either that or we stop resetting
|
||||
// animation on entity context switch
|
||||
EntityAnim_ anim[16];
|
||||
enum AnimList currAnimId;
|
||||
EntityAnim animList[16];
|
||||
i32 currAnimId;
|
||||
|
||||
EntityStats *stats;
|
||||
AudioRenderer *audioRenderer;
|
||||
i32 numAudioRenderers;
|
||||
} Entity;
|
||||
|
||||
void entity_setActiveAnim(Entity *entity, enum AnimList animId);
|
||||
void entity_setActiveAnim(Entity *entity, char *animName);
|
||||
void entity_updateAnim(Entity *entity, f32 dt);
|
||||
void entity_addAnim(AssetManager *assetManager, Entity *entity, i32 animId);
|
||||
void entity_addAnim(AssetManager *assetManager, Entity *entity, char *animName);
|
||||
void entity_addGenericMob(MemoryArena *arena, AssetManager *assetManager,
|
||||
World *world, v2 pos);
|
||||
Entity *entity_add(MemoryArena *arena, World *world, v2 pos, v2 size,
|
||||
|
@ -25,6 +25,8 @@ typedef struct Renderer
|
||||
typedef struct RenderTex
|
||||
{
|
||||
Texture *tex;
|
||||
|
||||
// TODO(doyle): Switch to rect
|
||||
v4 texRect;
|
||||
} RenderTex;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user