diff --git a/src/animation/foldhaus_animation.h b/src/animation/foldhaus_animation.h index 2967b2c..73aedeb 100644 --- a/src/animation/foldhaus_animation.h +++ b/src/animation/foldhaus_animation.h @@ -39,8 +39,12 @@ struct animation_system free_list FreeList; u32 BlocksCount; -r32 Time; - b32 TimelineShouldAdvance; + r32 Time; + s32 LastUpdatedFrame; + r32 SecondsPerFrame; + +b32 TimelineShouldAdvance; + // :Temporary r32 AnimationEnd; }; diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index 55eb6a2..8148b2c 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -275,6 +275,7 @@ INITIALIZE_APPLICATION(InitializeApplication) { // MODES PLAYGROUND InitializeAnimationSystem(&State->AnimationSystem); + State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; animation_block BlockZero = {0}; BlockZero.StartTime = 0; @@ -415,7 +416,14 @@ UPDATE_AND_RENDER(UpdateAndRender) { State->AnimationSystem.Time -= State->AnimationSystem.AnimationEnd; } - + } + +s32 CurrentFrame = (s32)(State->AnimationSystem.Time / State->AnimationSystem.SecondsPerFrame); + if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame) + { + State->AnimationSystem.LastUpdatedFrame = CurrentFrame; + r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame; + for (u32 i = 0; i < State->AnimationSystem.BlocksCount; i++) { animation_block_entry BlockEntry = State->AnimationSystem.Blocks[i]; @@ -425,11 +433,11 @@ UPDATE_AND_RENDER(UpdateAndRender) if (State->AnimationSystem.Time >= Block.StartTime && State->AnimationSystem.Time <= Block.EndTime) { - Block.Proc(State, State->AnimationSystem.Time - Block.StartTime); + Block.Proc(State, FrameTime - Block.StartTime); } } + } } - } s32 HeaderSize = State->NetworkProtocolHeaderSize; dmx_buffer_list* DMXBuffers = 0; diff --git a/src/gs_input.h b/src/gs_input.h index d77d12a..30bebb5 100644 --- a/src/gs_input.h +++ b/src/gs_input.h @@ -105,5 +105,7 @@ MouseButtonTransitionedUp (b32 MouseButtonState) internal b32 MouseButtonHeldDown (b32 MouseButtonState) { - return (KeyWasDown(MouseButtonState) && KeyIsDown(MouseButtonState)); + b32 WasDown = KeyWasDown(MouseButtonState); + b32 IsDown = KeyIsDown(MouseButtonState); + return (WasDown && IsDown); } \ No newline at end of file diff --git a/src/interface.h b/src/interface.h index 32acbae..e3631aa 100644 --- a/src/interface.h +++ b/src/interface.h @@ -8,12 +8,14 @@ enum string_alignment internal void DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, v4 Color) { - r32 MaxX = MinX + (CodepointInfo.Width); - r32 MaxY = MinY + (CodepointInfo.Height); + s32 AlignedMinX = (s32)(MinX); + s32 AlignedMinY = (s32)(MinY); +s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); + s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); PushQuad2DOnBatch(BatchConstructor, - v2{MinX, MinY}, v2{MaxX, MinY}, - v2{MaxX, MaxY}, v2{MinX, MaxY}, + v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, + v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, CodepointInfo.UVMin, CodepointInfo.UVMax, Color); } diff --git a/src/panels/foldhaus_panel_animation_timeline.h b/src/panels/foldhaus_panel_animation_timeline.h index 45957aa..829e1a6 100644 --- a/src/panels/foldhaus_panel_animation_timeline.h +++ b/src/panels/foldhaus_panel_animation_timeline.h @@ -18,36 +18,75 @@ PANEL_CLEANUP_PROC(AnimationTimeline_Cleanup) } internal animation_block_handle -DrawAnimationTimeline (animation_system* AnimationSystem, v2 PanelMin, v2 PanelMax, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse) +DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 EndFrame, v2 PanelMin, v2 PanelMax, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse) { + string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); +s32 FrameCount = EndFrame - StartFrame; + animation_block_handle Result = SelectedBlockHandle; -r32 AnimationPanelHeight = PanelMax.y - PanelMin.y; - r32 AnimationPanelWidth = PanelMax.x - PanelMin.x; - panel_result AnimationPanel = EvaluatePanel(RenderBuffer, PanelMin, PanelMax, - 0, Interface); + r32 AnimationPanelHeight = PanelMax.y - PanelMin.y; + r32 AnimationPanelWidth = PanelMax.x - PanelMin.x; + PushRenderQuad2D(RenderBuffer, PanelMin, PanelMax, v4{.22f, .22f, .22f, 1.f}); + // Frame Bar + r32 FrameBarHeight = 24; + v2 FrameBarMin = v2{PanelMin.x, PanelMax.y - FrameBarHeight}; + v2 FrameBarMax = PanelMax; + PushRenderQuad2D(RenderBuffer, FrameBarMin, FrameBarMax, v4{.16f, .16f, .16f, 1.f}); + +// Mouse clicked inside frame nubmer bar -> change current frame on timeline + if (MouseButtonHeldDown(Mouse.LeftButtonState) + && PointIsInRange(Mouse.DownPos, FrameBarMin, FrameBarMax)) + { + r32 MouseX = Mouse.DownPos.x; + r32 MousePercentX = (MouseX - FrameBarMin.x) / (FrameBarMax.x - FrameBarMin.y); + s32 MouseFrame = (s32)((MousePercentX * FrameCount) + StartFrame); + r32 MouseFrameTime = (r32)MouseFrame * AnimationSystem->SecondsPerFrame; + AnimationSystem->Time = MouseFrameTime; + } + + for (s32 f = 0; f < FrameCount; f += 10) + { + s32 Frame = StartFrame + f; + PrintF(&TempString, "%d", Frame); + + r32 FramePercent = (r32)f / (r32)FrameCount; + r32 FrameX = GSLerp(PanelMin.x, PanelMax.x, FramePercent); + v2 FrameTextPos = v2{FrameX, FrameBarMin.y + 2}; + DrawString(RenderBuffer, TempString, State->Interface.Font, FrameTextPos, WhiteV4); + + // Frame Vertical Slices + v2 LineTop = v2{FrameX, FrameBarMin.y}; + v2 LineBottom = v2{FrameX + 1, PanelMin.y}; + PushRenderQuad2D(RenderBuffer, LineTop, LineBottom, v4{.16f, .16f, .16f, 1.f}); + } + + // Animation Blocks + v2 TimelineMin = PanelMin; + v2 TimelineMax = v2{PanelMax.x, FrameBarMin.y}; b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState); - - for (u32 i = 0; i < AnimationSystem->BlocksCount; i++) - { - animation_block_entry AnimationBlockEntry = AnimationSystem->Blocks[i]; - if (AnimationBlockIsFree(AnimationBlockEntry)) { continue; } +for (u32 i = 0; i < AnimationSystem->BlocksCount; i++) + { + animation_block_entry AnimationBlockEntry = AnimationSystem->Blocks[i]; + if (AnimationBlockIsFree(AnimationBlockEntry)) { continue; } animation_block_handle CurrentBlockHandle = {}; CurrentBlockHandle.Index = i; CurrentBlockHandle.Generation = AnimationBlockEntry.Generation; - animation_block AnimationBlockAt = AnimationBlockEntry.Block; - -r32 StartTimePercent = AnimationBlockAt.StartTime / AnimationSystem->AnimationEnd; - r32 StartPosition = AnimationPanelWidth * StartTimePercent; - -r32 EndTimePercent = AnimationBlockAt.EndTime / AnimationSystem->AnimationEnd; - r32 EndPosition = AnimationPanelWidth * EndTimePercent; - - v2 Min = PanelMin + v2{StartPosition, 25}; - v2 Max = PanelMin + v2{EndPosition, 75}; + animation_block AnimationBlockAt = AnimationBlockEntry.Block; + + s32 BlockStartFrame = AnimationBlockAt.StartTime / AnimationSystem->SecondsPerFrame; + r32 StartFramePercent = (r32)(BlockStartFrame - StartFrame) / (r32)FrameCount; + r32 StartPosition = AnimationPanelWidth * StartFramePercent; + + s32 BlockEndFrame = AnimationBlockAt.EndTime / AnimationSystem->SecondsPerFrame; + r32 EndFramePercent = (r32)(BlockEndFrame - StartFrame) / (r32)FrameCount; + r32 EndPosition = AnimationPanelWidth * EndFramePercent; + + v2 Min = TimelineMin + v2{StartPosition, 25}; + v2 Max = TimelineMin + v2{EndPosition, 75}; v4 BlockColor = BlackV4; if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle)) @@ -55,32 +94,44 @@ r32 EndTimePercent = AnimationBlockAt.EndTime / AnimationSystem->AnimationEnd; BlockColor = PinkV4; } - PushRenderQuad2D(RenderBuffer, Min, Max, BlockColor); + PushRenderQuad2D(RenderBuffer, Min, Max, BlockColor); PushRenderBoundingBox2D(RenderBuffer, Min, Max, 1, WhiteV4); if (PointIsInRange(Mouse.Pos, Min, Max) && MouseButtonTransitionedDown(Mouse.LeftButtonState)) { MouseDownAndNotHandled = false; -if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle)) + if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle)) { -// If the block is already selected, deselect it. + // If the block is already selected, deselect it. Result = {0}; } else { -Result = CurrentBlockHandle; + Result = CurrentBlockHandle; } } - } + } - r32 TimePercent = AnimationSystem->Time / AnimationSystem->AnimationEnd; + // Time Slider +s32 SliderFrame = AnimationSystem->Time / AnimationSystem->SecondsPerFrame; + r32 TimePercent = (r32)SliderFrame / (r32)EndFrame; r32 SliderX = PanelMin.x + (AnimationPanelWidth * TimePercent); v2 SliderMin = v2{SliderX, PanelMin.y}; v2 SliderMax = v2{SliderX + 1, PanelMax.y - 25}; - PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, WhiteV4); + v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f}; - if (MouseDownAndNotHandled && PointIsInRange(Mouse.Pos, PanelMin, PanelMax)) + PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, TimeSliderColor); + + r32 SliderHalfWidth = 10; + v2 HeadMin = v2{SliderX - SliderHalfWidth, SliderMax.y}; + v2 HeadMax = v2{SliderX + SliderHalfWidth, SliderMax.y + FrameBarHeight}; + PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor); + + PrintF(&TempString, "%d", SliderFrame); + DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{4, 4}, WhiteV4); + + if (MouseDownAndNotHandled && PointIsInRange(Mouse.Pos, TimelineMin, TimelineMax)) { r32 MouseDownPositionPercent = (Mouse.Pos.x - PanelMin.x) / AnimationPanelWidth; r32 NewBlockTimeStart = MouseDownPositionPercent * AnimationSystem->AnimationEnd; @@ -96,21 +147,23 @@ Result = CurrentBlockHandle; Result = NewBlockHandle; } return Result; - } +} PANEL_RENDER_PROC(AnimationTimeline_Render) { animation_block_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; -r32 OptionsRowHeight = 25; + r32 OptionsRowHeight = 25; v2 TimelineMin = PanelMin; v2 TimelineMax = v2{PanelMax.x, PanelMax.y - OptionsRowHeight}; if (TimelineMax.y - TimelineMin.y > 0) { + s32 FrameEnd = (s32)(State->AnimationSystem.AnimationEnd / State->AnimationSystem.SecondsPerFrame); SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem, -TimelineMin, TimelineMax, - SelectedBlockHandle, - RenderBuffer, State->Interface, Mouse); + 0, FrameEnd, + TimelineMin, TimelineMax, + SelectedBlockHandle, + RenderBuffer, State, Mouse); } v2 OptionsRowMin = v2{ PanelMin.x, TimelineMax.y }; @@ -128,14 +181,14 @@ TimelineMin, TimelineMax, MakeStringLiteral("Pause"), State->Interface, Mouse); ButtonAt.x += ButtonWidth + 2; -button_result PlayResult = EvaluateButton(RenderBuffer, - ButtonAt + ButtonMin, ButtonAt + ButtonMax, - MakeStringLiteral("Play"), + button_result PlayResult = EvaluateButton(RenderBuffer, + ButtonAt + ButtonMin, ButtonAt + ButtonMax, + MakeStringLiteral("Play"), State->Interface, Mouse); ButtonAt.x += ButtonWidth + 2; -button_result StopResult = EvaluateButton(RenderBuffer, - ButtonAt + ButtonMin, ButtonAt + ButtonMax, - MakeStringLiteral("Stop"), + button_result StopResult = EvaluateButton(RenderBuffer, + ButtonAt + ButtonMin, ButtonAt + ButtonMax, + MakeStringLiteral("Stop"), State->Interface, Mouse); if (PauseResult.Pressed) @@ -153,6 +206,6 @@ button_result StopResult = EvaluateButton(RenderBuffer, State->AnimationSystem.TimelineShouldAdvance = false; State->AnimationSystem.Time = 0; } - -State->SelectedAnimationBlockHandle = SelectedBlockHandle; + + State->SelectedAnimationBlockHandle = SelectedBlockHandle; } diff --git a/src/panels/foldhaus_panel_hierarchy.h b/src/panels/foldhaus_panel_hierarchy.h index 4adc49b..db23770 100644 --- a/src/panels/foldhaus_panel_hierarchy.h +++ b/src/panels/foldhaus_panel_hierarchy.h @@ -21,7 +21,7 @@ v4 LineBGColors[] = { v4 LineBGHoverColor = { .22f, .22f, .22f, 1.f }; r32 LineHeight = State->Interface.Font->PixelHeight + 8; - v2 LineMin = v2{PanelMin.x + State->Interface.Margin.x, PanelMax.y - LineHeight}; + v2 LineMin = v2{PanelMin.x, PanelMax.y - LineHeight}; v2 LineMax = LineMin + v2{PanelWidth, LineHeight}; v2 TextOffset = v2{10, 4}; string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);