Implemented Crossfading between animations
This commit is contained in:
parent
8a4958938d
commit
59cb48c9f0
|
@ -144,7 +144,7 @@ BlumenLumen_CustomInit(app_state* State, context Context)
|
||||||
|
|
||||||
Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(15), 0);
|
Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(15), 0);
|
||||||
|
|
||||||
AnimationArray_Push(&State->AnimationSystem.Animations, Anim0);
|
BLState->AnimHandles[0] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim0);
|
||||||
|
|
||||||
animation Anim1 = {0};
|
animation Anim1 = {0};
|
||||||
Anim1.Name = PushStringF(&State->Permanent, 256, "test_anim_one");
|
Anim1.Name = PushStringF(&State->Permanent, 256, "test_anim_one");
|
||||||
|
@ -156,7 +156,7 @@ BlumenLumen_CustomInit(app_state* State, context Context)
|
||||||
|
|
||||||
Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(12), 0);
|
Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(12), 0);
|
||||||
|
|
||||||
AnimationArray_Push(&State->AnimationSystem.Animations, Anim1);
|
BLState->AnimHandles[1] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim1);
|
||||||
|
|
||||||
animation Anim2 = {0};
|
animation Anim2 = {0};
|
||||||
Anim2.Name = PushStringF(&State->Permanent, 256, "i_love_you");
|
Anim2.Name = PushStringF(&State->Permanent, 256, "i_love_you");
|
||||||
|
@ -166,10 +166,12 @@ BlumenLumen_CustomInit(app_state* State, context Context)
|
||||||
Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
|
Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem);
|
||||||
Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
|
Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem);
|
||||||
|
|
||||||
Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0);
|
Animation_AddBlock(&Anim2, 0, 100, Patterns_IndexToHandle(5), 0);
|
||||||
|
Animation_AddBlock(&Anim2, 50, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0);
|
||||||
|
|
||||||
AnimationArray_Push(&State->AnimationSystem.Animations, Anim2);
|
BLState->AnimHandles[2] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim2);
|
||||||
|
|
||||||
|
State->AnimationSystem.ActiveFadeGroup.From = BLState->AnimHandles[2];
|
||||||
State->AnimationSystem.TimelineShouldAdvance = true;
|
State->AnimationSystem.TimelineShouldAdvance = true;
|
||||||
} // End Animation Playground
|
} // End Animation Playground
|
||||||
|
|
||||||
|
@ -189,6 +191,15 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
|
||||||
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory;
|
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory;
|
||||||
|
|
||||||
MotorTimeElapsed += Context->DeltaTime;
|
MotorTimeElapsed += Context->DeltaTime;
|
||||||
|
BLState->TimeElapsed += Context->DeltaTime;
|
||||||
|
|
||||||
|
if (BLState->TimeElapsed > 5)
|
||||||
|
{
|
||||||
|
u32 NextIndex = ++BLState->CurrAnim % 3;
|
||||||
|
animation_handle Next = BLState->AnimHandles[NextIndex];
|
||||||
|
AnimationFadeGroup_FadeTo(&State->AnimationSystem.ActiveFadeGroup, Next, 5);
|
||||||
|
BLState->TimeElapsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
gs_string BlueString = MakeString("blue");
|
gs_string BlueString = MakeString("blue");
|
||||||
gs_string GreenString = MakeString("green");
|
gs_string GreenString = MakeString("green");
|
||||||
|
@ -207,15 +218,15 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
|
||||||
u32 NameLen = CStringLength(Packet.AnimationFileName);
|
u32 NameLen = CStringLength(Packet.AnimationFileName);
|
||||||
if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen))
|
if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen))
|
||||||
{
|
{
|
||||||
State->AnimationSystem.ActiveAnimationIndex = 0;
|
State->AnimationSystem.ActiveFadeGroup.From.Index = 0;
|
||||||
}
|
}
|
||||||
else if (StringEqualsCharArray(GreenString.ConstString, Packet.AnimationFileName, NameLen))
|
else if (StringEqualsCharArray(GreenString.ConstString, Packet.AnimationFileName, NameLen))
|
||||||
{
|
{
|
||||||
State->AnimationSystem.ActiveAnimationIndex = 1;
|
State->AnimationSystem.ActiveFadeGroup.From.Index = 1;
|
||||||
}
|
}
|
||||||
else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen))
|
else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen))
|
||||||
{
|
{
|
||||||
State->AnimationSystem.ActiveAnimationIndex = 2;
|
State->AnimationSystem.ActiveFadeGroup.From.Index = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputDebugStringA("Received Pattern Packet\n");
|
OutputDebugStringA("Received Pattern Packet\n");
|
||||||
|
|
|
@ -70,6 +70,11 @@ struct blumen_lumen_state
|
||||||
mic_listen_job_data MicListenJobData;
|
mic_listen_job_data MicListenJobData;
|
||||||
|
|
||||||
motor_packet LastKnownMotorState;
|
motor_packet LastKnownMotorState;
|
||||||
|
|
||||||
|
r64 TimeElapsed;
|
||||||
|
|
||||||
|
animation_handle AnimHandles[3];
|
||||||
|
u32 CurrAnim;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct animation_timeline_state
|
||||||
{
|
{
|
||||||
frame_range VisibleRange;
|
frame_range VisibleRange;
|
||||||
handle SelectedBlockHandle;
|
handle SelectedBlockHandle;
|
||||||
|
animation_handle EditingAnimationHandle;
|
||||||
u32 SelectedAnimationLayer;
|
u32 SelectedAnimationLayer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,22 +34,13 @@ GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range
|
||||||
return XPositionAtFrame;
|
return XPositionAtFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal handle
|
|
||||||
AddAnimationBlockAtCurrentTime (animation_pattern_handle AnimationProcHandle, u32 LayerHandle, animation_system* System)
|
|
||||||
{
|
|
||||||
u32 NewBlockStart = System->CurrentFrame;
|
|
||||||
u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System);
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
|
||||||
handle AnimHandle = Animation_AddBlock(ActiveAnim, NewBlockStart, NewBlockEnd, AnimationProcHandle, LayerHandle);
|
|
||||||
return AnimHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
|
FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
|
||||||
{
|
{
|
||||||
animation_timeline_state* PanelState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
animation_timeline_state* PanelState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
||||||
|
|
||||||
handle SelectedBlockHandle = PanelState->SelectedBlockHandle;
|
handle SelectedBlockHandle = PanelState->SelectedBlockHandle;
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
animation* ActiveAnim = AnimationArray_GetSafe(State->AnimationSystem.Animations, PanelState->EditingAnimationHandle);
|
||||||
|
|
||||||
if(SelectedBlockHandle.Index < ActiveAnim->Blocks_.Count &&
|
if(SelectedBlockHandle.Index < ActiveAnim->Blocks_.Count &&
|
||||||
ActiveAnim->Blocks_.Generations[SelectedBlockHandle.Index] == SelectedBlockHandle.Generation)
|
ActiveAnim->Blocks_.Generations[SelectedBlockHandle.Index] == SelectedBlockHandle.Generation)
|
||||||
{
|
{
|
||||||
|
@ -112,6 +104,7 @@ StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, app_state*
|
||||||
OPERATION_STATE_DEF(drag_animation_block_state)
|
OPERATION_STATE_DEF(drag_animation_block_state)
|
||||||
{
|
{
|
||||||
rect2 TimelineBounds;
|
rect2 TimelineBounds;
|
||||||
|
animation_handle EditingAnimationHandle;
|
||||||
handle BlockHandle;
|
handle BlockHandle;
|
||||||
frame_range VisibleRange;
|
frame_range VisibleRange;
|
||||||
frame_range ClipRange;
|
frame_range ClipRange;
|
||||||
|
@ -133,7 +126,9 @@ OPERATION_RENDER_PROC(UpdateDragAnimationBlock)
|
||||||
{
|
{
|
||||||
drag_animation_block_state* OpState = (drag_animation_block_state*)Operation.OpStateMemory;
|
drag_animation_block_state* OpState = (drag_animation_block_state*)Operation.OpStateMemory;
|
||||||
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
animation_array Animations = State->AnimationSystem.Animations;
|
||||||
|
animation_handle Handle = OpState->EditingAnimationHandle;
|
||||||
|
animation* ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||||
|
|
||||||
r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange);
|
r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange);
|
||||||
u32 ClipInitialStartFrameXPosition = LerpR32(ClipInitialStartFrameXPercent,
|
u32 ClipInitialStartFrameXPosition = LerpR32(ClipInitialStartFrameXPercent,
|
||||||
|
@ -237,7 +232,10 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
|
||||||
{
|
{
|
||||||
TimelineState->SelectedBlockHandle = BlockHandle;
|
TimelineState->SelectedBlockHandle = BlockHandle;
|
||||||
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
animation_handle Handle = TimelineState->EditingAnimationHandle;
|
||||||
|
animation_array Animations = State->AnimationSystem.Animations;
|
||||||
|
animation* ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||||
|
|
||||||
operation_mode* DragAnimationBlockMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationBlockCommands, UpdateDragAnimationBlock);
|
operation_mode* DragAnimationBlockMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationBlockCommands, UpdateDragAnimationBlock);
|
||||||
|
|
||||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
|
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
|
||||||
|
@ -245,29 +243,39 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
|
||||||
&State->Modes,
|
&State->Modes,
|
||||||
drag_animation_block_state);
|
drag_animation_block_state);
|
||||||
OpState->TimelineBounds = TimelineBounds;
|
OpState->TimelineBounds = TimelineBounds;
|
||||||
|
OpState->EditingAnimationHandle = Handle;
|
||||||
OpState->BlockHandle = BlockHandle;
|
OpState->BlockHandle = BlockHandle;
|
||||||
OpState->VisibleRange = VisibleRange;
|
OpState->VisibleRange = VisibleRange;
|
||||||
OpState->ClipRange = SelectedBlock->Range;
|
OpState->ClipRange = SelectedBlock->Range;
|
||||||
}
|
}
|
||||||
// -------------------
|
// -------------------
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
|
internal void
|
||||||
|
AnimationTimeline_AddAnimationBlockCommand(animation_timeline_state* TimelineState, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
animation_handle Handle = TimelineState->EditingAnimationHandle;
|
||||||
|
animation_array Animations = State->AnimationSystem.Animations;
|
||||||
|
animation* ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||||
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
s32 StartFrame = State->AnimationSystem.CurrentFrame;
|
||||||
|
s32 EndFrame = StartFrame + SecondsToFrames(3, State->AnimationSystem);
|
||||||
|
EndFrame = Clamp(0, EndFrame, ActiveAnim->PlayableRange.Max);
|
||||||
|
if ((EndFrame - StartFrame) > 0)
|
||||||
|
{
|
||||||
|
animation_pattern_handle PatternHandle = Patterns_IndexToHandle(0);
|
||||||
|
u32 Layer = TimelineState->SelectedAnimationLayer;
|
||||||
|
|
||||||
frame_range Range = ActiveAnim->PlayableRange;
|
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, StartFrame, EndFrame, PatternHandle, Layer);
|
||||||
u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, Panel->Bounds, Range);
|
|
||||||
|
|
||||||
animation_pattern_handle PatternHandle = Patterns_IndexToHandle(4);
|
|
||||||
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), PatternHandle, TimelineState->SelectedAnimationLayer);
|
|
||||||
TimelineState->SelectedBlockHandle = NewBlockHandle;
|
TimelineState->SelectedBlockHandle = NewBlockHandle;
|
||||||
|
} else {
|
||||||
|
// TODO(pjs): we don't want to create a block of zero frames
|
||||||
|
// since you won't be able to delete it. What do we do here??
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input_command AnimationTimeline_Commands[] = {
|
input_command AnimationTimeline_Commands[] = {
|
||||||
{ KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand },
|
{ KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand },
|
||||||
{ KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand },
|
|
||||||
};
|
};
|
||||||
s32 AnimationTimeline_CommandsCount = 2;
|
s32 AnimationTimeline_CommandsCount = 2;
|
||||||
|
|
||||||
|
@ -276,10 +284,17 @@ GSMetaTag(panel_type_animation_timeline);
|
||||||
internal void
|
internal void
|
||||||
AnimationTimeline_Init(panel* Panel, app_state* State, context Context)
|
AnimationTimeline_Init(panel* Panel, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
|
animation_handle Handle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||||
|
|
||||||
// TODO: :FreePanelMemory
|
// TODO: :FreePanelMemory
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
|
||||||
animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state);
|
animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state);
|
||||||
|
TimelineState->EditingAnimationHandle = Handle;
|
||||||
|
|
||||||
|
if (IsValid(Handle)) {
|
||||||
|
animation_array Animations = State->AnimationSystem.Animations;
|
||||||
|
animation* ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||||
TimelineState->VisibleRange = ActiveAnim->PlayableRange;
|
TimelineState->VisibleRange = ActiveAnim->PlayableRange;
|
||||||
|
}
|
||||||
|
|
||||||
Panel->StateMemory = StructToData(TimelineState, animation_timeline_state);
|
Panel->StateMemory = StructToData(TimelineState, animation_timeline_state);
|
||||||
}
|
}
|
||||||
|
@ -481,92 +496,6 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range V
|
||||||
return BlockBounds;
|
return BlockBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal handle
|
|
||||||
DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect2 PanelBounds, handle SelectedBlockHandle, ui_interface* Interface, app_state* State)
|
|
||||||
{
|
|
||||||
gs_string Tempgs_string = PushString(State->Transient, 256);
|
|
||||||
handle Result = SelectedBlockHandle;
|
|
||||||
|
|
||||||
animation CurrAnimation = *AnimationSystem_GetActiveAnimation(AnimationSystem);
|
|
||||||
|
|
||||||
rect2 LayerMenuBounds, TimelineBounds;
|
|
||||||
RectVSplitAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds);
|
|
||||||
|
|
||||||
// In Top To Bottom Order
|
|
||||||
rect2 TimelineFrameBarBounds;
|
|
||||||
rect2 TimelineBlockDisplayBounds;
|
|
||||||
rect2 TimelineRangeBarBounds;
|
|
||||||
RectHSplitAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds);
|
|
||||||
RectHSplitAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds);
|
|
||||||
|
|
||||||
DrawLayerMenu(AnimationSystem, CurrAnimation, *Interface, LayerMenuBounds, &TimelineState->SelectedAnimationLayer);
|
|
||||||
|
|
||||||
frame_range AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, CurrAnimation, TimelineState, *Interface, TimelineRangeBarBounds);
|
|
||||||
|
|
||||||
DrawFrameBar(AnimationSystem, *Interface, AdjustedViewRange, TimelineFrameBarBounds, State);
|
|
||||||
|
|
||||||
ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f});
|
|
||||||
|
|
||||||
// Animation Blocks
|
|
||||||
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
|
|
||||||
handle DragBlockHandle = {0};
|
|
||||||
for (u32 i = 0; i < CurrAnimation.Blocks_.Count; i++)
|
|
||||||
{
|
|
||||||
animation_block* AnimationBlockAt = CurrAnimation.Blocks_.Values + i;
|
|
||||||
|
|
||||||
// If either end is in the range, we should draw it
|
|
||||||
b32 RangeIsVisible = (FrameIsInRange(AdjustedViewRange, AnimationBlockAt->Range.Min) ||
|
|
||||||
FrameIsInRange(AdjustedViewRange, 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 <= AdjustedViewRange.Min &&
|
|
||||||
AnimationBlockAt->Range.Max>= AdjustedViewRange.Max);
|
|
||||||
if (RangeIsVisible)
|
|
||||||
{
|
|
||||||
v4 BlockColor = BlackV4;
|
|
||||||
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == CurrAnimation.Blocks_.Generations[i])
|
|
||||||
{
|
|
||||||
BlockColor = PinkV4;
|
|
||||||
}
|
|
||||||
rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer);
|
|
||||||
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
|
|
||||||
{
|
|
||||||
DragBlockHandle.Index = i;
|
|
||||||
DragBlockHandle.Generation = CurrAnimation.Blocks_.Generations[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MouseDownAndNotHandled && Handle_IsValid(DragBlockHandle))
|
|
||||||
{
|
|
||||||
MouseDownAndNotHandled = false;
|
|
||||||
SelectAndBeginDragAnimationBlock(TimelineState, DragBlockHandle, AdjustedViewRange, TimelineBounds, State);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time Slider
|
|
||||||
if (FrameIsInRange(AdjustedViewRange, AnimationSystem->CurrentFrame))
|
|
||||||
{
|
|
||||||
r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange);
|
|
||||||
r32 SliderX = LerpR32(FrameAtPercentVisibleRange, TimelineBounds.Min.x, TimelineBounds.Max.x);
|
|
||||||
rect2 SliderBounds = {
|
|
||||||
v2{ SliderX, TimelineBounds.Min.y },
|
|
||||||
v2{ SliderX + 1, TimelineBounds.Max.y }
|
|
||||||
};
|
|
||||||
ui_FillRect(Interface, SliderBounds, TimeSliderColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4);
|
|
||||||
ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4);
|
|
||||||
ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4);
|
|
||||||
|
|
||||||
if (MouseDownAndNotHandled && PointIsInRect(TimelineBounds, Interface->Mouse.Pos))
|
|
||||||
{
|
|
||||||
TimelineState->SelectedBlockHandle = {0};
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
|
PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
|
||||||
{
|
{
|
||||||
Assert(ReturningFrom->TypeIndex == PanelType_FileView);
|
Assert(ReturningFrom->TypeIndex == PanelType_FileView);
|
||||||
|
@ -581,28 +510,11 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
|
||||||
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, State->Patterns);
|
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, State->Patterns);
|
||||||
NewAnim.FileInfo = AnimFile.FileInfo;
|
NewAnim.FileInfo = AnimFile.FileInfo;
|
||||||
|
|
||||||
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||||
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
|
State->AnimationSystem.ActiveFadeGroup.From = NewAnimHandle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem, animation_pattern_array Patterns)
|
|
||||||
{
|
|
||||||
ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("AnimClips Layout"));
|
|
||||||
for (u32 i = 0; i < Patterns.Count; i++)
|
|
||||||
{
|
|
||||||
animation_pattern Pattern = Patterns.Values[i];
|
|
||||||
gs_string PatternName = MakeString(Pattern.Name, Pattern.NameLength);
|
|
||||||
if (ui_Button(Interface, PatternName))
|
|
||||||
{
|
|
||||||
animation_pattern_handle PatternHandle = Patterns_IndexToHandle(i);
|
|
||||||
AddAnimationBlockAtCurrentTime(PatternHandle, SelectedAnimationLayerHandle, AnimationSystem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ui_PopLayout(Interface, MakeString("AnimClips Layout"));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
|
@ -634,14 +546,18 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
FrameCount_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
ui_interface* Interface = &State->Interface;
|
ui_interface* Interface = &State->Interface;
|
||||||
gs_string TempString = PushString(State->Transient, 256);
|
gs_string TempString = PushString(State->Transient, 256);
|
||||||
|
|
||||||
// :FrameRange
|
// :FrameRange
|
||||||
// frame_range VisibleFrames = TimelineState->VisibleRange;
|
// frame_range VisibleFrames = TimelineState->VisibleRange;
|
||||||
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
|
||||||
frame_range VisibleFrames = ActiveAnim.PlayableRange;
|
frame_range VisibleFrames = {};
|
||||||
|
if (ActiveAnim) {
|
||||||
|
VisibleFrames = ActiveAnim->PlayableRange;
|
||||||
|
}
|
||||||
|
|
||||||
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
|
s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min;
|
||||||
|
|
||||||
|
@ -687,10 +603,9 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
LayerList_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
ui_interface* Interface = &State->Interface;
|
ui_interface* Interface = &State->Interface;
|
||||||
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
|
||||||
|
|
||||||
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
|
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
|
||||||
|
|
||||||
|
@ -698,9 +613,12 @@ LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* P
|
||||||
rect2 LayerBounds = {0};
|
rect2 LayerBounds = {0};
|
||||||
LayerBounds.Min = Bounds.Min;
|
LayerBounds.Min = Bounds.Min;
|
||||||
LayerBounds.Max = LayerBounds.Min + LayerDim;
|
LayerBounds.Max = LayerBounds.Min + LayerDim;
|
||||||
for (u32 i = 0; i < ActiveAnim.Layers.Count; i++)
|
|
||||||
|
if (ActiveAnim)
|
||||||
{
|
{
|
||||||
anim_layer* Layer = ActiveAnim.Layers.Values + i;
|
for (u32 i = 0; i < ActiveAnim->Layers.Count; i++)
|
||||||
|
{
|
||||||
|
anim_layer* Layer = ActiveAnim->Layers.Values + i;
|
||||||
|
|
||||||
if (ui_MouseClickedRect(*Interface, LayerBounds))
|
if (ui_MouseClickedRect(*Interface, LayerBounds))
|
||||||
{
|
{
|
||||||
|
@ -717,19 +635,23 @@ LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* P
|
||||||
LayerBounds = Rect2TranslateY(LayerBounds, LayerDim.y);
|
LayerBounds = Rect2TranslateY(LayerBounds, LayerDim.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
TimeRange_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
ui_interface* Interface = &State->Interface;
|
ui_interface* Interface = &State->Interface;
|
||||||
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
|
||||||
|
|
||||||
// TODO(pjs): setting the timeline to show the entire range
|
// TODO(pjs): setting the timeline to show the entire range
|
||||||
// of the current animation until I reimplement the range
|
// of the current animation until I reimplement the range
|
||||||
// slider bars
|
// slider bars
|
||||||
// :FrameRange
|
// :FrameRange
|
||||||
// frame_range ViewRange = TimelineState->VisibleRange;
|
// frame_range ViewRange = TimelineState->VisibleRange;
|
||||||
frame_range ViewRange = ActiveAnim.PlayableRange;
|
frame_range ViewRange = {};
|
||||||
|
if (ActiveAnim)
|
||||||
|
{
|
||||||
|
ViewRange = ActiveAnim->PlayableRange;
|
||||||
|
}
|
||||||
|
|
||||||
handle SelectedBlockHandle = TimelineState->SelectedBlockHandle;
|
handle SelectedBlockHandle = TimelineState->SelectedBlockHandle;
|
||||||
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
|
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
|
||||||
|
@ -737,9 +659,11 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
||||||
// Animation Blocks
|
// Animation Blocks
|
||||||
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
|
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
|
||||||
handle DragBlockHandle = {0};
|
handle DragBlockHandle = {0};
|
||||||
for (u32 i = 0; i < ActiveAnim.Blocks_.Count; i++)
|
if (ActiveAnim)
|
||||||
{
|
{
|
||||||
animation_block* AnimationBlockAt = ActiveAnim.Blocks_.Values + i;
|
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
|
// If either end is in the range, we should draw it
|
||||||
b32 RangeIsVisible = (FrameIsInRange(ViewRange, AnimationBlockAt->Range.Min) ||
|
b32 RangeIsVisible = (FrameIsInRange(ViewRange, AnimationBlockAt->Range.Min) ||
|
||||||
|
@ -751,7 +675,7 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
||||||
if (RangeIsVisible)
|
if (RangeIsVisible)
|
||||||
{
|
{
|
||||||
v4 BlockColor = BlackV4;
|
v4 BlockColor = BlackV4;
|
||||||
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == ActiveAnim.Blocks_.Generations[i])
|
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == ActiveAnim->Blocks_.Generations[i])
|
||||||
{
|
{
|
||||||
BlockColor = PinkV4;
|
BlockColor = PinkV4;
|
||||||
}
|
}
|
||||||
|
@ -760,7 +684,8 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
||||||
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
|
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
|
||||||
{
|
{
|
||||||
DragBlockHandle.Index = i;
|
DragBlockHandle.Index = i;
|
||||||
DragBlockHandle.Generation = ActiveAnim.Blocks_.Generations[i];
|
DragBlockHandle.Generation = ActiveAnim->Blocks_.Generations[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -795,10 +720,10 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
||||||
internal void
|
internal void
|
||||||
AnimInfoView_SaveAnimFile (gs_const_string Path, app_state* State, context Context)
|
AnimInfoView_SaveAnimFile (gs_const_string Path, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex;
|
animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||||
animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex];
|
animation ActiveAnim = *AnimationArray_GetSafe(State->AnimationSystem.Animations, ActiveAnimHandle);
|
||||||
|
|
||||||
gs_string FileText = AnimSerializer_Serialize(ActiveAnimation, State->Patterns, State->Transient);
|
gs_string FileText = AnimSerializer_Serialize(ActiveAnim, State->Patterns, State->Transient);
|
||||||
|
|
||||||
if (!WriteEntireFile(Context.ThreadContext.FileHandler, Path, StringToData(FileText)))
|
if (!WriteEntireFile(Context.ThreadContext.FileHandler, Path, StringToData(FileText)))
|
||||||
{
|
{
|
||||||
|
@ -816,24 +741,41 @@ PANEL_MODAL_OVERRIDE_CALLBACK(AnimInfoView_SaveAnimFileCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
AnimationTimeline_SetActiveAnimation (animation_handle Handle, animation_timeline_state* TimelineState,
|
||||||
|
animation_system* System)
|
||||||
|
{
|
||||||
|
System->ActiveFadeGroup.From = Handle;
|
||||||
|
TimelineState->EditingAnimationHandle = Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||||
{
|
{
|
||||||
animation_system* AnimSystem = &State->AnimationSystem;
|
animation_system* AnimSystem = &State->AnimationSystem;
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem);
|
|
||||||
|
|
||||||
ui_interface* Interface = &State->Interface;
|
ui_interface* Interface = &State->Interface;
|
||||||
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"));
|
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"));
|
||||||
|
|
||||||
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG);
|
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG);
|
||||||
|
|
||||||
if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), ActiveAnim->Name))
|
gs_string AnimName = {};
|
||||||
|
if (ActiveAnim)
|
||||||
|
{
|
||||||
|
AnimName = ActiveAnim->Name;
|
||||||
|
} else {
|
||||||
|
AnimName = MakeString("[None]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), AnimName))
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
|
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
|
||||||
{
|
{
|
||||||
animation Animation = AnimSystem->Animations.Values[i];
|
animation Animation = AnimSystem->Animations.Values[i];
|
||||||
if (ui_Button(Interface, Animation.Name))
|
if (ui_Button(Interface, Animation.Name))
|
||||||
{
|
{
|
||||||
AnimSystem->ActiveAnimationIndex = i;
|
animation_handle NewHandle = {};
|
||||||
|
NewHandle.Index = i;
|
||||||
|
AnimationTimeline_SetActiveAnimation(NewHandle, TimelineState, AnimSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -846,16 +788,16 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel
|
||||||
animation NewAnim = {};
|
animation NewAnim = {};
|
||||||
NewAnim.Name = PushString(State->AnimationSystem.Storage, 256);
|
NewAnim.Name = PushString(State->AnimationSystem.Storage, 256);
|
||||||
|
|
||||||
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||||
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
|
State->AnimationSystem.ActiveFadeGroup.From = NewAnimHandle;
|
||||||
}
|
}
|
||||||
if (ui_Button(Interface, MakeString("Save")))
|
if (ActiveAnim && ui_Button(Interface, MakeString("Save")))
|
||||||
{
|
{
|
||||||
// Save Animation File
|
// Save Animation File
|
||||||
// TODO(pjs): If you created the animation via the "new" button, there won't be a file attached.
|
// TODO(pjs): If you created the animation via the "new" button, there won't be a file attached.
|
||||||
// need to use the file browser to create a file
|
// need to use the file browser to create a file
|
||||||
u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex;
|
animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||||
animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex];
|
animation ActiveAnimation = *AnimationArray_GetSafe(State->AnimationSystem.Animations, ActiveAnimHandle);
|
||||||
|
|
||||||
if (!ActiveAnimation.FileInfo.Path.Str)
|
if (!ActiveAnimation.FileInfo.Path.Str)
|
||||||
{
|
{
|
||||||
|
@ -875,6 +817,8 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel
|
||||||
}
|
}
|
||||||
ui_EndRow(Interface);
|
ui_EndRow(Interface);
|
||||||
|
|
||||||
|
if (ActiveAnim)
|
||||||
|
{
|
||||||
ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name);
|
ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name);
|
||||||
|
|
||||||
ui_Label(Interface, MakeString("Frame Range"));
|
ui_Label(Interface, MakeString("Frame Range"));
|
||||||
|
@ -908,6 +852,11 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel
|
||||||
ui_EndLabeledDropdown(Interface);
|
ui_EndLabeledDropdown(Interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ui_Button(Interface, MakeString("+ Add Block")))
|
||||||
|
{
|
||||||
|
AnimationTimeline_AddAnimationBlockCommand(TimelineState, State, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
ui_PopLayout(Interface, MakeString("AnimInfo Layout"));
|
ui_PopLayout(Interface, MakeString("AnimInfo Layout"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,6 +873,15 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
|
||||||
{
|
{
|
||||||
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
||||||
|
|
||||||
|
animation* ActiveAnim = 0;
|
||||||
|
animation_handle Handle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||||
|
TimelineState->EditingAnimationHandle = Handle;
|
||||||
|
if (IsValid(Handle))
|
||||||
|
{
|
||||||
|
animation_array Animations = State->AnimationSystem.Animations;
|
||||||
|
ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||||
|
}
|
||||||
|
|
||||||
ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f});
|
ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f});
|
||||||
|
|
||||||
rect2 TimelineBounds, InfoBounds;
|
rect2 TimelineBounds, InfoBounds;
|
||||||
|
@ -940,10 +898,10 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
|
||||||
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
|
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
|
||||||
|
|
||||||
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
|
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
|
||||||
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
|
FrameCount_Render(TimelineState, ActiveAnim, FrameCountBounds, RenderBuffer, State, Context);
|
||||||
LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context);
|
LayerList_Render(TimelineState, ActiveAnim, LayersBounds, Panel, RenderBuffer, State, Context);
|
||||||
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
|
TimeRange_Render(TimelineState, ActiveAnim, TimeRangeBounds, RenderBuffer, State, Context);
|
||||||
AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context);
|
AnimInfoView_Render(TimelineState, ActiveAnim, InfoBounds, Panel, RenderBuffer, State, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
|
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
|
||||||
|
|
|
@ -16,6 +16,8 @@ struct file_view_state
|
||||||
file_view_mode Mode;
|
file_view_mode Mode;
|
||||||
|
|
||||||
gs_string WorkingDirectory;
|
gs_string WorkingDirectory;
|
||||||
|
gs_string DisplayDirectory;
|
||||||
|
|
||||||
gs_memory_arena FileNamesArena;
|
gs_memory_arena FileNamesArena;
|
||||||
gs_file_info_array FileNames;
|
gs_file_info_array FileNames;
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
||||||
Assert(LastChar == '\\' || LastChar == '/');
|
Assert(LastChar == '\\' || LastChar == '/');
|
||||||
ClearArena(&State->FileNamesArena);
|
ClearArena(&State->FileNamesArena);
|
||||||
|
|
||||||
|
|
||||||
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
|
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
|
||||||
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
|
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
|
||||||
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
|
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
|
||||||
|
@ -62,6 +65,8 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
||||||
AppendPrintF(&SanitizedDir, "\\");
|
AppendPrintF(&SanitizedDir, "\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
|
||||||
|
|
||||||
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
|
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
|
||||||
if (NewWorkingDir.IsDirectory)
|
if (NewWorkingDir.IsDirectory)
|
||||||
{
|
{
|
||||||
|
@ -73,7 +78,7 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
||||||
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
|
// NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory
|
||||||
// in some cases. Shouldn't be a problem but it is unnecessary
|
// in some cases. Shouldn't be a problem but it is unnecessary
|
||||||
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
|
PrintF(&State->WorkingDirectory, "%S", SanitizedDir.ConstString);
|
||||||
|
PrintF(&State->DisplayDirectory, "%S", SanitizedDisplayDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +93,9 @@ FileView_Init(panel* Panel, app_state* State, context Context)
|
||||||
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator);
|
FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator);
|
||||||
|
|
||||||
// TODO(pjs): this shouldn't be stored in permanent
|
// TODO(pjs): this shouldn't be stored in permanent
|
||||||
FileViewState->WorkingDirectory = PushString(&State->Permanent, 256);
|
FileViewState->DisplayDirectory = PushString(&State->Permanent, 1024);
|
||||||
|
FileViewState->WorkingDirectory = PushString(&State->Permanent, 1024);
|
||||||
|
|
||||||
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
|
FileView_UpdateWorkingDirectory(ConstString(".\\"), FileViewState, Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +116,17 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
||||||
|
|
||||||
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
|
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout"));
|
||||||
{
|
{
|
||||||
|
|
||||||
ui_BeginRow(&State->Interface, 3);
|
ui_BeginRow(&State->Interface, 3);
|
||||||
{
|
{
|
||||||
if (FileViewState->Mode == FileViewMode_Save)
|
if (FileViewState->Mode == FileViewMode_Save)
|
||||||
{
|
{
|
||||||
if (ui_Button(&State->Interface, MakeString("Save")))
|
if (ui_Button(&State->Interface, MakeString("Save")))
|
||||||
{
|
{
|
||||||
|
if (!FileViewState->SelectedFile.Path.Str)
|
||||||
|
{
|
||||||
|
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
|
||||||
|
}
|
||||||
|
|
||||||
FileView_Exit_(Panel, State, Context);
|
FileView_Exit_(Panel, State, Context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,11 +139,11 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
||||||
ui_EndRow(&State->Interface);
|
ui_EndRow(&State->Interface);
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->WorkingDirectory))
|
if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->DisplayDirectory))
|
||||||
{
|
{
|
||||||
// if last character is a slash, update pwd, and clear the filter string
|
// if last character is a slash, update pwd, and clear the filter string
|
||||||
// otherwise update the filter string
|
// otherwise update the filter string
|
||||||
gs_string Pwd = FileViewState->WorkingDirectory;
|
gs_string Pwd = FileViewState->DisplayDirectory;
|
||||||
char LastChar = Pwd.Str[Pwd.Length - 1];
|
char LastChar = Pwd.Str[Pwd.Length - 1];
|
||||||
if (LastChar == '\\' || LastChar == '/')
|
if (LastChar == '\\' || LastChar == '/')
|
||||||
{
|
{
|
||||||
|
@ -163,9 +174,9 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
FileViewState->SelectedFile = File;
|
||||||
switch (FileViewState->Mode)
|
switch (FileViewState->Mode)
|
||||||
{
|
{
|
||||||
FileViewState->SelectedFile = File;
|
|
||||||
case FileViewMode_Load:
|
case FileViewMode_Load:
|
||||||
{
|
{
|
||||||
FileView_Exit_(Panel, State, Context);
|
FileView_Exit_(Panel, State, Context);
|
||||||
|
|
|
@ -46,9 +46,7 @@ enum blend_mode
|
||||||
BlendMode_Count,
|
BlendMode_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(pjs): Add Opacity to this
|
// TODO(pjs): This really doesn't belong here
|
||||||
typedef pixel led_blend_proc(pixel PixelA, pixel PixelB);
|
|
||||||
|
|
||||||
global gs_const_string BlendModeStrings[] = {
|
global gs_const_string BlendModeStrings[] = {
|
||||||
ConstString("Overwrite"),
|
ConstString("Overwrite"),
|
||||||
ConstString("Add"),
|
ConstString("Add"),
|
||||||
|
@ -86,6 +84,18 @@ struct animation
|
||||||
gs_file_info FileInfo;
|
gs_file_info FileInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct animation_handle
|
||||||
|
{
|
||||||
|
s32 Index;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal bool IsValid (animation_handle H) { return H.Index >= 0; }
|
||||||
|
internal void Clear (animation_handle* H) { H->Index = -1; }
|
||||||
|
internal bool AnimHandlesAreEqual (animation_handle A, animation_handle B)
|
||||||
|
{
|
||||||
|
return A.Index == B.Index;
|
||||||
|
}
|
||||||
|
|
||||||
struct animation_array
|
struct animation_array
|
||||||
{
|
{
|
||||||
animation* Values;
|
animation* Values;
|
||||||
|
@ -101,7 +111,9 @@ struct animation_layer_frame
|
||||||
animation_block NextHot;
|
animation_block NextHot;
|
||||||
bool HasNextHot;
|
bool HasNextHot;
|
||||||
|
|
||||||
r32 HotOpacity;
|
r32 NextHotOpacity;
|
||||||
|
|
||||||
|
blend_mode BlendMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(pjs): This is an evaluated frame - across all layers in an
|
// NOTE(pjs): This is an evaluated frame - across all layers in an
|
||||||
|
@ -112,6 +124,27 @@ struct animation_frame
|
||||||
u32 LayersCount;
|
u32 LayersCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum animation_repeat_mode
|
||||||
|
{
|
||||||
|
AnimationRepeat_Single,
|
||||||
|
AnimationRepeat_Loop,
|
||||||
|
AnimationRepeat_Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
|
global gs_const_string AnimationRepeatModeStrings[] = {
|
||||||
|
ConstString("Repeat Single"),
|
||||||
|
ConstString("Loop"),
|
||||||
|
ConstString("Invalid"),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct animation_fade_group
|
||||||
|
{
|
||||||
|
animation_handle From;
|
||||||
|
animation_handle To;
|
||||||
|
r32 FadeElapsed;
|
||||||
|
r32 FadeDuration;
|
||||||
|
};
|
||||||
|
|
||||||
#define ANIMATION_SYSTEM_LAYERS_MAX 128
|
#define ANIMATION_SYSTEM_LAYERS_MAX 128
|
||||||
#define ANIMATION_SYSTEM_BLOCKS_MAX 128
|
#define ANIMATION_SYSTEM_BLOCKS_MAX 128
|
||||||
struct animation_system
|
struct animation_system
|
||||||
|
@ -119,10 +152,14 @@ struct animation_system
|
||||||
gs_memory_arena* Storage;
|
gs_memory_arena* Storage;
|
||||||
animation_array Animations;
|
animation_array Animations;
|
||||||
|
|
||||||
|
animation_repeat_mode RepeatMode;
|
||||||
|
|
||||||
// NOTE(Peter): The frame currently being displayed/processed. you
|
// NOTE(Peter): The frame currently being displayed/processed. you
|
||||||
// can see which frame you're on by looking at the time slider on the timeline
|
// can see which frame you're on by looking at the time slider on the timeline
|
||||||
// panel
|
// panel
|
||||||
u32 ActiveAnimationIndex;
|
animation_handle ActiveAnimationHandle_;
|
||||||
|
animation_fade_group ActiveFadeGroup;
|
||||||
|
|
||||||
s32 CurrentFrame;
|
s32 CurrentFrame;
|
||||||
s32 LastUpdatedFrame;
|
s32 LastUpdatedFrame;
|
||||||
r32 SecondsPerFrame;
|
r32 SecondsPerFrame;
|
||||||
|
@ -214,7 +251,7 @@ Patterns_Create(gs_memory_arena* Arena, s32 CountMax)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define Patterns_PushPattern(array, proc) Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)))
|
#define Patterns_PushPattern(array, proc) Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)) - 1)
|
||||||
internal void
|
internal void
|
||||||
Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength)
|
Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength)
|
||||||
{
|
{
|
||||||
|
@ -341,13 +378,33 @@ AnimationArray_Create(gs_memory_arena* Storage, u32 CountMax)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal u32
|
internal animation_handle
|
||||||
AnimationArray_Push(animation_array* Array, animation Value)
|
AnimationArray_Push(animation_array* Array, animation Value)
|
||||||
{
|
{
|
||||||
Assert(Array->Count < Array->CountMax);
|
Assert(Array->Count < Array->CountMax);
|
||||||
u32 Index = Array->Count++;
|
animation_handle Result = {0};
|
||||||
Array->Values[Index] = Value;
|
Result.Index = Array->Count++;
|
||||||
return Index;
|
Array->Values[Result.Index] = Value;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal animation*
|
||||||
|
AnimationArray_Get(animation_array Array, animation_handle Handle)
|
||||||
|
{
|
||||||
|
animation* Result = 0;
|
||||||
|
if (IsValid(Handle) && Handle.Index < (s32)Array.Count)
|
||||||
|
{
|
||||||
|
Result = Array.Values + Handle.Index;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal animation*
|
||||||
|
AnimationArray_GetSafe(animation_array Array, animation_handle Handle)
|
||||||
|
{
|
||||||
|
Assert(IsValid(Handle));
|
||||||
|
Assert(Handle.Index < (s32)Array.Count);
|
||||||
|
return AnimationArray_Get(Array, Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
@ -482,6 +539,49 @@ ClampFrameToRange(s32 Frame, frame_range Range)
|
||||||
|
|
||||||
// Layers
|
// Layers
|
||||||
|
|
||||||
|
// Fade Group
|
||||||
|
|
||||||
|
internal bool
|
||||||
|
AnimationFadeGroup_ShouldRender (animation_fade_group FadeGroup)
|
||||||
|
{
|
||||||
|
return IsValid(FadeGroup.From);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationFadeGroup_Advance(animation_fade_group* Group)
|
||||||
|
{
|
||||||
|
Group->From = Group->To;
|
||||||
|
Clear(&Group->To);
|
||||||
|
Group->FadeElapsed = 0;
|
||||||
|
Group->FadeDuration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationFadeGroup_Update(animation_fade_group* Group, r32 DeltaTime)
|
||||||
|
{
|
||||||
|
if (IsValid(Group->To))
|
||||||
|
{
|
||||||
|
Group->FadeElapsed += DeltaTime;
|
||||||
|
if (Group->FadeElapsed >= Group->FadeDuration)
|
||||||
|
{
|
||||||
|
AnimationFadeGroup_Advance(Group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationFadeGroup_FadeTo(animation_fade_group* Group, animation_handle To, r32 Duration)
|
||||||
|
{
|
||||||
|
// complete current fade if there is one in progress
|
||||||
|
if (IsValid(Group->To))
|
||||||
|
{
|
||||||
|
AnimationFadeGroup_Advance(Group);
|
||||||
|
}
|
||||||
|
|
||||||
|
Group->To = To;
|
||||||
|
Group->FadeDuration = Duration;
|
||||||
|
}
|
||||||
|
|
||||||
// System
|
// System
|
||||||
|
|
||||||
struct animation_system_desc
|
struct animation_system_desc
|
||||||
|
@ -499,29 +599,38 @@ AnimationSystem_Init(animation_system_desc Desc)
|
||||||
Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount);
|
Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount);
|
||||||
Result.SecondsPerFrame = Desc.SecondsPerFrame;
|
Result.SecondsPerFrame = Desc.SecondsPerFrame;
|
||||||
|
|
||||||
|
Clear(&Result.ActiveFadeGroup.From);
|
||||||
|
Clear(&Result.ActiveFadeGroup.To);
|
||||||
|
Result.ActiveFadeGroup.FadeElapsed = 0;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal animation*
|
internal animation*
|
||||||
AnimationSystem_GetActiveAnimation(animation_system* System)
|
AnimationSystem_GetActiveAnimation(animation_system* System)
|
||||||
{
|
{
|
||||||
// TODO(pjs): need a way to specify the active animation
|
return AnimationArray_Get(System->Animations, System->ActiveFadeGroup.From);
|
||||||
return System->Animations.Values + System->ActiveAnimationIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal animation_frame
|
internal animation_frame
|
||||||
AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_arena* Arena)
|
AnimationSystem_CalculateAnimationFrame(animation_system* System,
|
||||||
|
animation* Animation,
|
||||||
|
gs_memory_arena* Arena)
|
||||||
{
|
{
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
|
||||||
|
|
||||||
animation_frame Result = {0};
|
animation_frame Result = {0};
|
||||||
Result.LayersCount = ActiveAnim->Layers.Count;
|
Result.LayersCount = Animation->Layers.Count;
|
||||||
Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount);
|
Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount);
|
||||||
ZeroArray(Result.Layers, animation_layer_frame, Result.LayersCount);
|
ZeroArray(Result.Layers, animation_layer_frame, Result.LayersCount);
|
||||||
|
|
||||||
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
|
for (u32 l = 0; l < Animation->Layers.Count; l++)
|
||||||
{
|
{
|
||||||
animation_block Block = ActiveAnim->Blocks_.Values[i];
|
animation_layer_frame* Layer = Result.Layers + l;
|
||||||
|
Layer->BlendMode = Animation->Layers.Values[l].BlendMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < Animation->Blocks_.Count; i++)
|
||||||
|
{
|
||||||
|
animation_block Block = Animation->Blocks_.Values[i];
|
||||||
|
|
||||||
if (FrameIsInRange(Block.Range, System->CurrentFrame))
|
if (FrameIsInRange(Block.Range, System->CurrentFrame))
|
||||||
{
|
{
|
||||||
|
@ -548,12 +657,12 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
||||||
frame_range BlendRange = {};
|
frame_range BlendRange = {};
|
||||||
BlendRange.Min = Layer->NextHot.Range.Min;
|
BlendRange.Min = Layer->NextHot.Range.Min;
|
||||||
BlendRange.Max = Layer->Hot.Range.Max;
|
BlendRange.Max = Layer->Hot.Range.Max;
|
||||||
Layer->HotOpacity = 1.0f - FrameToPercentRange(System->CurrentFrame, BlendRange);
|
Layer->NextHotOpacity = FrameToPercentRange(System->CurrentFrame, BlendRange);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Layer->Hot = Block;
|
Layer->Hot = Block;
|
||||||
Layer->HotOpacity = 1.0f;
|
Layer->NextHotOpacity = 0.0f;
|
||||||
Layer->HasHot = true;
|
Layer->HasHot = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -563,18 +672,34 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
AnimationSystem_Update(animation_system* System)
|
AnimationSystem_Update(animation_system* System, r32 DeltaTime)
|
||||||
{
|
{
|
||||||
|
if (!System->TimelineShouldAdvance) { return; }
|
||||||
|
if (!AnimationFadeGroup_ShouldRender(System->ActiveFadeGroup)) { return; }
|
||||||
|
|
||||||
|
AnimationFadeGroup_Update(&System->ActiveFadeGroup, DeltaTime);
|
||||||
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||||
if (System->TimelineShouldAdvance) {
|
|
||||||
// TODO(Peter): Revisit this. This implies that the framerate of the animation system
|
// TODO(Peter): Revisit this. This implies that the framerate of the animation system
|
||||||
// is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
|
// is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
|
||||||
System->CurrentFrame += 1;
|
System->CurrentFrame += 1;
|
||||||
|
|
||||||
// Loop back to the beginning
|
// Loop back to the beginning
|
||||||
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
|
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
|
||||||
|
{
|
||||||
|
switch (System->RepeatMode)
|
||||||
|
{
|
||||||
|
case AnimationRepeat_Single:
|
||||||
{
|
{
|
||||||
System->CurrentFrame = 0;
|
System->CurrentFrame = 0;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case AnimationRepeat_Loop:
|
||||||
|
{
|
||||||
|
// TODO(pjs):
|
||||||
|
}break;
|
||||||
|
|
||||||
|
InvalidDefaultCase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,25 +6,27 @@
|
||||||
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
|
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
|
||||||
|
|
||||||
internal pixel
|
internal pixel
|
||||||
LedBlend_Overwrite(pixel PixelA, pixel PixelB)
|
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData)
|
||||||
{
|
{
|
||||||
return PixelB;
|
return PixelB;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal pixel
|
internal pixel
|
||||||
LedBlend_Overwrite(pixel PixelA, pixel PixelB, r32 Opacity)
|
LedBlend_Lerp(pixel PixelA, pixel PixelB, u8* UserData)
|
||||||
{
|
{
|
||||||
|
r32 BOpacity = *(r32*)UserData;
|
||||||
|
|
||||||
pixel Result = {};
|
pixel Result = {};
|
||||||
|
|
||||||
r32 BOpacity = 1.0f - Opacity;
|
r32 AOpacity = 1.0f - BOpacity;
|
||||||
Result.R = (u8)((PixelA.R * Opacity) + (PixelB.R * BOpacity));
|
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
|
||||||
Result.G = (u8)((PixelA.G * Opacity) + (PixelB.G * BOpacity));
|
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
|
||||||
Result.B = (u8)((PixelA.B * Opacity) + (PixelB.B * BOpacity));
|
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal pixel
|
internal pixel
|
||||||
LedBlend_Add(pixel PixelA, pixel PixelB)
|
LedBlend_Add(pixel PixelA, pixel PixelB, u8* UserData)
|
||||||
{
|
{
|
||||||
pixel Result = {};
|
pixel Result = {};
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ LedBlend_Add(pixel PixelA, pixel PixelB)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal pixel
|
internal pixel
|
||||||
LedBlend_Multiply(pixel PixelA, pixel PixelB)
|
LedBlend_Multiply(pixel PixelA, pixel PixelB, u8* UserData)
|
||||||
{
|
{
|
||||||
pixel Result = {};
|
pixel Result = {};
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ LedBlend_Multiply(pixel PixelA, pixel PixelB)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal pixel
|
internal pixel
|
||||||
LedBlend_Overlay(pixel PixelA, pixel PixelB)
|
LedBlend_Overlay(pixel PixelA, pixel PixelB, u8* UserData)
|
||||||
{
|
{
|
||||||
pixel Result = {};
|
pixel Result = {};
|
||||||
return Result;
|
return Result;
|
||||||
|
@ -80,30 +82,23 @@ LedBlend_GetProc(blend_mode BlendMode)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pattern_args
|
||||||
|
{
|
||||||
|
assembly Assembly;
|
||||||
|
gs_memory_arena* Transient;
|
||||||
|
u8* UserData;
|
||||||
|
};
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array Patterns, gs_memory_arena* Transient,
|
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs)
|
||||||
u8* UserData)
|
|
||||||
{
|
{
|
||||||
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
|
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
|
||||||
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
||||||
|
|
||||||
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
|
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
|
||||||
Pattern.Proc(Buffer, Assembly, SecondsIntoBlock, Transient, UserData);
|
Pattern.Proc(Buffer, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
|
|
||||||
led_system* LedSystem,
|
|
||||||
animation_pattern_array Patterns,
|
|
||||||
gs_memory_arena* Transient,
|
|
||||||
u8* UserData)
|
|
||||||
{
|
|
||||||
s32 CurrentFrame = System->CurrentFrame;
|
|
||||||
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
|
|
||||||
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
|
||||||
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient);
|
|
||||||
|
|
||||||
// NOTE(pjs): This mirrors animation_layer_frame to account
|
// NOTE(pjs): This mirrors animation_layer_frame to account
|
||||||
// for overlapping
|
// for overlapping
|
||||||
struct layer_led_buffer
|
struct layer_led_buffer
|
||||||
|
@ -112,31 +107,30 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
||||||
led_buffer NextHotBuffer;
|
led_buffer NextHotBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
layer_led_buffer* LayerBuffers = PushArray(Transient, layer_led_buffer, CurrFrame.LayersCount);
|
internal led_buffer
|
||||||
|
RenderAnimationToLedBuffer (animation_system* System,
|
||||||
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
pattern_args PatternArgs,
|
||||||
|
animation_frame CurrFrame,
|
||||||
|
layer_led_buffer* LayerBuffers,
|
||||||
|
led_buffer* AssemblyLedBuffer,
|
||||||
|
animation_pattern_array Patterns,
|
||||||
|
gs_memory_arena* Transient)
|
||||||
{
|
{
|
||||||
assembly* Assembly = &Assemblies.Values[AssemblyIndex];
|
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||||
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
|
|
||||||
|
|
||||||
// Create the LayerLEDBuffers
|
// Create the LayerLEDBuffers
|
||||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||||
{
|
{
|
||||||
layer_led_buffer TempBuffer = {};
|
layer_led_buffer TempBuffer = {};
|
||||||
|
|
||||||
if (CurrFrame.Layers[Layer].HasHot)
|
if (CurrFrame.Layers[Layer].HasHot)
|
||||||
{
|
{
|
||||||
TempBuffer.HotBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||||
TempBuffer.HotBuffer.Positions = AssemblyLedBuffer->Positions;
|
|
||||||
TempBuffer.HotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
|
|
||||||
LedBuffer_ClearToBlack(&TempBuffer.HotBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrFrame.Layers[Layer].HasNextHot)
|
if (CurrFrame.Layers[Layer].HasNextHot)
|
||||||
{
|
{
|
||||||
TempBuffer.NextHotBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||||
TempBuffer.NextHotBuffer.Positions = AssemblyLedBuffer->Positions;
|
}
|
||||||
TempBuffer.NextHotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
|
|
||||||
LedBuffer_ClearToBlack(&TempBuffer.NextHotBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LayerBuffers[Layer] = TempBuffer;
|
LayerBuffers[Layer] = TempBuffer;
|
||||||
|
@ -150,14 +144,14 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
||||||
{
|
{
|
||||||
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
|
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
|
||||||
animation_block Block = LayerFrame.Hot;
|
animation_block Block = LayerFrame.Hot;
|
||||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
|
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LayerFrame.HasNextHot)
|
if (LayerFrame.HasNextHot)
|
||||||
{
|
{
|
||||||
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
||||||
animation_block Block = LayerFrame.NextHot;
|
animation_block Block = LayerFrame.NextHot;
|
||||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
|
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,33 +162,121 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
||||||
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
|
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
|
||||||
if (LayerFrame.HasNextHot)
|
if (LayerFrame.HasNextHot)
|
||||||
{
|
{
|
||||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
LedBuffer_Blend(LayerBuffer.HotBuffer,
|
||||||
{
|
LayerBuffer.NextHotBuffer,
|
||||||
pixel A = LayerBuffer.HotBuffer.Colors[LED];
|
&LayerBuffer.HotBuffer,
|
||||||
pixel B = LayerBuffer.NextHotBuffer.Colors[LED];
|
LedBlend_Lerp,
|
||||||
LayerBuffer.HotBuffer.Colors[LED] = LedBlend_Overwrite(A, B, LayerFrame.HotOpacity);
|
(u8*)&LayerFrame.NextHotOpacity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consolidate Temp Buffers
|
// Consolidate Temp Buffers back into AssemblyLedBuffer
|
||||||
// We do this in reverse order so that they go from top to bottom
|
// We do this in reverse order so that they go from top to bottom
|
||||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||||
{
|
{
|
||||||
if (CurrFrame.Layers[Layer].HasHot)
|
if (CurrFrame.Layers[Layer].HasHot)
|
||||||
{
|
{
|
||||||
led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode);
|
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
|
||||||
Assert(Blend != 0);
|
LedBuffer_Blend(AccBuffer,
|
||||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
LayerBuffers[Layer].HotBuffer,
|
||||||
|
&AccBuffer,
|
||||||
|
Blend,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
|
||||||
|
led_system* LedSystem,
|
||||||
|
animation_pattern_array Patterns,
|
||||||
|
gs_memory_arena* Transient,
|
||||||
|
u8* UserData)
|
||||||
{
|
{
|
||||||
pixel A = AssemblyLedBuffer->Colors[LED];
|
s32 CurrentFrame = System->CurrentFrame;
|
||||||
pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED];
|
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
|
||||||
AssemblyLedBuffer->Colors[LED] = Blend(A, B);
|
|
||||||
|
#if 1
|
||||||
|
animation_array Animations = System->Animations;
|
||||||
|
animation_fade_group FadeGroup = System->ActiveFadeGroup;
|
||||||
|
|
||||||
|
animation* FromAnim = AnimationArray_Get(Animations, FadeGroup.From);
|
||||||
|
animation_frame FromFrame = AnimationSystem_CalculateAnimationFrame(System, FromAnim, Transient);
|
||||||
|
layer_led_buffer* FromLayerBuffers = PushArray(Transient, layer_led_buffer, FromFrame.LayersCount);
|
||||||
|
|
||||||
|
animation* ToAnim = AnimationArray_Get(Animations, FadeGroup.To);
|
||||||
|
animation_frame ToFrame = {0};
|
||||||
|
layer_led_buffer* ToLayerBuffers = 0;
|
||||||
|
if (ToAnim)
|
||||||
|
{
|
||||||
|
ToFrame = AnimationSystem_CalculateAnimationFrame(System, ToAnim, Transient);
|
||||||
|
ToLayerBuffers = PushArray(Transient, layer_led_buffer, ToFrame.LayersCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
||||||
|
{
|
||||||
|
assembly Assembly = Assemblies.Values[AssemblyIndex];
|
||||||
|
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
|
||||||
|
|
||||||
|
pattern_args PatternArgs = {};
|
||||||
|
PatternArgs.Assembly = Assembly;
|
||||||
|
PatternArgs.Transient = Transient;
|
||||||
|
PatternArgs.UserData = UserData;
|
||||||
|
|
||||||
|
led_buffer FromBuffer = RenderAnimationToLedBuffer(System,
|
||||||
|
PatternArgs,
|
||||||
|
FromFrame,
|
||||||
|
FromLayerBuffers,
|
||||||
|
AssemblyLedBuffer,
|
||||||
|
Patterns,
|
||||||
|
Transient);
|
||||||
|
led_buffer ConsolidatedBuffer = FromBuffer;
|
||||||
|
|
||||||
|
if (ToAnim) {
|
||||||
|
led_buffer ToBuffer = RenderAnimationToLedBuffer(System,
|
||||||
|
PatternArgs,
|
||||||
|
ToFrame,
|
||||||
|
ToLayerBuffers,
|
||||||
|
AssemblyLedBuffer,
|
||||||
|
Patterns,
|
||||||
|
Transient);
|
||||||
|
|
||||||
|
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
|
||||||
|
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LedBuffer_Copy(ConsolidatedBuffer, AssemblyLedBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||||
|
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, ActiveAnim, Transient);
|
||||||
|
|
||||||
|
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
||||||
|
{
|
||||||
|
assembly Assembly = Assemblies.Values[AssemblyIndex];
|
||||||
|
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
|
||||||
|
|
||||||
|
pattern_args PatternArgs = {};
|
||||||
|
PatternArgs.Assembly = Assembly;
|
||||||
|
PatternArgs.Transient = Transient;
|
||||||
|
PatternArgs.UserData = UserData;
|
||||||
|
|
||||||
|
led_buffer AccBuffer = RenderAnimationToLedBuffer(System,
|
||||||
|
PatternArgs,
|
||||||
|
CurrFrame,
|
||||||
|
LayerBuffers,
|
||||||
|
AssemblyLedBuffer,
|
||||||
|
Patterns,
|
||||||
|
Transient);
|
||||||
|
LedBuffer_Copy(AccBuffer, AssemblyLedBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
System->LastUpdatedFrame = System->CurrentFrame;
|
System->LastUpdatedFrame = System->CurrentFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@ struct assembly_array
|
||||||
assembly* Values;
|
assembly* Values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef pixel led_blend_proc(pixel A, pixel B, u8* UserData);
|
||||||
|
|
||||||
internal led_buffer*
|
internal led_buffer*
|
||||||
LedSystemGetBuffer(led_system* System, u32 Index)
|
LedSystemGetBuffer(led_system* System, u32 Index)
|
||||||
{
|
{
|
||||||
|
@ -178,6 +180,44 @@ LedBuffer_ClearToBlack(led_buffer* Buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
LedBuffer_Copy(led_buffer From, led_buffer* To)
|
||||||
|
{
|
||||||
|
Assert(From.LedCount == To->LedCount);
|
||||||
|
u32 LedCount = To->LedCount;
|
||||||
|
for (u32 i = 0; i < LedCount; i++)
|
||||||
|
{
|
||||||
|
To->Colors[i] = From.Colors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
LedBuffer_Blend(led_buffer A, led_buffer B, led_buffer* Dest, led_blend_proc* BlendProc, u8* UserData)
|
||||||
|
{
|
||||||
|
Assert(A.LedCount == B.LedCount);
|
||||||
|
Assert(Dest->LedCount == A.LedCount);
|
||||||
|
Assert(BlendProc);
|
||||||
|
|
||||||
|
u32 LedCount = Dest->LedCount;
|
||||||
|
for (u32 i = 0; i < LedCount; i++)
|
||||||
|
{
|
||||||
|
pixel PA = A.Colors[i];
|
||||||
|
pixel PB = B.Colors[i];
|
||||||
|
Dest->Colors[i] = BlendProc(PA, PB, UserData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal led_buffer
|
||||||
|
LedBuffer_CreateCopyCleared (led_buffer Buffer, gs_memory_arena* Arena)
|
||||||
|
{
|
||||||
|
led_buffer Result = {};
|
||||||
|
Result.LedCount = Buffer.LedCount;
|
||||||
|
Result.Positions = Buffer.Positions;
|
||||||
|
Result.Colors = PushArray(Arena, pixel, Buffer.LedCount);
|
||||||
|
LedBuffer_ClearToBlack(&Result);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
internal u32
|
internal u32
|
||||||
StripGenData_CountLeds(strip_gen_data Data)
|
StripGenData_CountLeds(strip_gen_data Data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,6 +62,14 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
||||||
GlobalDebugServices->Interface.RenderSculpture = true;
|
GlobalDebugServices->Interface.RenderSculpture = true;
|
||||||
|
|
||||||
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
|
PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent);
|
||||||
|
|
||||||
|
State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext);
|
||||||
|
|
||||||
|
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
|
||||||
|
|
||||||
|
ReloadStaticData(Context, GlobalDebugServices);
|
||||||
|
US_CustomInit(&State->UserSpaceDesc, State, Context);
|
||||||
|
|
||||||
{
|
{
|
||||||
// NOTE(pjs): This just sets up the default panel layout
|
// NOTE(pjs): This just sets up the default panel layout
|
||||||
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
|
panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context);
|
||||||
|
@ -83,13 +91,6 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
||||||
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, Context);
|
Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_AssemblyDebug, State, Context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext);
|
|
||||||
|
|
||||||
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
|
|
||||||
|
|
||||||
ReloadStaticData(Context, GlobalDebugServices);
|
|
||||||
US_CustomInit(&State->UserSpaceDesc, State, Context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UPDATE_AND_RENDER(UpdateAndRender)
|
UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
|
@ -105,7 +106,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
|
|
||||||
Editor_Update(State, Context, InputQueue);
|
Editor_Update(State, Context, InputQueue);
|
||||||
|
|
||||||
AnimationSystem_Update(&State->AnimationSystem);
|
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
|
||||||
if (AnimationSystem_NeedsRender(State->AnimationSystem))
|
if (AnimationSystem_NeedsRender(State->AnimationSystem))
|
||||||
{
|
{
|
||||||
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
|
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
|
||||||
|
|
|
@ -260,6 +260,10 @@ Win32SocketPeek(platform_socket* Socket)
|
||||||
{
|
{
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
|
case WSAECONNRESET:
|
||||||
|
{
|
||||||
|
}break;
|
||||||
|
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue