339 lines
7.4 KiB
C
339 lines
7.4 KiB
C
|
#if !defined(HANDMADE_ASSET_H)
|
||
|
/* ========================================================================
|
||
|
$File: $
|
||
|
$Date: $
|
||
|
$Revision: $
|
||
|
$Creator: Casey Muratori $
|
||
|
$Notice: (C) Copyright 2015 by Molly Rocket, Inc. All Rights Reserved. $
|
||
|
======================================================================== */
|
||
|
|
||
|
struct loaded_sound
|
||
|
{
|
||
|
int16 *Samples[2];
|
||
|
u32 SampleCount; // NOTE(casey): This is the sample count divided by 8
|
||
|
u32 ChannelCount;
|
||
|
};
|
||
|
|
||
|
struct loaded_font
|
||
|
{
|
||
|
hha_font_glyph *Glyphs;
|
||
|
r32 *HorizontalAdvance;
|
||
|
u32 BitmapIDOffset;
|
||
|
u16 *UnicodeMap;
|
||
|
};
|
||
|
|
||
|
// TODO(casey): Streamling this, by using header pointer as an indicator of unloaded status?
|
||
|
enum asset_state
|
||
|
{
|
||
|
AssetState_Unloaded,
|
||
|
AssetState_Queued,
|
||
|
AssetState_Loaded,
|
||
|
};
|
||
|
|
||
|
struct asset_memory_header
|
||
|
{
|
||
|
asset_memory_header *Next;
|
||
|
asset_memory_header *Prev;
|
||
|
|
||
|
u32 AssetIndex;
|
||
|
u32 TotalSize;
|
||
|
u32 GenerationID;
|
||
|
union
|
||
|
{
|
||
|
loaded_bitmap Bitmap;
|
||
|
loaded_sound Sound;
|
||
|
loaded_font Font;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
struct asset
|
||
|
{
|
||
|
u32 State;
|
||
|
asset_memory_header *Header;
|
||
|
|
||
|
hha_asset HHA;
|
||
|
u32 FileIndex;
|
||
|
};
|
||
|
|
||
|
struct asset_vector
|
||
|
{
|
||
|
real32 E[Tag_Count];
|
||
|
};
|
||
|
|
||
|
struct asset_type
|
||
|
{
|
||
|
uint32 FirstAssetIndex;
|
||
|
uint32 OnePastLastAssetIndex;
|
||
|
};
|
||
|
|
||
|
struct asset_file
|
||
|
{
|
||
|
platform_file_handle Handle;
|
||
|
|
||
|
// TODO(casey): If we ever do thread stacks, AssetTypeArray
|
||
|
// doesn't actually need to be kept here probably.
|
||
|
hha_header Header;
|
||
|
hha_asset_type *AssetTypeArray;
|
||
|
|
||
|
u32 TagBase;
|
||
|
s32 FontBitmapIDOffset;
|
||
|
};
|
||
|
|
||
|
enum asset_memory_block_flags
|
||
|
{
|
||
|
AssetMemory_Used = 0x1,
|
||
|
};
|
||
|
struct asset_memory_block
|
||
|
{
|
||
|
asset_memory_block *Prev;
|
||
|
asset_memory_block *Next;
|
||
|
u64 Flags;
|
||
|
memory_index Size;
|
||
|
};
|
||
|
|
||
|
struct game_assets
|
||
|
{
|
||
|
u32 NextGenerationID;
|
||
|
|
||
|
// TODO(casey): Not thrilled about this back-pointer
|
||
|
struct transient_state *TranState;
|
||
|
|
||
|
asset_memory_block MemorySentinel;
|
||
|
|
||
|
asset_memory_header LoadedAssetSentinel;
|
||
|
|
||
|
real32 TagRange[Tag_Count];
|
||
|
|
||
|
u32 FileCount;
|
||
|
asset_file *Files;
|
||
|
|
||
|
uint32 TagCount;
|
||
|
hha_tag *Tags;
|
||
|
|
||
|
uint32 AssetCount;
|
||
|
asset *Assets;
|
||
|
|
||
|
asset_type AssetTypes[Asset_Count];
|
||
|
|
||
|
u32 OperationLock;
|
||
|
|
||
|
u32 InFlightGenerationCount;
|
||
|
u32 InFlightGenerations[16];
|
||
|
};
|
||
|
|
||
|
inline void
|
||
|
BeginAssetLock(game_assets *Assets)
|
||
|
{
|
||
|
for(;;)
|
||
|
{
|
||
|
if(AtomicCompareExchangeUInt32(&Assets->OperationLock, 1, 0) == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
EndAssetLock(game_assets *Assets)
|
||
|
{
|
||
|
CompletePreviousWritesBeforeFutureWrites;
|
||
|
Assets->OperationLock = 0;
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
InsertAssetHeaderAtFront(game_assets *Assets, asset_memory_header *Header)
|
||
|
{
|
||
|
asset_memory_header *Sentinel = &Assets->LoadedAssetSentinel;
|
||
|
|
||
|
Header->Prev = Sentinel;
|
||
|
Header->Next = Sentinel->Next;
|
||
|
|
||
|
Header->Next->Prev = Header;
|
||
|
Header->Prev->Next = Header;
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
RemoveAssetHeaderFromList(asset_memory_header *Header)
|
||
|
{
|
||
|
Header->Prev->Next = Header->Next;
|
||
|
Header->Next->Prev = Header->Prev;
|
||
|
|
||
|
Header->Next = Header->Prev = 0;
|
||
|
}
|
||
|
|
||
|
inline asset_memory_header *GetAsset(game_assets *Assets, u32 ID, u32 GenerationID)
|
||
|
{
|
||
|
Assert(ID <= Assets->AssetCount);
|
||
|
asset *Asset = Assets->Assets + ID;
|
||
|
|
||
|
asset_memory_header *Result = 0;
|
||
|
|
||
|
BeginAssetLock(Assets);
|
||
|
|
||
|
if(Asset->State == AssetState_Loaded)
|
||
|
{
|
||
|
Result = Asset->Header;
|
||
|
RemoveAssetHeaderFromList(Result);
|
||
|
InsertAssetHeaderAtFront(Assets, Result);
|
||
|
|
||
|
if(Asset->Header->GenerationID < GenerationID)
|
||
|
{
|
||
|
Asset->Header->GenerationID = GenerationID;
|
||
|
}
|
||
|
|
||
|
CompletePreviousWritesBeforeFutureWrites;
|
||
|
}
|
||
|
|
||
|
EndAssetLock(Assets);
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline loaded_bitmap *
|
||
|
GetBitmap(game_assets *Assets, bitmap_id ID, u32 GenerationID)
|
||
|
{
|
||
|
asset_memory_header *Header = GetAsset(Assets, ID.Value, GenerationID);
|
||
|
|
||
|
loaded_bitmap *Result = Header ? &Header->Bitmap : 0;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline hha_bitmap *
|
||
|
GetBitmapInfo(game_assets *Assets, bitmap_id ID)
|
||
|
{
|
||
|
Assert(ID.Value <= Assets->AssetCount);
|
||
|
hha_bitmap *Result = &Assets->Assets[ID.Value].HHA.Bitmap;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline loaded_sound *
|
||
|
GetSound(game_assets *Assets, sound_id ID, u32 GenerationID)
|
||
|
{
|
||
|
asset_memory_header *Header = GetAsset(Assets, ID.Value, GenerationID);
|
||
|
|
||
|
loaded_sound *Result = Header ? &Header->Sound : 0;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline hha_sound *
|
||
|
GetSoundInfo(game_assets *Assets, sound_id ID)
|
||
|
{
|
||
|
Assert(ID.Value <= Assets->AssetCount);
|
||
|
hha_sound *Result = &Assets->Assets[ID.Value].HHA.Sound;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline loaded_font *
|
||
|
GetFont(game_assets *Assets, font_id ID, u32 GenerationID)
|
||
|
{
|
||
|
asset_memory_header *Header = GetAsset(Assets, ID.Value, GenerationID);
|
||
|
|
||
|
loaded_font *Result = Header ? &Header->Font : 0;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline hha_font *
|
||
|
GetFontInfo(game_assets *Assets, font_id ID)
|
||
|
{
|
||
|
Assert(ID.Value <= Assets->AssetCount);
|
||
|
hha_font *Result = &Assets->Assets[ID.Value].HHA.Font;
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline bool32
|
||
|
IsValid(bitmap_id ID)
|
||
|
{
|
||
|
bool32 Result = (ID.Value != 0);
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline bool32
|
||
|
IsValid(sound_id ID)
|
||
|
{
|
||
|
bool32 Result = (ID.Value != 0);
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
internal void LoadBitmap(game_assets *Assets, bitmap_id ID, b32 Immediate);
|
||
|
inline void PrefetchBitmap(game_assets *Assets, bitmap_id ID) {LoadBitmap(Assets, ID, false);}
|
||
|
internal void LoadSound(game_assets *Assets, sound_id ID);
|
||
|
inline void PrefetchSound(game_assets *Assets, sound_id ID) {LoadSound(Assets, ID);}
|
||
|
internal void LoadFont(game_assets *Assets, font_id ID, b32 Immediate);
|
||
|
inline void PrefetchFont(game_assets *Assets, font_id ID) {LoadFont(Assets, ID, false);}
|
||
|
|
||
|
inline sound_id GetNextSoundInChain(game_assets *Assets, sound_id ID)
|
||
|
{
|
||
|
sound_id Result = {};
|
||
|
|
||
|
hha_sound *Info = GetSoundInfo(Assets, ID);
|
||
|
switch(Info->Chain)
|
||
|
{
|
||
|
case HHASoundChain_None:
|
||
|
{
|
||
|
// NOTE(casey): Nothing to do.
|
||
|
} break;
|
||
|
|
||
|
case HHASoundChain_Loop:
|
||
|
{
|
||
|
Result = ID;
|
||
|
} break;
|
||
|
|
||
|
case HHASoundChain_Advance:
|
||
|
{
|
||
|
Result.Value = ID.Value + 1;
|
||
|
} break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
InvalidCodePath;
|
||
|
} break;
|
||
|
}
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline u32
|
||
|
BeginGeneration(game_assets *Assets)
|
||
|
{
|
||
|
BeginAssetLock(Assets);
|
||
|
|
||
|
Assert(Assets->InFlightGenerationCount < ArrayCount(Assets->InFlightGenerations));
|
||
|
u32 Result = Assets->NextGenerationID++;
|
||
|
Assets->InFlightGenerations[Assets->InFlightGenerationCount++] = Result;
|
||
|
|
||
|
EndAssetLock(Assets);
|
||
|
|
||
|
return(Result);
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
EndGeneration(game_assets *Assets, u32 GenerationID)
|
||
|
{
|
||
|
BeginAssetLock(Assets);
|
||
|
|
||
|
for(u32 Index = 0;
|
||
|
Index < Assets->InFlightGenerationCount;
|
||
|
++Index)
|
||
|
{
|
||
|
if(Assets->InFlightGenerations[Index] == GenerationID)
|
||
|
{
|
||
|
Assets->InFlightGenerations[Index] =
|
||
|
Assets->InFlightGenerations[--Assets->InFlightGenerationCount];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EndAssetLock(Assets);
|
||
|
}
|
||
|
|
||
|
#define HANDMADE_ASSET_H
|
||
|
#endif
|