fixed some issues with the panel system, and began rearraning the animation timeline window

This commit is contained in:
PS 2020-11-03 12:49:16 -08:00
parent 57f144ea64
commit 723458c491
9 changed files with 301 additions and 94 deletions

View File

@ -26,7 +26,7 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue
State->HotPanel = PanelWithMouseOverIt;
s32 PanelTypeIndex = PanelWithMouseOverIt->TypeIndex;
panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex];
panel_definition PanelDefinition = State->PanelSystem.PanelDefs[PanelTypeIndex];
if (!PanelDefinition.InputCommands) { return; }
ActiveCommands.Commands = PanelDefinition.InputCommands;

View File

@ -245,7 +245,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation)
gs_data PanelStateMemory = Panel->StateMemory;
Panel_SetCurrentType(Panel->Left, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context);
SetAndInitPanelType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context);
Panel_SetType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context);
DeactivateCurrentOperationMode(&State->Modes);
}
@ -396,23 +396,22 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB
{
ButtonBounds.Min,
v2{
ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * GlobalPanelDefsCount)
ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * State->PanelSystem.PanelDefsCount)
},
};
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)
&& !PointIsInRect(MenuBounds, Mouse.DownPos))
if (ui_MouseClickedRect(State->Interface, MenuBounds))
{
Panel->PanelSelectionMenuOpen = false;
}
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{
panel_definition Def = GlobalPanelDefs[i];
panel_definition Def = State->PanelSystem.PanelDefs[i];
gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
if (ui_Button(&State->Interface, DefName, ButtonBounds))
{
SetAndInitPanelType(Panel, &State->PanelSystem, i, State, Context);
Panel_SetType(Panel, &State->PanelSystem, i, State, Context);
Panel->PanelSelectionMenuOpen = false;
}
@ -430,8 +429,9 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB
internal void
RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
{
s32 PanelType = Panel->TypeIndex;
u32 PanelType = Panel->TypeIndex;
Assert(PanelType >= 0);
Assert(PanelType < State->PanelSystem.PanelDefsCount);
rect2 FooterBounds = rect2{
PanelBounds.Min,
@ -442,7 +442,7 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_
PanelBounds.Max,
};
panel_definition Definition = GlobalPanelDefs[PanelType];
panel_definition Definition = State->PanelSystem.PanelDefs[PanelType];
Definition.Render(Panel, PanelViewBounds, RenderBuffer, State, Context);
PushRenderOrthographic(RenderBuffer, WindowBounds);
@ -463,11 +463,12 @@ DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_stat
case PanelSplit_NoSplit:
{
RenderPanel(Panel, Panel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
panel* OverridePanel = Panel_GetModalOverride(Panel);
RenderPanel(OverridePanel, OverridePanel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse);
v4 BorderColor = v4{0, 0, 0, 1};
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
DrawPanelBorder(*Panel, Panel->Bounds.Min, Panel->Bounds.Max, BorderColor, Mouse, RenderBuffer);
DrawPanelBorder(*OverridePanel, OverridePanel->Bounds.Min, OverridePanel->Bounds.Max, BorderColor, Mouse, RenderBuffer);
}break;
InvalidDefaultCase;

View File

@ -84,7 +84,7 @@ struct panel_system
panel_definition* PanelDefs;
u32 PanelDefsCount;
panel Panels[PANELS_MAX];
panel* Panels;
u32 PanelsUsed;
free_panel* FreeList;
@ -97,22 +97,24 @@ struct panel_system
/////////////////////////////////
internal void
InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount)
PanelSystem_Init(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount, gs_memory_arena* Storage)
{
PanelSystem->FreeList = 0;
PanelSystem->PanelDefs = PanelDefs;
PanelSystem->PanelDefsCount = PanelDefsCount;
PanelSystem->Panels = PushArray(Storage, panel, PANELS_MAX);
}
internal panel*
TakeNewPanelEntry(panel_system* PanelSystem)
PanelSystem_TakePanel(panel_system* PanelSystem)
{
panel* FreeEntry = 0;
if (PanelSystem->FreeList != 0)
{
free_panel* FreePanel = PanelSystem->FreeList;
PanelSystem->FreeList = FreePanel->Next;
FreeEntry = (panel*)PanelSystem->FreeList;
FreeEntry = (panel*)FreePanel;
}
else
{
@ -123,7 +125,7 @@ TakeNewPanelEntry(panel_system* PanelSystem)
}
internal void
FreePanelEntry(panel* Panel, panel_system* PanelSystem)
PanelSystem_FreePanel(panel* Panel, panel_system* PanelSystem)
{
Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX);
@ -133,14 +135,14 @@ FreePanelEntry(panel* Panel, panel_system* PanelSystem)
}
internal void
FreePanelEntryRecursive(panel* Panel, panel_system* PanelSystem)
PanelSystem_FreePanelRecursive(panel* Panel, panel_system* PanelSystem)
{
if (Panel->SplitDirection != PanelSplit_NoSplit)
{
FreePanelEntryRecursive(Panel->Left, PanelSystem);
FreePanelEntryRecursive(Panel->Right, PanelSystem);
PanelSystem_FreePanelRecursive(Panel->Left, PanelSystem);
PanelSystem_FreePanelRecursive(Panel->Right, PanelSystem);
}
FreePanelEntry(Panel, PanelSystem);
PanelSystem_FreePanel(Panel, PanelSystem);
}
internal panel*
@ -160,13 +162,14 @@ Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callb
Root->ModalOverride = Override;
Root->ModalOverrideCB = Callback;
Override->IsModalOverrideFor = Root;
Override->Bounds = Root->Bounds;
}
internal void
Panel_PopModalOverride(panel* Parent, panel_system* System)
{
// TODO(pjs): Free the overrided panel
FreePanelEntry(Parent->ModalOverride, System);
PanelSystem_FreePanel(Parent->ModalOverride, System);
Parent->ModalOverride = 0;
}
@ -185,7 +188,7 @@ Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_da
}
internal void
SetAndInitPanelType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context)
Panel_SetType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context)
{
gs_data EmptyStateData = {0};
Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context);
@ -204,8 +207,8 @@ Panel_GetStateMemory(panel* Panel, u64 Size)
internal panel*
PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context)
{
panel* Panel = TakeNewPanelEntry(PanelSystem);
SetAndInitPanelType(Panel, PanelSystem, PanelTypeIndex, State, Context);
panel* Panel = PanelSystem_TakePanel(PanelSystem);
Panel_SetType(Panel, PanelSystem, PanelTypeIndex, State, Context);
return Panel;
}
@ -220,11 +223,11 @@ SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, pan
s32 ParentTypeIndex = Parent->TypeIndex;
gs_data ParentStateMemory = Parent->StateMemory;
Parent->Left = TakeNewPanelEntry(PanelSystem);
Parent->Left = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Left->Parent = Parent;
Parent->Right = TakeNewPanelEntry(PanelSystem);
Parent->Right = PanelSystem_TakePanel(PanelSystem);
Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context);
Parent->Right->Parent = Parent;
}
@ -252,8 +255,8 @@ ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelS
*Parent = *PanelToKeep;
FreePanelEntry(PanelToKeep, PanelSystem);
FreePanelEntryRecursive(PanelToDestroy, PanelSystem);
PanelSystem_FreePanel(PanelToKeep, PanelSystem);
PanelSystem_FreePanelRecursive(PanelToDestroy, PanelSystem);
}
/////////////////////////////////

