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);
|
||||
|
||||
AnimationArray_Push(&State->AnimationSystem.Animations, Anim0);
|
||||
BLState->AnimHandles[0] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim0);
|
||||
|
||||
animation Anim1 = {0};
|
||||
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);
|
||||
|
||||
AnimationArray_Push(&State->AnimationSystem.Animations, Anim1);
|
||||
BLState->AnimHandles[1] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim1);
|
||||
|
||||
animation Anim2 = {0};
|
||||
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);
|
||||
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;
|
||||
} // 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;
|
||||
|
||||
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 GreenString = MakeString("green");
|
||||
|
@ -207,15 +218,15 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
|
|||
u32 NameLen = CStringLength(Packet.AnimationFileName);
|
||||
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))
|
||||
{
|
||||
State->AnimationSystem.ActiveAnimationIndex = 1;
|
||||
State->AnimationSystem.ActiveFadeGroup.From.Index = 1;
|
||||
}
|
||||
else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen))
|
||||
{
|
||||
State->AnimationSystem.ActiveAnimationIndex = 2;
|
||||
State->AnimationSystem.ActiveFadeGroup.From.Index = 2;
|
||||
}
|
||||
|
||||
OutputDebugStringA("Received Pattern Packet\n");
|
||||
|
|
|
@ -70,6 +70,11 @@ struct blumen_lumen_state
|
|||
mic_listen_job_data MicListenJobData;
|
||||
|
||||
motor_packet LastKnownMotorState;
|
||||
|
||||
r64 TimeElapsed;
|
||||
|
||||
animation_handle AnimHandles[3];
|
||||
u32 CurrAnim;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ struct animation_timeline_state
|
|||
{
|
||||
frame_range VisibleRange;
|
||||
handle SelectedBlockHandle;
|
||||
animation_handle EditingAnimationHandle;
|
||||
u32 SelectedAnimationLayer;
|
||||
};
|
||||
|
||||
|
@ -33,22 +34,13 @@ GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range
|
|||
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)
|
||||
{
|
||||
animation_timeline_state* PanelState = Panel_GetStateStruct(Panel, animation_timeline_state);
|
||||
|
||||
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 &&
|
||||
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)
|
||||
{
|
||||
rect2 TimelineBounds;
|
||||
animation_handle EditingAnimationHandle;
|
||||
handle BlockHandle;
|
||||
frame_range VisibleRange;
|
||||
frame_range ClipRange;
|
||||
|
@ -133,7 +126,9 @@ OPERATION_RENDER_PROC(UpdateDragAnimationBlock)
|
|||
{
|
||||
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);
|
||||
u32 ClipInitialStartFrameXPosition = LerpR32(ClipInitialStartFrameXPercent,
|
||||
|
@ -237,7 +232,10 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
|
|||
{
|
||||
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);
|
||||
|
||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
|
||||
|
@ -245,29 +243,39 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
|
|||
&State->Modes,
|
||||
drag_animation_block_state);
|
||||
OpState->TimelineBounds = TimelineBounds;
|
||||
OpState->EditingAnimationHandle = Handle;
|
||||
OpState->BlockHandle = BlockHandle;
|
||||
OpState->VisibleRange = VisibleRange;
|
||||
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);
|
||||
|
||||
frame_range Range = ActiveAnim->PlayableRange;
|
||||
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;
|
||||
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;
|
||||
|
||||
handle NewBlockHandle = Animation_AddBlock(ActiveAnim, StartFrame, EndFrame, PatternHandle, Layer);
|
||||
|
||||
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[] = {
|
||||
{ KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand },
|
||||
{ KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand },
|
||||
};
|
||||
s32 AnimationTimeline_CommandsCount = 2;
|
||||
|
||||
|
@ -276,10 +284,17 @@ GSMetaTag(panel_type_animation_timeline);
|
|||
internal void
|
||||
AnimationTimeline_Init(panel* Panel, app_state* State, context Context)
|
||||
{
|
||||
animation_handle Handle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||
|
||||
// TODO: :FreePanelMemory
|
||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
||||
animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state);
|
||||
TimelineState->VisibleRange = ActiveAnim->PlayableRange;
|
||||
TimelineState->EditingAnimationHandle = Handle;
|
||||
|
||||
if (IsValid(Handle)) {
|
||||
animation_array Animations = State->AnimationSystem.Animations;
|
||||
animation* ActiveAnim = AnimationArray_GetSafe(Animations, Handle);
|
||||
TimelineState->VisibleRange = ActiveAnim->PlayableRange;
|
||||
}
|
||||
|
||||
Panel->StateMemory = StructToData(TimelineState, animation_timeline_state);
|
||||
}
|
||||
|
@ -481,92 +496,6 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range V
|
|||
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)
|
||||
{
|
||||
Assert(ReturningFrom->TypeIndex == PanelType_FileView);
|
||||
|
@ -581,28 +510,11 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
|
|||
animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, State->Patterns);
|
||||
NewAnim.FileInfo = AnimFile.FileInfo;
|
||||
|
||||
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
|
||||
animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||
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
|
||||
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
|
||||
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;
|
||||
gs_string TempString = PushString(State->Transient, 256);
|
||||
|
||||
// :FrameRange
|
||||
// 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;
|
||||
|
||||
|
@ -687,10 +603,9 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_
|
|||
}
|
||||
|
||||
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;
|
||||
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
||||
|
||||
ui_FillRect(Interface, Bounds, Interface->Style.PanelBG);
|
||||
|
||||
|
@ -698,38 +613,45 @@ LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* P
|
|||
rect2 LayerBounds = {0};
|
||||
LayerBounds.Min = Bounds.Min;
|
||||
LayerBounds.Max = LayerBounds.Min + LayerDim;
|
||||
for (u32 i = 0; i < ActiveAnim.Layers.Count; i++)
|
||||
|
||||
if (ActiveAnim)
|
||||
{
|
||||
anim_layer* Layer = ActiveAnim.Layers.Values + i;
|
||||
|
||||
if (ui_MouseClickedRect(*Interface, LayerBounds))
|
||||
for (u32 i = 0; i < ActiveAnim->Layers.Count; i++)
|
||||
{
|
||||
TimelineState->SelectedAnimationLayer = 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);
|
||||
}
|
||||
|
||||
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)
|
||||
TimeRange_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
|
||||
{
|
||||
ui_interface* Interface = &State->Interface;
|
||||
animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
||||
|
||||
// TODO(pjs): setting the timeline to show the entire range
|
||||
// of the current animation until I reimplement the range
|
||||
// slider bars
|
||||
// :FrameRange
|
||||
// frame_range ViewRange = TimelineState->VisibleRange;
|
||||
frame_range ViewRange = ActiveAnim.PlayableRange;
|
||||
frame_range ViewRange = {};
|
||||
if (ActiveAnim)
|
||||
{
|
||||
ViewRange = ActiveAnim->PlayableRange;
|
||||
}
|
||||
|
||||
handle SelectedBlockHandle = TimelineState->SelectedBlockHandle;
|
||||
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
|
||||
|
@ -737,30 +659,33 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
|||
// Animation Blocks
|
||||
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState);
|
||||
handle DragBlockHandle = {0};
|
||||
for (u32 i = 0; i < ActiveAnim.Blocks_.Count; i++)
|
||||
if (ActiveAnim)
|
||||
{
|
||||
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)
|
||||
for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++)
|
||||
{
|
||||
v4 BlockColor = BlackV4;
|
||||
if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == ActiveAnim.Blocks_.Generations[i])
|
||||
{
|
||||
BlockColor = PinkV4;
|
||||
}
|
||||
rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, ViewRange, Bounds, Interface->RenderBuffer);
|
||||
animation_block* AnimationBlockAt = ActiveAnim->Blocks_.Values + i;
|
||||
|
||||
if (PointIsInRect(BlockBounds, Interface->Mouse.Pos))
|
||||
// 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)
|
||||
{
|
||||
DragBlockHandle.Index = i;
|
||||
DragBlockHandle.Generation = ActiveAnim.Blocks_.Generations[i];
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -795,10 +720,10 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
|||
internal void
|
||||
AnimInfoView_SaveAnimFile (gs_const_string Path, app_state* State, context Context)
|
||||
{
|
||||
u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex;
|
||||
animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex];
|
||||
animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||
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)))
|
||||
{
|
||||
|
@ -816,24 +741,41 @@ PANEL_MODAL_OVERRIDE_CALLBACK(AnimInfoView_SaveAnimFileCallback)
|
|||
}
|
||||
|
||||
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* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem);
|
||||
|
||||
ui_interface* Interface = &State->Interface;
|
||||
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"));
|
||||
|
||||
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++)
|
||||
{
|
||||
animation Animation = AnimSystem->Animations.Values[i];
|
||||
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 = {};
|
||||
NewAnim.Name = PushString(State->AnimationSystem.Storage, 256);
|
||||
|
||||
u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||
State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex;
|
||||
animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim);
|
||||
State->AnimationSystem.ActiveFadeGroup.From = NewAnimHandle;
|
||||
}
|
||||
if (ui_Button(Interface, MakeString("Save")))
|
||||
if (ActiveAnim && ui_Button(Interface, MakeString("Save")))
|
||||
{
|
||||
// Save Animation File
|
||||
// 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
|
||||
u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex;
|
||||
animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex];
|
||||
animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From;
|
||||
animation ActiveAnimation = *AnimationArray_GetSafe(State->AnimationSystem.Animations, ActiveAnimHandle);
|
||||
|
||||
if (!ActiveAnimation.FileInfo.Path.Str)
|
||||
{
|
||||
|
@ -875,39 +817,46 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel
|
|||
}
|
||||
ui_EndRow(Interface);
|
||||
|
||||
ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name);
|
||||
|
||||
ui_Label(Interface, MakeString("Frame Range"));
|
||||
ui_BeginRow(Interface, 3);
|
||||
if (ActiveAnim)
|
||||
{
|
||||
ActiveAnim->PlayableRange.Min = ui_TextEntryU64(Interface, MakeString("StartFrame"), ActiveAnim->PlayableRange.Min);
|
||||
ActiveAnim->PlayableRange.Max = ui_TextEntryU64(Interface, MakeString("EndFrame"), ActiveAnim->PlayableRange.Max);
|
||||
|
||||
}
|
||||
ui_EndRow(Interface);
|
||||
|
||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, TimelineState->SelectedBlockHandle);
|
||||
if (SelectedBlock)
|
||||
{
|
||||
animation_pattern BlockPattern = Patterns_GetPattern(State->Patterns, SelectedBlock->AnimationProcHandle);
|
||||
ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name);
|
||||
|
||||
ui_Label(Interface, MakeString("Frame Range"));
|
||||
ui_BeginRow(Interface, 3);
|
||||
ui_Label(Interface, MakeString("Selected Pattern"));
|
||||
//if (ui_BeginLabeledDropdown(Interface, MakeString("Selected Pattern"), MakeString(BlockPattern.Name, BlockPattern.NameLength)))
|
||||
if (ui_BeginDropdown(Interface, MakeString(BlockPattern.Name, BlockPattern.NameLength)))
|
||||
{
|
||||
for (u32 i = 0; i < State->Patterns.Count; i++)
|
||||
ActiveAnim->PlayableRange.Min = ui_TextEntryU64(Interface, MakeString("StartFrame"), ActiveAnim->PlayableRange.Min);
|
||||
ActiveAnim->PlayableRange.Max = ui_TextEntryU64(Interface, MakeString("EndFrame"), ActiveAnim->PlayableRange.Max);
|
||||
|
||||
}
|
||||
ui_EndRow(Interface);
|
||||
|
||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, TimelineState->SelectedBlockHandle);
|
||||
if (SelectedBlock)
|
||||
{
|
||||
animation_pattern BlockPattern = Patterns_GetPattern(State->Patterns, SelectedBlock->AnimationProcHandle);
|
||||
|
||||
ui_BeginRow(Interface, 3);
|
||||
ui_Label(Interface, MakeString("Selected Pattern"));
|
||||
//if (ui_BeginLabeledDropdown(Interface, MakeString("Selected Pattern"), MakeString(BlockPattern.Name, BlockPattern.NameLength)))
|
||||
if (ui_BeginDropdown(Interface, MakeString(BlockPattern.Name, BlockPattern.NameLength)))
|
||||
{
|
||||
animation_pattern Pattern = State->Patterns.Values[i];
|
||||
if (ui_Button(Interface, MakeString(Pattern.Name, Pattern.NameLength)))
|
||||
for (u32 i = 0; i < State->Patterns.Count; i++)
|
||||
{
|
||||
SelectedBlock->AnimationProcHandle = Patterns_IndexToHandle(i);
|
||||
animation_pattern Pattern = State->Patterns.Values[i];
|
||||
if (ui_Button(Interface, MakeString(Pattern.Name, Pattern.NameLength)))
|
||||
{
|
||||
SelectedBlock->AnimationProcHandle = Patterns_IndexToHandle(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_EndLabeledDropdown(Interface);
|
||||
}
|
||||
|
||||
if (ui_Button(Interface, MakeString("+ Add Block")))
|
||||
{
|
||||
AnimationTimeline_AddAnimationBlockCommand(TimelineState, State, Context);
|
||||
}
|
||||
ui_EndLabeledDropdown(Interface);
|
||||
}
|
||||
|
||||
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* 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});
|
||||
|
||||
rect2 TimelineBounds, InfoBounds;
|
||||
|
@ -940,10 +898,10 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
|
|||
RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds);
|
||||
|
||||
PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context);
|
||||
FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context);
|
||||
LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context);
|
||||
TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context);
|
||||
AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context);
|
||||
FrameCount_Render(TimelineState, ActiveAnim, FrameCountBounds, RenderBuffer, State, Context);
|
||||
LayerList_Render(TimelineState, ActiveAnim, LayersBounds, Panel, RenderBuffer, State, Context);
|
||||
TimeRange_Render(TimelineState, ActiveAnim, TimeRangeBounds, RenderBuffer, State, Context);
|
||||
AnimInfoView_Render(TimelineState, ActiveAnim, InfoBounds, Panel, RenderBuffer, State, Context);
|
||||
}
|
||||
|
||||
#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H
|
||||
|
|
|
@ -16,6 +16,8 @@ struct file_view_state
|
|||
file_view_mode Mode;
|
||||
|
||||
gs_string WorkingDirectory;
|
||||
gs_string DisplayDirectory;
|
||||
|
||||
gs_memory_arena FileNamesArena;
|
||||
gs_file_info_array FileNames;
|
||||
|
||||
|
@ -55,6 +57,7 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
|||
Assert(LastChar == '\\' || LastChar == '/');
|
||||
ClearArena(&State->FileNamesArena);
|
||||
|
||||
|
||||
gs_string SanitizedDir = PushString(Context.ThreadContext.Transient, WorkingDirectory.Length + 2);
|
||||
SanitizePath(WorkingDirectory, &SanitizedDir, Context.ThreadContext.Transient);
|
||||
if (SanitizedDir.Str[SanitizedDir.Length - 1] != '\\')
|
||||
|
@ -62,6 +65,8 @@ FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_stat
|
|||
AppendPrintF(&SanitizedDir, "\\");
|
||||
}
|
||||
|
||||
gs_const_string SanitizedDisplayDir = SanitizedDir.ConstString;
|
||||
|
||||
gs_file_info NewWorkingDir = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDir.ConstString);
|
||||
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
|
||||
// in some cases. Shouldn't be a problem but it is unnecessary
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -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_BeginRow(&State->Interface, 3);
|
||||
{
|
||||
if (FileViewState->Mode == FileViewMode_Save)
|
||||
{
|
||||
if (ui_Button(&State->Interface, MakeString("Save")))
|
||||
{
|
||||
if (!FileViewState->SelectedFile.Path.Str)
|
||||
{
|
||||
FileViewState->SelectedFile.Path = FileViewState->DisplayDirectory.ConstString;
|
||||
}
|
||||
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
}
|
||||
}
|
||||
|
@ -128,11 +139,11 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
|||
ui_EndRow(&State->Interface);
|
||||
|
||||
// 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
|
||||
// otherwise update the filter string
|
||||
gs_string Pwd = FileViewState->WorkingDirectory;
|
||||
gs_string Pwd = FileViewState->DisplayDirectory;
|
||||
char LastChar = Pwd.Str[Pwd.Length - 1];
|
||||
if (LastChar == '\\' || LastChar == '/')
|
||||
{
|
||||
|
@ -163,9 +174,9 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
|||
}
|
||||
else
|
||||
{
|
||||
FileViewState->SelectedFile = File;
|
||||
switch (FileViewState->Mode)
|
||||
{
|
||||
FileViewState->SelectedFile = File;
|
||||
case FileViewMode_Load:
|
||||
{
|
||||
FileView_Exit_(Panel, State, Context);
|
||||
|
|
|
@ -46,9 +46,7 @@ enum blend_mode
|
|||
BlendMode_Count,
|
||||
};
|
||||
|
||||
// TODO(pjs): Add Opacity to this
|
||||
typedef pixel led_blend_proc(pixel PixelA, pixel PixelB);
|
||||
|
||||
// TODO(pjs): This really doesn't belong here
|
||||
global gs_const_string BlendModeStrings[] = {
|
||||
ConstString("Overwrite"),
|
||||
ConstString("Add"),
|
||||
|
@ -86,6 +84,18 @@ struct animation
|
|||
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
|
||||
{
|
||||
animation* Values;
|
||||
|
@ -101,7 +111,9 @@ struct animation_layer_frame
|
|||
animation_block NextHot;
|
||||
bool HasNextHot;
|
||||
|
||||
r32 HotOpacity;
|
||||
r32 NextHotOpacity;
|
||||
|
||||
blend_mode BlendMode;
|
||||
};
|
||||
|
||||
// NOTE(pjs): This is an evaluated frame - across all layers in an
|
||||
|
@ -112,6 +124,27 @@ struct animation_frame
|
|||
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_BLOCKS_MAX 128
|
||||
struct animation_system
|
||||
|
@ -119,10 +152,14 @@ struct animation_system
|
|||
gs_memory_arena* Storage;
|
||||
animation_array Animations;
|
||||
|
||||
animation_repeat_mode RepeatMode;
|
||||
|
||||
// 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
|
||||
// panel
|
||||
u32 ActiveAnimationIndex;
|
||||
animation_handle ActiveAnimationHandle_;
|
||||
animation_fade_group ActiveFadeGroup;
|
||||
|
||||
s32 CurrentFrame;
|
||||
s32 LastUpdatedFrame;
|
||||
r32 SecondsPerFrame;
|
||||
|
@ -214,7 +251,7 @@ Patterns_Create(gs_memory_arena* Arena, s32 CountMax)
|
|||
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
|
||||
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;
|
||||
}
|
||||
|
||||
internal u32
|
||||
internal animation_handle
|
||||
AnimationArray_Push(animation_array* Array, animation Value)
|
||||
{
|
||||
Assert(Array->Count < Array->CountMax);
|
||||
u32 Index = Array->Count++;
|
||||
Array->Values[Index] = Value;
|
||||
return Index;
|
||||
animation_handle Result = {0};
|
||||
Result.Index = Array->Count++;
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
struct animation_system_desc
|
||||
|
@ -499,29 +599,38 @@ AnimationSystem_Init(animation_system_desc Desc)
|
|||
Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount);
|
||||
Result.SecondsPerFrame = Desc.SecondsPerFrame;
|
||||
|
||||
Clear(&Result.ActiveFadeGroup.From);
|
||||
Clear(&Result.ActiveFadeGroup.To);
|
||||
Result.ActiveFadeGroup.FadeElapsed = 0;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal animation*
|
||||
AnimationSystem_GetActiveAnimation(animation_system* System)
|
||||
{
|
||||
// TODO(pjs): need a way to specify the active animation
|
||||
return System->Animations.Values + System->ActiveAnimationIndex;
|
||||
return AnimationArray_Get(System->Animations, System->ActiveFadeGroup.From);
|
||||
}
|
||||
|
||||
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};
|
||||
Result.LayersCount = ActiveAnim->Layers.Count;
|
||||
Result.LayersCount = Animation->Layers.Count;
|
||||
Result.Layers = PushArray(Arena, 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))
|
||||
{
|
||||
|
@ -548,12 +657,12 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
|||
frame_range BlendRange = {};
|
||||
BlendRange.Min = Layer->NextHot.Range.Min;
|
||||
BlendRange.Max = Layer->Hot.Range.Max;
|
||||
Layer->HotOpacity = 1.0f - FrameToPercentRange(System->CurrentFrame, BlendRange);
|
||||
Layer->NextHotOpacity = FrameToPercentRange(System->CurrentFrame, BlendRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
Layer->Hot = Block;
|
||||
Layer->HotOpacity = 1.0f;
|
||||
Layer->NextHotOpacity = 0.0f;
|
||||
Layer->HasHot = true;
|
||||
}
|
||||
}
|
||||
|
@ -563,18 +672,34 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
|||
}
|
||||
|
||||
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);
|
||||
if (System->TimelineShouldAdvance) {
|
||||
// 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
|
||||
System->CurrentFrame += 1;
|
||||
|
||||
// Loop back to the beginning
|
||||
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
|
||||
// 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
|
||||
System->CurrentFrame += 1;
|
||||
|
||||
// Loop back to the beginning
|
||||
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
|
||||
{
|
||||
switch (System->RepeatMode)
|
||||
{
|
||||
System->CurrentFrame = 0;
|
||||
case AnimationRepeat_Single:
|
||||
{
|
||||
System->CurrentFrame = 0;
|
||||
}break;
|
||||
|
||||
case AnimationRepeat_Loop:
|
||||
{
|
||||
// TODO(pjs):
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,25 +6,27 @@
|
|||
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
|
||||
|
||||
internal pixel
|
||||
LedBlend_Overwrite(pixel PixelA, pixel PixelB)
|
||||
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData)
|
||||
{
|
||||
return PixelB;
|
||||
}
|
||||
|
||||
internal pixel
|
||||
LedBlend_Overwrite(pixel PixelA, pixel PixelB, r32 Opacity)
|
||||
LedBlend_Lerp(pixel PixelA, pixel PixelB, u8* UserData)
|
||||
{
|
||||
r32 BOpacity = *(r32*)UserData;
|
||||
|
||||
pixel Result = {};
|
||||
|
||||
r32 BOpacity = 1.0f - Opacity;
|
||||
Result.R = (u8)((PixelA.R * Opacity) + (PixelB.R * BOpacity));
|
||||
Result.G = (u8)((PixelA.G * Opacity) + (PixelB.G * BOpacity));
|
||||
Result.B = (u8)((PixelA.B * Opacity) + (PixelB.B * BOpacity));
|
||||
r32 AOpacity = 1.0f - BOpacity;
|
||||
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
|
||||
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
|
||||
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal pixel
|
||||
LedBlend_Add(pixel PixelA, pixel PixelB)
|
||||
LedBlend_Add(pixel PixelA, pixel PixelB, u8* UserData)
|
||||
{
|
||||
pixel Result = {};
|
||||
|
||||
|
@ -40,7 +42,7 @@ LedBlend_Add(pixel PixelA, pixel PixelB)
|
|||
}
|
||||
|
||||
internal pixel
|
||||
LedBlend_Multiply(pixel PixelA, pixel PixelB)
|
||||
LedBlend_Multiply(pixel PixelA, pixel PixelB, u8* UserData)
|
||||
{
|
||||
pixel Result = {};
|
||||
|
||||
|
@ -60,7 +62,7 @@ LedBlend_Multiply(pixel PixelA, pixel PixelB)
|
|||
}
|
||||
|
||||
internal pixel
|
||||
LedBlend_Overlay(pixel PixelA, pixel PixelB)
|
||||
LedBlend_Overlay(pixel PixelA, pixel PixelB, u8* UserData)
|
||||
{
|
||||
pixel Result = {};
|
||||
return Result;
|
||||
|
@ -80,15 +82,110 @@ LedBlend_GetProc(blend_mode BlendMode)
|
|||
return Result;
|
||||
}
|
||||
|
||||
struct pattern_args
|
||||
{
|
||||
assembly Assembly;
|
||||
gs_memory_arena* Transient;
|
||||
u8* UserData;
|
||||
};
|
||||
|
||||
internal void
|
||||
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array Patterns, gs_memory_arena* Transient,
|
||||
u8* UserData)
|
||||
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs)
|
||||
{
|
||||
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
|
||||
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// NOTE(pjs): This mirrors animation_layer_frame to account
|
||||
// for overlapping
|
||||
struct layer_led_buffer
|
||||
{
|
||||
led_buffer HotBuffer;
|
||||
led_buffer NextHotBuffer;
|
||||
};
|
||||
|
||||
internal led_buffer
|
||||
RenderAnimationToLedBuffer (animation_system* System,
|
||||
pattern_args PatternArgs,
|
||||
animation_frame CurrFrame,
|
||||
layer_led_buffer* LayerBuffers,
|
||||
led_buffer* AssemblyLedBuffer,
|
||||
animation_pattern_array Patterns,
|
||||
gs_memory_arena* Transient)
|
||||
{
|
||||
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||
|
||||
// Create the LayerLEDBuffers
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
layer_led_buffer TempBuffer = {};
|
||||
|
||||
if (CurrFrame.Layers[Layer].HasHot)
|
||||
{
|
||||
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||
|
||||
if (CurrFrame.Layers[Layer].HasNextHot)
|
||||
{
|
||||
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
||||
}
|
||||
}
|
||||
|
||||
LayerBuffers[Layer] = TempBuffer;
|
||||
}
|
||||
|
||||
// Render Each layer's block to the appropriate temp buffer
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
||||
if (LayerFrame.HasHot)
|
||||
{
|
||||
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
|
||||
animation_block Block = LayerFrame.Hot;
|
||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs);
|
||||
}
|
||||
|
||||
if (LayerFrame.HasNextHot)
|
||||
{
|
||||
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
||||
animation_block Block = LayerFrame.NextHot;
|
||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs);
|
||||
}
|
||||
}
|
||||
|
||||
// Blend together any layers that have a hot and next hot buffer
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
||||
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
|
||||
if (LayerFrame.HasNextHot)
|
||||
{
|
||||
LedBuffer_Blend(LayerBuffer.HotBuffer,
|
||||
LayerBuffer.NextHotBuffer,
|
||||
&LayerBuffer.HotBuffer,
|
||||
LedBlend_Lerp,
|
||||
(u8*)&LayerFrame.NextHotOpacity);
|
||||
}
|
||||
}
|
||||
|
||||
// Consolidate Temp Buffers back into AssemblyLedBuffer
|
||||
// We do this in reverse order so that they go from top to bottom
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
if (CurrFrame.Layers[Layer].HasHot)
|
||||
{
|
||||
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
|
||||
LedBuffer_Blend(AccBuffer,
|
||||
LayerBuffers[Layer].HotBuffer,
|
||||
&AccBuffer,
|
||||
Blend,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
return AccBuffer;
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -101,100 +198,85 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
|||
s32 CurrentFrame = System->CurrentFrame;
|
||||
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
|
||||
|
||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient);
|
||||
#if 1
|
||||
animation_array Animations = System->Animations;
|
||||
animation_fade_group FadeGroup = System->ActiveFadeGroup;
|
||||
|
||||
// NOTE(pjs): This mirrors animation_layer_frame to account
|
||||
// for overlapping
|
||||
struct layer_led_buffer
|
||||
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)
|
||||
{
|
||||
led_buffer HotBuffer;
|
||||
led_buffer NextHotBuffer;
|
||||
};
|
||||
|
||||
layer_led_buffer* LayerBuffers = PushArray(Transient, layer_led_buffer, CurrFrame.LayersCount);
|
||||
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);
|
||||
assembly Assembly = Assemblies.Values[AssemblyIndex];
|
||||
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
|
||||
|
||||
// Create the LayerLEDBuffers
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
layer_led_buffer TempBuffer = {};
|
||||
if (CurrFrame.Layers[Layer].HasHot)
|
||||
{
|
||||
TempBuffer.HotBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
||||
TempBuffer.HotBuffer.Positions = AssemblyLedBuffer->Positions;
|
||||
TempBuffer.HotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
|
||||
LedBuffer_ClearToBlack(&TempBuffer.HotBuffer);
|
||||
}
|
||||
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);
|
||||
|
||||
if (CurrFrame.Layers[Layer].HasNextHot)
|
||||
{
|
||||
TempBuffer.NextHotBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
||||
TempBuffer.NextHotBuffer.Positions = AssemblyLedBuffer->Positions;
|
||||
TempBuffer.NextHotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
|
||||
LedBuffer_ClearToBlack(&TempBuffer.NextHotBuffer);
|
||||
}
|
||||
|
||||
LayerBuffers[Layer] = TempBuffer;
|
||||
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
|
||||
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
|
||||
}
|
||||
|
||||
// Render Each layer's block to the appropriate temp buffer
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
||||
if (LayerFrame.HasHot)
|
||||
{
|
||||
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
|
||||
animation_block Block = LayerFrame.Hot;
|
||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
|
||||
}
|
||||
|
||||
if (LayerFrame.HasNextHot)
|
||||
{
|
||||
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
||||
animation_block Block = LayerFrame.NextHot;
|
||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData);
|
||||
}
|
||||
}
|
||||
|
||||
// Blend together any layers that have a hot and next hot buffer
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
||||
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
|
||||
if (LayerFrame.HasNextHot)
|
||||
{
|
||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
||||
{
|
||||
pixel A = LayerBuffer.HotBuffer.Colors[LED];
|
||||
pixel B = LayerBuffer.NextHotBuffer.Colors[LED];
|
||||
LayerBuffer.HotBuffer.Colors[LED] = LedBlend_Overwrite(A, B, LayerFrame.HotOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consolidate Temp Buffers
|
||||
// We do this in reverse order so that they go from top to bottom
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
if (CurrFrame.Layers[Layer].HasHot)
|
||||
{
|
||||
led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode);
|
||||
Assert(Blend != 0);
|
||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
||||
{
|
||||
pixel A = AssemblyLedBuffer->Colors[LED];
|
||||
pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED];
|
||||
AssemblyLedBuffer->Colors[LED] = Blend(A, B);
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,8 @@ struct assembly_array
|
|||
assembly* Values;
|
||||
};
|
||||
|
||||
typedef pixel led_blend_proc(pixel A, pixel B, u8* UserData);
|
||||
|
||||
internal led_buffer*
|
||||
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
|
||||
StripGenData_CountLeds(strip_gen_data Data)
|
||||
{
|
||||
|
|
|
@ -62,6 +62,14 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
GlobalDebugServices->Interface.RenderSculpture = true;
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext);
|
||||
|
||||
State->UserSpaceDesc = BlumenLumen_UserSpaceCreate();
|
||||
|
||||
ReloadStaticData(Context, GlobalDebugServices);
|
||||
US_CustomInit(&State->UserSpaceDesc, State, Context);
|
||||
}
|
||||
|
||||
UPDATE_AND_RENDER(UpdateAndRender)
|
||||
|
@ -105,7 +106,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
|
||||
Editor_Update(State, Context, InputQueue);
|
||||
|
||||
AnimationSystem_Update(&State->AnimationSystem);
|
||||
AnimationSystem_Update(&State->AnimationSystem, Context->DeltaTime);
|
||||
if (AnimationSystem_NeedsRender(State->AnimationSystem))
|
||||
{
|
||||
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
|
||||
|
|
|
@ -260,6 +260,10 @@ Win32SocketPeek(platform_socket* Socket)
|
|||
{
|
||||
}break;
|
||||
|
||||
case WSAECONNRESET:
|
||||
{
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue