Moved everything over to using frames rather than seconds in the animation system.

This commit is contained in:
Peter Slattery 2020-02-29 17:11:15 -08:00
parent dc36d44cd2
commit 197b6accc7
4 changed files with 126 additions and 134 deletions

View File

@ -92,8 +92,8 @@ static void DebugPrint(char* Format, ...);
if((expression)) \ if((expression)) \
{ \ { \
}else{ \ }else{ \
volatile int* p = 0; \ volatile int* p = 0; \
*p = 5; \ *p = 5; \
} }
#endif #endif

View File

@ -10,11 +10,9 @@ typedef ANIMATION_PROC(animation_proc);
struct animation_block struct animation_block
{ {
// TODO(Peter): Should we change this to frames?? u32 StartFrame;
r32 StartTime; u32 EndFrame;
r32 EndTime;
u32 AnimationProcHandle; u32 AnimationProcHandle;
u32 Layer; u32 Layer;
}; };
@ -24,16 +22,26 @@ struct animation_system
{ {
gs_list<animation_block> Blocks; gs_list<animation_block> Blocks;
r32 Time; // NOTE(Peter): The frame currently being displayed/processed. you
s32 LastUpdatedFrame; // can see which frame you're on by looking at the time slider on the timeline
// panel
u32 CurrentFrame;
u32 LastUpdatedFrame;
r32 SecondsPerFrame; r32 SecondsPerFrame;
b32 TimelineShouldAdvance; b32 TimelineShouldAdvance;
// :Temporary // Timeline
r32 AnimationStart; r32 StartFrame;
r32 AnimationEnd; r32 EndFrame;
}; };
internal u32
SecondsToFrames(r32 Seconds, animation_system System)
{
u32 Result = Seconds * (1.0f / System.SecondsPerFrame);
return Result;
}
#define FOLDHAUS_ANIMATION #define FOLDHAUS_ANIMATION
#endif // FOLDHAUS_ANIMATION #endif // FOLDHAUS_ANIMATION

View File