View File

@ -6,13 +6,13 @@
#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
// Colors
global v4 TimeSliderColor = GreenV4; //v4{.36f, .52f, .78f, 1.f};
global v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f};
//
struct animation_timeline_state
{
frame_range VisibleRange;
handle SelectedAnimationBlockHandle;
handle SelectedBlockHandle;
u32 SelectedAnimationLayer;
};
@ -43,18 +43,6 @@ AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animat
return AnimHandle;
}
internal void
SelectAnimationBlock(handle BlockHandle, app_state* State)
{
State->SelectedAnimationBlockHandle = BlockHandle;
}
internal void
DeselectCurrentAnimationBlock(app_state* State)
{
State->SelectedAnimationBlockHandle = {};
}
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
{
handle SelectedAnimHandle = State->SelectedAnimationBlockHandle;
@ -122,6 +110,7 @@ StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, app_state*
OPERATION_STATE_DEF(drag_animation_clip_state)
{
rect2 TimelineBounds;
handle BlockHandle;
frame_range VisibleRange;
frame_range ClipRange;
};
@ -158,7 +147,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip)
u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange);
s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX;
animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, State->SelectedAnimationBlockHandle);
animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, OpState->BlockHandle);
if (!AnimationBlock)
{
EndCurrentOperationMode(State, {}, Mouse, Context);
@ -242,9 +231,9 @@ input_command DragAnimationClipCommands [] = {
};
internal void
SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State)
SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State)
{
SelectAnimationBlock(BlockHandle, State);
TimelineState->SelectedBlockHandle = BlockHandle;
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip);
@ -253,6 +242,7 @@ SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, r
&State->Modes,
drag_animation_clip_state);
OpState->TimelineBounds = TimelineBounds;
OpState->BlockHandle = BlockHandle;
OpState->VisibleRange = VisibleRange;
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
@ -265,11 +255,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
panel* ActivePanel = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0);
animation_timeline_state* TimelineState = Panel_GetStateStruct(ActivePanel, animation_timeline_state);
frame_range Range = ActiveAnim->PlayableRange;
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range);
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer);
SelectAnimationBlock(NewBlockHandle, State);
TimelineState->SelectedBlockHandle = NewBlockHandle;
}
input_command AnimationTimeline_Commands[] = {
@ -310,6 +301,8 @@ DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_r
r32 BarWidth = Rect2Width(BarBounds);
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
// TODO(pjs): both of these functions can get wrapped in a MouseClickedRect
// and an alternate MouseIsDraggingRect
if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) &&
PointIsInRect(BarBounds, Interface.Mouse.DownPos))
{
@ -484,6 +477,8 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range V
PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor);
PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4);
// TODO(pjs): If mouse is on one of the border hot spots, render an off colored square to signal the region is hot
return BlockBounds;
}
@ -546,7 +541,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta
if (MouseDownAndNotHandled && Handle_IsValid(DragBlockHandle))
{
MouseDownAndNotHandled = false;
SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State);
SelectAndBeginDragAnimationBlock(TimelineState, DragBlockHandle, AdjustedViewRange, TimelineBounds, State);
}
// Time Slider
@ -567,7 +562,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta
if (MouseDownAndNotHandled && PointIsInRect(TimelineBounds, Interface->Mouse.Pos))
{
DeselectCurrentAnimationBlock(State);
TimelineState->SelectedBlockHandle = {0};
}
return Result;
@ -579,6 +574,8 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state);
gs_file_info FileInfo = FileViewState->SelectedFile;
if (FileInfo.Path.Length > 0)
{
gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path);
gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size);
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips);
@ -586,6 +583,7 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
}
}
internal void
DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem)
@ -602,56 +600,234 @@ DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedA
}
}
internal void
PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
animation_system* AnimSystem = &State->AnimationSystem;
ui_interface* Interface = &State->Interface;
ui_layout Layout = ui_CreateLayout(*Interface, Bounds);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_StartRow(&Layout, 4);
{
if (ui_LayoutButton(Interface, &Layout, MakeString("Pause")))
{
AnimSystem->TimelineShouldAdvance = false;
}
if (ui_LayoutButton(Interface, &Layout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4))
{
AnimSystem->TimelineShouldAdvance = true;
}
if (ui_LayoutButton(Interface, &Layout, MakeString("Stop")))
{
AnimSystem->TimelineShouldAdvance = false;
AnimSystem->CurrentFrame = 0;
}
if (ui_LayoutButton(Interface, &Layout, MakeString("Load")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
}
}
ui_EndRow(&Layout);
}
internal void
FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
gs_string TempString = PushString(State->Transient, 256);
frame_range VisibleFrames = TimelineState->VisibleRange;
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
// Frame Ticks
u32 TickCount = 10;
for (u32 Tick = 0; Tick < TickCount; Tick++)
{
r32 Percent = (r32)Tick / (r32)TickCount;
u32 Frame = PercentToFrameInRange(Percent, VisibleFrames);
PrintF(&TempString, "%d", Frame);
r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames);
r32 FrameX = LerpR32(FramePercent, Bounds.Min.x, Bounds.Max.x);
v2 FrameTextPos = v2{FrameX, Bounds.Min.y + 2};
DrawString(Interface->RenderBuffer, TempString, Interface->Style.Font, FrameTextPos, WhiteV4);
}
// Time Slider
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
if (FrameIsInRange(VisibleFrames, CurrentFrame))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(CurrentFrame, VisibleFrames);
r32 SliderX = LerpR32(FrameAtPercentVisibleRange, Bounds.Min.x, Bounds.Max.x);
PrintF(&TempString, "%d", CurrentFrame);
// space for each character + a margin on either side
r32 SliderWidth = (8 * TempString.Length) + 8;
r32 SliderHalfWidth = SliderWidth / 2.f;
v2 HeadMin = v2{SliderX - SliderHalfWidth, Bounds.Min.y};
v2 HeadMax = v2{SliderX + SliderHalfWidth, Bounds.Max.y};
PushRenderQuad2D(Interface->RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
DrawString(Interface->RenderBuffer, TempString, Interface->Style.Font, HeadMin + v2{6, 4}, WhiteV4);
}
// Interaction
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
if (ui_MouseClickedRect(*Interface, Bounds))
{
StartDragTimeMarker(Bounds, VisibleFrames, State);
}
}
internal void
LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
v2 LayerDim = { Rect2Width(Bounds), LAYER_HEIGHT };
rect2 LayerBounds = {0};
LayerBounds.Min = Bounds.Min;
LayerBounds.Max = LayerBounds.Min + LayerDim;
for (u32 i = 0; i < ActiveAnim.Layers.Count; i++)
{
anim_layer* Layer = ActiveAnim.Layers.Values + i;
if (ui_MouseClickedRect(*Interface, LayerBounds))
{
TimelineState->SelectedAnimationLayer = i;
}
v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16};
if (TimelineState->SelectedAnimationLayer == i)
{
PushRenderBoundingBox2D(Interface->RenderBuffer, LayerBounds.Min, LayerBounds.Max, 1, WhiteV4);
}
DrawString(Interface->RenderBuffer, Layer->Name, Interface->Style.Font, LayerTextPos, WhiteV4);
LayerBounds = Rect2TranslateY(LayerBounds, LayerDim.y);
}
}
internal void
TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_interface* Interface = &State->Interface;
frame_range ViewRange = TimelineState->VisibleRange;
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
handle SelectedBlockHandle = TimelineState->SelectedBlockHandle;
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
// Animation Blocks
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
handle DragBlockHandle = {0};
for (u32 i = 0; i < ActiveAnim.Blocks_.Count; i++)
{
animation_block* AnimationBlockAt = ActiveAnim.Blocks_.Values + i;
// If either end is in the range, we should draw it
b32 RangeIsVisible = (FrameIsInRange(ViewRange, AnimationBlockAt->Range.Min) ||
FrameIsInRange(ViewRange, AnimationBlockAt->Range.Max));
// If neither end is in the range, but the ends surround the visible range,
// we should still draw it.
RangeIsVisible |= (AnimationBlockAt->Range.Min <= ViewRange.Min &&
AnimationBlockAt->Range.Max>= ViewRange.Max);
if (RangeIsVisible)
{
v4 BlockColor = BlackV4;
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == ActiveAnim.Blocks_.Generations[i])
{
BlockColor = PinkV4;
}
rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, ViewRange, Bounds, Interface->RenderBuffer);
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
{
DragBlockHandle.Index = i;
DragBlockHandle.Generation = ActiveAnim.Blocks_.Generations[i];
}
}
}
// Time Slider
if (FrameIsInRange(ViewRange, CurrentFrame))
{
r32 FrameAtPercentVisibleRange = FrameToPercentRange(CurrentFrame, ViewRange);
r32 SliderX = LerpR32(FrameAtPercentVisibleRange, Bounds.Min.x, Bounds.Max.x);
rect2 SliderBounds = {
v2{ SliderX, Bounds.Min.y },
v2{ SliderX + 1, Bounds.Max.y }
};
ui_FillRect(Interface, SliderBounds, TimeSliderColor);
}
// Interaction
if (MouseDownAndNotHandled)
{
if (Handle_IsValid(DragBlockHandle))
{
MouseDownAndNotHandled = false;
SelectAndBeginDragAnimationBlock(TimelineState, DragBlockHandle, ViewRange, Bounds, State);
}
else if (PointIsInRect(Bounds, Interface->Mouse.Pos))
{
TimelineState->SelectedBlockHandle = {0};
}
}
}
internal void
AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_FillRect(&State->Interface, Bounds, PinkV4);
}
internal void
SelectionInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
ui_FillRect(&State->Interface, Bounds, YellowV4);
}
GSMetaTag(panel_render);
GSMetaTag(panel_type_animation_timeline);
internal void
AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
// TODO(pjs): SelectedAnimationBlockHandle should be a property of animation_timeline_state
// unless its used elsewhere. Audit later
handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
ui_interface* Interface = &State->Interface;
animation_system* AnimationSystem = &State->AnimationSystem;
rect2 TitleBarBounds, PanelContentsBounds;
rect2 AnimationListBounds, TimelineBounds;
RectHSplitAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds);
RectVSplitAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds);
rect2 TimelineBounds, InfoBounds;
RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds);
ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]);
ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds);
ui_StartRow(&TitleBarLayout, 4);
{
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Pause")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
rect2 AnimInfoBounds, SelectionInfoBounds;
RectHSplitAtPercent(InfoBounds, .35f, &AnimInfoBounds, &SelectionInfoBounds);
{ // Timeline
rect2 LayersPanelBounds, TimeRangePanelBounds;
RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds);
r32 TitleBarHeight = State->Interface.Style.RowHeight;
// These are the actual rects we will draw in
rect2 PlayBarBounds, FrameCountBounds;
rect2 LayersBounds, TimeRangeBounds;
RectHSplitAtDistanceFromTop(LayersPanelBounds, TitleBarHeight, &PlayBarBounds, &LayersBounds);
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
LayerList_Render(TimelineState, LayersBounds, RenderBuffer, State, Context);
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4))
{
State->AnimationSystem.TimelineShouldAdvance = true;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Stop")))
{
State->AnimationSystem.TimelineShouldAdvance = false;
State->AnimationSystem.CurrentFrame = 0;
}
if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load")))
{
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
}
}
ui_EndRow(&TitleBarLayout);
if (Rect2Height(TimelineBounds) > 0)
{
SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State);
DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem);
}
AnimInfoView_Render(TimelineState, AnimInfoBounds, RenderBuffer, State, Context);
SelectionInfoView_Render(TimelineState, SelectionInfoBounds, RenderBuffer, State, Context);
}
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H

