vn/code/vn_animation_curve.cpp

161 lines
3.6 KiB
C++

global animation_curve_state *Global_AnimationCurveState = 0;
////////////////////////////////
//~ sixten: Animation Curve Functions
inline animation_curve_state *AC_GetState(void)
{
return(Global_AnimationCurveState);
}
inline void AC_SetState(animation_curve_state *State)
{
Global_AnimationCurveState = State;
}
static void AC_Init(animation_curve_state *State)
{
State->Arena = ArenaAlloc(Kilobytes(32), true, "Animation Curve State Arena");
}
inline animation_curve_key AC_GenerateKeyFromString(string String)
{
animation_curve_key Key;
Key.Value = HashString(String);
return(Key);
}
static animation_curve_entry *AC_GetEntryByKey(animation_curve_key Key, r32 Initial)
{
animation_curve_state *State = AC_GetState();
u64 Hash = Key.Value;
u64 Slot = Hash % ArrayCount(State->Buckets);
animation_curve_bucket *Bucket = State->Buckets + Slot;
animation_curve_entry *Result = 0;
for(animation_curve_entry *Entry = Bucket->First;
Entry != 0;
Entry = Entry->Next)
{
if(AreEqual(Entry->Key, Key))
{
Result = Entry;
break;
}
}
if(!Result)
{
if(DLLIsEmpty(State->FirstFreeEntry))
{
Result = PushStruct(State->Arena, animation_curve_entry);
}
else
{
Result = State->FirstFreeEntry;
DLLRemove(State->FirstFreeEntry, State->LastFreeEntry, Result);
}
DLLInsertLast(Bucket->First, Bucket->Last, Result);
Result->Value = Initial;
}
Result->Key = Key;
Result->LastFrameTouched = State->CurrentFrame;
return(Result);
}
inline r32 AC_GetValue(string Name, r32 Initial)
{
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
r32 Result = Entry->Value;
return(Result);
}
inline void AC_SetValue(string Name, r32 Value)
{
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Value);
Entry->Value = Value;
}
inline r32 AC_AnimateValueDirect(r32 Target, r32 Duration, r32 *Value)
{
animation_curve_state *State = AC_GetState();
//- sixten: make sure the value is valid
if(*Value != *Value) *Value = 0;
r32 Result = *Value;
r32 Rate = 1.0 - Pow(2, -(10.0 / Duration * State->dtForFrame));
*Value += (Target - *Value) * Rate;
return(Result);
}
inline r32 AC_AnimateValue(r32 Target, r32 Initial, r32 Duration, string Name)
{
animation_curve_key Key = AC_GenerateKeyFromString(Name);
animation_curve_entry *Entry = AC_GetEntryByKey(Key, Initial);
r32 Result = AC_AnimateValueDirect(Target, Duration, &Entry->Value);
return(Result);
}
inline r32 AC_AnimateValueF(r32 Target, r32 Initial, r32 Duration, char *Format, ...)
{
temp Scratch = GetScratch(0, 0);
va_list Arguments;
va_start(Arguments, Format);
string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
va_end(Arguments);
r32 Result = AC_AnimateValue(Target, Initial, Duration, String);
ReleaseScratch(Scratch);
return(Result);
}
static void AC_NewFrame(animation_curve_state *State, r32 dtForFrame)
{
AC_SetState(State);
State->dtForFrame = dtForFrame;
// sixten: Prune untouched entries.
for(s32 BucketIndex = 0;
BucketIndex < ArrayCount(State->Buckets);
++BucketIndex)
{
animation_curve_bucket *Bucket = State->Buckets + BucketIndex;
animation_curve_entry *Entry = Bucket->First;
while(Entry != 0)
{
if(Entry->LastFrameTouched != State->CurrentFrame)
{
animation_curve_entry *ToRemove = Entry;
Entry = Entry->Next;
DLLRemove(Bucket->First, Bucket->Last, ToRemove);
DLLInsertLast(State->FirstFreeEntry, State->LastFreeEntry, ToRemove);
}
else
{
Entry = Entry->Next;
}
}
}
++State->CurrentFrame;
}