@ -188,8 +188,8 @@ INITIALIZE_APPLICATION(InitializeApplication)
{ // Animation PLAYGROUND { // Animation PLAYGROUND
State->AnimationSystem = {}; State->AnimationSystem = {};
State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; State->AnimationSystem.SecondsPerFrame = 1.f / 24.f;
State->AnimationSystem.AnimationStart = 0; State->AnimationSystem.StartFrame = 0;
State->AnimationSystem.AnimationEnd = 15; State->AnimationSystem.EndFrame = SecondsToFrames(15, State->AnimationSystem);
} // End Animation Playground } // End Animation Playground
@ -320,14 +320,17 @@ UPDATE_AND_RENDER(UpdateAndRender)
HandleInput(State, State->WindowBounds, InputQueue, Mouse); HandleInput(State, State->WindowBounds, InputQueue, Mouse);
if (State->AnimationSystem.TimelineShouldAdvance) { if (State->AnimationSystem.TimelineShouldAdvance) {
State->AnimationSystem.Time += Context.DeltaTime; // TODO(Peter): Revisit this. This implies that the framerate of the animation system
if (State->AnimationSystem.Time > State->AnimationSystem.AnimationEnd) // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
State->AnimationSystem.CurrentFrame += 1;
// Loop back to the beginning
if (State->AnimationSystem.CurrentFrame > State->AnimationSystem.EndFrame)
{ {
State->AnimationSystem.Time -= State->AnimationSystem.AnimationEnd; State->AnimationSystem.CurrentFrame = 0;
} }
} }
s32 CurrentFrame = (s32)(State->AnimationSystem.Time / State->AnimationSystem.SecondsPerFrame); u32 CurrentFrame = State->AnimationSystem.CurrentFrame;
if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame) if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame)
{ {
State->AnimationSystem.LastUpdatedFrame = CurrentFrame; State->AnimationSystem.LastUpdatedFrame = CurrentFrame;
@ -339,30 +342,31 @@ UPDATE_AND_RENDER(UpdateAndRender)
if (!EntryIsFree(BlockEntry)) if (!EntryIsFree(BlockEntry))
{ {
animation_block Block = BlockEntry->Value; animation_block Block = BlockEntry->Value;
if (State->AnimationSystem.Time >= Block.StartTime if (CurrentFrame >= Block.StartFrame && CurrentFrame <= Block.EndFrame)
&& State->AnimationSystem.Time <= Block.EndTime)
{ {
for (u32 j = 0; j < State->ActiveAssemblyIndecies.Used; j++) for (u32 j = 0; j < State->ActiveAssemblyIndecies.Used; j++)
{ {
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(j); gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(j);
assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle);
u32 FramesIntoBlock = CurrentFrame - Block.StartFrame;
r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame;
// TODO(Peter): Temporary // TODO(Peter): Temporary
switch(Block.AnimationProcHandle) switch(Block.AnimationProcHandle)
{ {
case 1: case 1:
{ {
TestPatternOne(Assembly, FrameTime - Block.StartTime); TestPatternOne(Assembly, SecondsIntoBlock);
}break; }break;
case 2: case 2:
{ {
TestPatternTwo(Assembly, FrameTime - Block.StartTime); TestPatternTwo(Assembly, SecondsIntoBlock);
}break; }break;
case 3: case 3:
{ {
TestPatternThree(Assembly, FrameTime - Block.StartTime); TestPatternThree(Assembly, SecondsIntoBlock);
}break; }break;
// NOTE(Peter): Zero is invalid // NOTE(Peter): Zero is invalid

View File

@ -5,48 +5,41 @@
// //
#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H #ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
inline r32 inline u32
GetTimeFromPointInAnimationPanel(v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) GetFrameFromPointInAnimationPanel(v2 Point, rect PanelBounds, u32 StartFrame, u32 EndFrame)
{ {
r32 StartFrameTime = (r32)StartFrame * SecondsPerFrame; r32 HorizontalPercentOfBounds = (Point.x - PanelBounds.Min.x) / (PanelBounds.Max.x - PanelBounds.Min.x);
r32 EndFrameTime = (r32)EndFrame * SecondsPerFrame; u32 TimeAtPoint = (u32)(HorizontalPercentOfBounds * (EndFrame - StartFrame)) + StartFrame;
r32 TimeAtPoint = GSRemap(Point.x, PanelBounds.Min.x, PanelBounds.Max.x, StartFrameTime, EndFrameTime);
return TimeAtPoint; return TimeAtPoint;
} }
inline s32 inline s32
GetFrameFromPointInAnimationPanel (v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) GetXPositionFromFrameInAnimationPanel (u32 Frame, rect PanelBounds, s32 StartFrame, s32 EndFrame)
{ {
r32 TimeAtPoint = GetTimeFromPointInAnimationPanel(Point, PanelBounds, StartFrame, EndFrame, SecondsPerFrame); r32 PercentOfTimeline = (r32)(Frame - StartFrame) / (r32)(EndFrame - StartFrame);
s32 FrameAtPoint = (s32)(TimeAtPoint * SecondsPerFrame); s32 XPositionAtFrame = (PercentOfTimeline * Width(PanelBounds)) + PanelBounds.Min.x;
return FrameAtPoint; return XPositionAtFrame;
} }
inline s32 internal gs_list_handle
GetXPositionFromTimeInAnimationPanel (r32 Time, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) AddAnimationBlock(u32 StartFrame, u32 EndFrame, u32 AnimationProcHandle, animation_system* AnimationSystem)
{
r32 StartFrameTime = (r32)StartFrame * SecondsPerFrame;
r32 EndFrameTime = (r32)EndFrame * SecondsPerFrame;
s32 XPositionAtTime = GSRemap(Time, StartFrameTime, EndFrameTime, PanelBounds.Min.x, PanelBounds.Max.x);
return XPositionAtTime;
}
internal void
AddAnimationBlock(r32 StartTime, r32 EndTime, u32 AnimationProcHandle, animation_system* AnimationSystem)
{ {
gs_list_handle Result = {0};
animation_block NewBlock = {0}; animation_block NewBlock = {0};
NewBlock.StartTime = StartTime; NewBlock.StartFrame = StartFrame;
NewBlock.EndTime = EndTime; NewBlock.EndFrame = EndFrame;
NewBlock.AnimationProcHandle = AnimationProcHandle; NewBlock.AnimationProcHandle = AnimationProcHandle;
AnimationSystem->Blocks.PushElementOnList(NewBlock); Result = AnimationSystem->Blocks.PushElementOnList(NewBlock);
return Result;
} }
#define NEW_ANIMATION_BLOCK_DURATION 3 internal gs_list_handle
internal void
AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, animation_system* System) AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, animation_system* System)
{ {
r32 CurrentTime = System->Time; u32 NewBlockStart = System->CurrentFrame;
AddAnimationBlock(CurrentTime, CurrentTime + NEW_ANIMATION_BLOCK_DURATION, AnimationProcHandle, System); u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System);
gs_list_handle Result = AddAnimationBlock(NewBlockStart, NewBlockEnd, AnimationProcHandle, System);
return Result;
} }
internal void internal void
@ -70,7 +63,10 @@ DeselectCurrentAnimationBlock(app_state* State)
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
{ {
DeleteAnimationBlock(State->SelectedAnimationBlockHandle, State); if(ListHandleIsValid(State->SelectedAnimationBlockHandle))
{
DeleteAnimationBlock(State->SelectedAnimationBlockHandle, State);
}
} }
// //
@ -87,8 +83,8 @@ OPERATION_STATE_DEF(drag_time_marker_operation_state)
OPERATION_RENDER_PROC(UpdateDragTimeMarker) OPERATION_RENDER_PROC(UpdateDragTimeMarker)
{ {
drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory; drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory;
r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->StartFrame, OpState->EndFrame, State->AnimationSystem.SecondsPerFrame); u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->StartFrame, OpState->EndFrame);
State->AnimationSystem.Time = TimeAtMouseX; State->AnimationSystem.CurrentFrame = FrameAtMouseX;
} }
FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker) FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker)
@ -124,20 +120,20 @@ StartDragTimeMarker(rect TimelineBounds, s32 PanelStartFrame, s32 PanelEndFrame,
OPERATION_STATE_DEF(drag_animation_clip_state) OPERATION_STATE_DEF(drag_animation_clip_state)
{ {
rect TimelineBounds; rect TimelineBounds;
r32 AnimationPanel_StartFrame; s32 AnimationPanel_StartFrame;
r32 AnimationPanel_EndFrame; s32 AnimationPanel_EndFrame;
r32 SelectedClip_InitialStartTime; s32 SelectedClip_InitialStartFrame;
r32 SelectedClip_InitialEndTime; s32 SelectedClip_InitialEndFrame;
}; };
internal r32 internal u32
AttemptToSnapPosition(r32 Snapping, r32 SnapTo) AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame)
{ {
r32 Result = Snapping; u32 Result = SnappingFrame;
r32 SnapDistance = .25f; s32 SnapDistance = 5;
if (GSAbs(Snapping - SnapTo) <= SnapDistance) if (GSAbs((s32)SnappingFrame - (s32)SnapToFrame) <= SnapDistance)
{ {
Result = SnapTo; Result = SnapToFrame;
} }
return Result; return Result;
} }
@ -146,12 +142,13 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip)
{ {
drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory;
s32 ClipInitialStartTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialStartTime, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); u32 ClipInitialStartFrameXPosition = GetXPositionFromFrameInAnimationPanel(OpState->SelectedClip_InitialStartFrame, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame);
s32 ClipInitialEndTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialEndTime, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); u32 ClipInitialEndFrameXPosition = GetXPositionFromFrameInAnimationPanel(OpState->SelectedClip_InitialEndFrame, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame);
r32 TimeAtMouseDownX = GetTimeFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); u32 FrameAtMouseDownX = GetFrameFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame);
r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame);
r32 TimeOffset = TimeAtMouseX - TimeAtMouseDownX; u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame);
s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX;
animation_block* AnimationBlock = State->AnimationSystem.Blocks.GetElementWithHandle(State->SelectedAnimationBlockHandle); animation_block* AnimationBlock = State->AnimationSystem.Blocks.GetElementWithHandle(State->SelectedAnimationBlockHandle);
if (!AnimationBlock) if (!AnimationBlock)
@ -160,83 +157,82 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip)
return; return;
} }
// TODO(Peter): This should really be in pixels so we can zoom in and out on the timeline if (GSAbs(Mouse.DownPos.x - ClipInitialStartFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
r32 SnapDistance = .25f;
if (GSAbs(Mouse.DownPos.x - ClipInitialStartTimeXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{ {
r32 NewStartTime = OpState->SelectedClip_InitialStartTime + TimeOffset; u32 NewStartFrame = OpState->SelectedClip_InitialStartFrame + FrameOffset;
if (TimeOffset < 0) if (FrameOffset < 0)
{ {
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{ {
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; } if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value; animation_block OtherBlock = OtherBlockEntry->Value;
NewStartTime = AttemptToSnapPosition(NewStartTime, OtherBlock.EndTime); NewStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.EndFrame);
} }
} }
else else
{ {
if (NewStartTime >= AnimationBlock->EndTime) if (NewStartFrame >= AnimationBlock->EndFrame)
{ {
NewStartTime = AnimationBlock->EndTime - State->AnimationSystem.SecondsPerFrame; NewStartFrame = AnimationBlock->EndFrame - 1;
} }
} }
AnimationBlock->StartTime = NewStartTime; AnimationBlock->StartFrame = NewStartFrame;
} }
else if (GSAbs(Mouse.DownPos.x - ClipInitialEndTimeXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) else if (GSAbs(Mouse.DownPos.x - ClipInitialEndFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE)
{ {
r32 NewEndTime = OpState->SelectedClip_InitialEndTime + TimeOffset; r32 NewEndFrame = OpState->SelectedClip_InitialEndFrame + FrameOffset;
if (TimeOffset > 0) if (FrameOffset > 0)
{ {
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{ {
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; } if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value; animation_block OtherBlock = OtherBlockEntry->Value;
NewEndTime = AttemptToSnapPosition(NewEndTime, OtherBlock.StartTime); NewEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.StartFrame);
} }
} }
else else
{ {
if(NewEndTime <= AnimationBlock->StartTime) if(NewEndFrame <= AnimationBlock->StartFrame)
{ {
NewEndTime = AnimationBlock->StartTime + State->AnimationSystem.SecondsPerFrame; NewEndFrame = AnimationBlock->StartFrame + 1;
} }
} }
AnimationBlock->EndTime = NewEndTime; AnimationBlock->EndFrame = NewEndFrame;
} }
else else
{ {
r32 NewStartTime = OpState->SelectedClip_InitialStartTime + TimeOffset; u32 NewStartFrame = OpState->SelectedClip_InitialStartFrame + FrameOffset;
r32 NewEndTime = OpState->SelectedClip_InitialEndTime + TimeOffset; u32 NewEndFrame = OpState->SelectedClip_InitialEndFrame + FrameOffset;
for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++)
{ {
gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); gs_list_entry<animation_block>* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i);
if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; } if (OtherBlockEntry->Free.NextFreeEntry != 0) { continue; }
animation_block OtherBlock = OtherBlockEntry->Value; animation_block OtherBlock = OtherBlockEntry->Value;
r32 SnapAmount = 0; u32 SnapFramesAmount = 0;
if (TimeOffset > 0) if (FrameOffset > 0)
{ {
r32 FinalEndTime = AttemptToSnapPosition(NewEndTime, OtherBlock.StartTime); u32 FinalEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.StartFrame);
SnapAmount = FinalEndTime - NewEndTime; SnapFramesAmount = FinalEndFrame - NewEndFrame;
} }
else if (TimeOffset < 0) else if (FrameOffset < 0)
{ {
r32 FinalStartTime = AttemptToSnapPosition(NewStartTime, OtherBlock.EndTime); u32 FinalStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.EndFrame);
SnapAmount = FinalStartTime - NewStartTime; SnapFramesAmount = FinalStartFrame - NewStartFrame;
} }
NewEndTime += SnapAmount; NewEndFrame += SnapFramesAmount;
NewStartTime += SnapAmount; NewStartFrame += SnapFramesAmount;
} }
AnimationBlock->StartTime = NewStartTime; AnimationBlock->StartFrame = NewStartFrame;
AnimationBlock->EndTime = NewEndTime; AnimationBlock->EndFrame = NewEndFrame;
} }
r32 TimelineEndTime = OpState->AnimationPanel_EndFrame * State->AnimationSystem.SecondsPerFrame; s32 VisibleStartFrame = OpState->AnimationPanel_StartFrame;
AnimationBlock->StartTime = GSClamp(0.f, AnimationBlock->StartTime, TimelineEndTime); s32 VisibleEndFrame = OpState->AnimationPanel_EndFrame;
AnimationBlock->EndTime = GSClamp(0.f, AnimationBlock->EndTime, TimelineEndTime); AnimationBlock->StartFrame = (u32)GSClamp(VisibleStartFrame, (s32)AnimationBlock->StartFrame, VisibleEndFrame);
AnimationBlock->EndFrame = (u32)GSClamp(VisibleStartFrame, (s32)AnimationBlock->EndFrame, VisibleEndFrame);
} }
input_command DragAnimationClipCommands [] = { input_command DragAnimationClipCommands [] = {
@ -258,25 +254,16 @@ SelectAndBeginDragAnimationBlock(gs_list_handle BlockHandle, s32 PanelStartFrame
OpState->AnimationPanel_EndFrame = PanelEndFrame ; OpState->AnimationPanel_EndFrame = PanelEndFrame ;
animation_block* SelectedBlock = State->AnimationSystem.Blocks.GetElementWithHandle(BlockHandle); animation_block* SelectedBlock = State->AnimationSystem.Blocks.GetElementWithHandle(BlockHandle);
OpState->SelectedClip_InitialStartTime = SelectedBlock->StartTime; OpState->SelectedClip_InitialStartFrame = SelectedBlock->StartFrame;
OpState->SelectedClip_InitialEndTime = SelectedBlock->EndTime; OpState->SelectedClip_InitialEndFrame = SelectedBlock->EndFrame;
} }
// ------------------- // -------------------
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
{ {
panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds);
r32 MouseDownPositionPercent = (Mouse.Pos.x - ActivePanel.Bounds.Min.x) / Width(ActivePanel.Bounds); u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, State->AnimationSystem.StartFrame, State->AnimationSystem.EndFrame);
r32 NewBlockTimeStart = MouseDownPositionPercent * State->AnimationSystem.AnimationEnd; gs_list_handle NewBlockHandle = AddAnimationBlock(MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, &State->AnimationSystem);
#define NEW_BLOCK_DURATION 1
r32 NewBlockTimeEnd = NewBlockTimeStart + NEW_BLOCK_DURATION;
animation_block Block = {0};
Block.StartTime = NewBlockTimeStart;
Block.EndTime = NewBlockTimeEnd;
Block.AnimationProcHandle = 4;
gs_list_handle NewBlockHandle = State->AnimationSystem.Blocks.PushElementOnList(Block);
SelectAnimationBlock(NewBlockHandle, State); SelectAnimationBlock(NewBlockHandle, State);
} }
@ -343,18 +330,16 @@ DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBu
} }
internal rect internal rect
DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, r32 SecondsPerFrame, s32 FrameCount, s32 StartFrame, rect TimelineBounds, render_command_buffer* RenderBuffer) DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, s32 FrameCount, s32 StartFrame, rect TimelineBounds, render_command_buffer* RenderBuffer)
{ {
rect BlockBounds = {}; rect BlockBounds = {};
r32 TimelineWidth = Width(TimelineBounds); r32 TimelineWidth = Width(TimelineBounds);
s32 BlockStartFrame = AnimationBlock.StartTime / SecondsPerFrame; r32 StartFramePercent = (r32)(AnimationBlock.StartFrame - StartFrame) / (r32)FrameCount;
r32 StartFramePercent = (r32)(BlockStartFrame - StartFrame) / (r32)FrameCount;
r32 StartPosition = TimelineWidth * StartFramePercent; r32 StartPosition = TimelineWidth * StartFramePercent;
s32 BlockEndFrame = AnimationBlock.EndTime / SecondsPerFrame; r32 EndFramePercent = (r32)(AnimationBlock.EndFrame - StartFrame) / (r32)FrameCount;
r32 EndFramePercent = (r32)(BlockEndFrame - StartFrame) / (r32)FrameCount;
r32 EndPosition = TimelineWidth * EndFramePercent; r32 EndPosition = TimelineWidth * EndFramePercent;
BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, 25}; BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, 25};
@ -367,10 +352,10 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, r32 SecondsPe
} }
internal gs_list_handle internal gs_list_handle
DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 EndFrame, rect PanelBounds, gs_list_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse) DrawAnimationTimeline (animation_system* AnimationSystem, s32 VisibleStartFrame, s32 VisibleEndFrame, rect PanelBounds, gs_list_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse)
{ {
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
s32 FrameCount = EndFrame - StartFrame; s32 VisibleFrameCount = VisibleEndFrame - VisibleStartFrame;
gs_list_handle Result = SelectedBlockHandle; gs_list_handle Result = SelectedBlockHandle;
@ -378,11 +363,8 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
r32 AnimationPanelWidth = PanelBounds.Max.x - PanelBounds.Min.x; r32 AnimationPanelWidth = PanelBounds.Max.x - PanelBounds.Min.x;
{ {
s32 FirstPlayableFrame = (AnimationSystem->AnimationStart / AnimationSystem->SecondsPerFrame); r32 FirstPlayablePercentX = ((r32)(AnimationSystem->StartFrame - VisibleStartFrame) / (r32)VisibleFrameCount);
s32 LastPlayableFrame = (AnimationSystem->AnimationEnd / AnimationSystem->SecondsPerFrame); r32 LastPlayablePercentX = ((r32)(AnimationSystem->EndFrame - VisibleStartFrame) / (r32)VisibleFrameCount);
r32 FirstPlayablePercentX = ((r32)(FirstPlayableFrame - StartFrame) / (r32)FrameCount);
r32 LastPlayablePercentX = ((r32)(LastPlayableFrame - StartFrame) / (r32)FrameCount);
v2 PlayableMin = v2{(FirstPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Min.y }; v2 PlayableMin = v2{(FirstPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Min.y };
v2 PlayableMax = v2{(LastPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Max.y }; v2 PlayableMax = v2{(LastPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Max.y };
@ -391,7 +373,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
PushRenderQuad2D(RenderBuffer, PlayableMin, PlayableMax, v4{.22f, .22f, .22f, 1.f}); PushRenderQuad2D(RenderBuffer, PlayableMin, PlayableMax, v4{.22f, .22f, .22f, 1.f});
} }
r32 FrameBarBottom = DrawFrameBar(AnimationSystem, RenderBuffer, StartFrame, EndFrame, PanelBounds, Mouse, State); r32 FrameBarBottom = DrawFrameBar(AnimationSystem, RenderBuffer, VisibleStartFrame, VisibleEndFrame, PanelBounds, Mouse, State);
// Animation Blocks // Animation Blocks
rect TimelineBounds = rect{ PanelBounds.Min, v2{PanelBounds.Max.x, FrameBarBottom} }; rect TimelineBounds = rect{ PanelBounds.Min, v2{PanelBounds.Max.x, FrameBarBottom} };
@ -410,19 +392,18 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
BlockColor = PinkV4; BlockColor = PinkV4;
} }
rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AnimationSystem->SecondsPerFrame, FrameCount, StartFrame, TimelineBounds, RenderBuffer); rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, VisibleFrameCount, VisibleStartFrame, TimelineBounds, RenderBuffer);
if (PointIsInRange(Mouse.Pos, BlockBounds.Min, BlockBounds.Max) if (PointIsInRange(Mouse.Pos, BlockBounds.Min, BlockBounds.Max)
&& MouseButtonTransitionedDown(Mouse.LeftButtonState)) && MouseButtonTransitionedDown(Mouse.LeftButtonState))
{ {
MouseDownAndNotHandled = false; MouseDownAndNotHandled = false;
SelectAndBeginDragAnimationBlock(CurrentBlockHandle, StartFrame, EndFrame, TimelineBounds, State); SelectAndBeginDragAnimationBlock(CurrentBlockHandle, VisibleStartFrame, VisibleEndFrame, TimelineBounds, State);
} }
} }
// Time Slider // Time Slider
s32 SliderFrame = AnimationSystem->Time / AnimationSystem->SecondsPerFrame; r32 TimePercent = (r32)(AnimationSystem->CurrentFrame - VisibleStartFrame) / (r32)VisibleFrameCount;
r32 TimePercent = (r32)(SliderFrame - StartFrame) / (r32)FrameCount;
r32 SliderX = PanelBounds.Min.x + (AnimationPanelWidth * TimePercent); r32 SliderX = PanelBounds.Min.x + (AnimationPanelWidth * TimePercent);
v2 SliderMin = v2{SliderX, PanelBounds.Min.y}; v2 SliderMin = v2{SliderX, PanelBounds.Min.y};
v2 SliderMax = v2{SliderX + 1, PanelBounds.Max.y - 25}; v2 SliderMax = v2{SliderX + 1, PanelBounds.Max.y - 25};
@ -435,7 +416,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
v2 HeadMax = v2{SliderX + SliderHalfWidth, PanelBounds.Max.y}; v2 HeadMax = v2{SliderX + SliderHalfWidth, PanelBounds.Max.y};
PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor); PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
PrintF(&TempString, "%d", SliderFrame); PrintF(&TempString, "%d", AnimationSystem->CurrentFrame);
DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{4, 4}, WhiteV4); DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{4, 4}, WhiteV4);
if (MouseDownAndNotHandled && PointIsInRect(Mouse.Pos, TimelineBounds)) if (MouseDownAndNotHandled && PointIsInRect(Mouse.Pos, TimelineBounds))
@ -518,10 +499,9 @@ AnimationTimeline_Render(panel Panel, rect PanelBounds, render_command_buffer* R
{ {
DrawAnimationClipsList(AnimationClipListBounds, Mouse, RenderBuffer, State); DrawAnimationClipsList(AnimationClipListBounds, Mouse, RenderBuffer, State);
s32 FrameStart = (s32)(State->AnimationSystem.AnimationStart / State->AnimationSystem.SecondsPerFrame);
s32 FrameEnd = (s32)(State->AnimationSystem.AnimationEnd / State->AnimationSystem.SecondsPerFrame);
SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem, SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem,
FrameStart - 20, FrameEnd + 20, State->AnimationSystem.StartFrame - 20,
State->AnimationSystem.EndFrame + 20,
TimelineBounds, TimelineBounds,
SelectedBlockHandle, SelectedBlockHandle,
RenderBuffer, State, Mouse); RenderBuffer, State, Mouse);
@ -564,7 +544,7 @@ AnimationTimeline_Render(panel Panel, rect PanelBounds, render_command_buffer* R
if (StopResult.Pressed) if (StopResult.Pressed)
{ {
State->AnimationSystem.TimelineShouldAdvance = false; State->AnimationSystem.TimelineShouldAdvance = false;
State->AnimationSystem.Time = 0; State->AnimationSystem.CurrentFrame = 0;
} }
} }