View File

@ -15,6 +15,8 @@ RELOAD_STATIC_DATA(ReloadStaticData)
app_state* State = (app_state*)Context.MemoryBase;
GlobalDebugServices = DebugServices;
State->PanelSystem.PanelDefs = GlobalPanelDefs;
State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount;
}
INITIALIZE_APPLICATION(InitializeApplication)
@ -158,7 +160,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
} // End Animation Playground
InitializePanelSystem(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount);
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
}

View File

@ -148,7 +148,7 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint);
// Worker Threads
#define PLATFORM_THREAD_COUNT 4
#define PLATFORM_THREAD_COUNT 0
RESET_WORK_QUEUE(ResetWorkQueue)
{

View File

@ -340,6 +340,18 @@ ui_LayoutRemaining(ui_layout Layout)
return Result;
}
//
// Interaction
//
internal b32
ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
{
b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState);
Result &= PointIsInRect(Rect, Interface.Mouse.Pos);
return Result;
}
//
// Drawing Functions
//

View File

@ -855,6 +855,7 @@ RectHSplit(rect2 Rect, r32 YValue, rect2* Top, rect2* Bottom)
Bottom->Max = { Rect.Max.x, ClampedYValue };
Bottom->Min = Rect.Min;
}
internal void
RectVSplit(rect2 Rect, r32 XValue, rect2* Left, rect2* Right)
{

View File

@ -1,5 +1,17 @@
TODO FOLDHAUS
- engine environment
- primary color
- default controller
- gets its own update function
- has access to the engine state
- can select animations
- change playback speed, primary color
- user space controller
- socket listener
STREAM #1: 3D Overhaul
- Rendering (Working on this elsewhere)
- OpenGL 3