fixed some issues with the panel system, and began rearraning the animation timeline window
This commit is contained in:
parent
57f144ea64
commit
723458c491
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
12
src/todo.txt
12
src/todo.txt
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue