Implemented dragging animation clips
This commit is contained in:
parent
d112b01e79
commit
e21da76a2b
|
@ -1,5 +1,4 @@
|
||||||
// TODO
|
// TODO
|
||||||
// [] - animation system start and end time
|
|
||||||
// [] - animation blending
|
// [] - animation blending
|
||||||
// [] - delete a layer
|
// [] - delete a layer
|
||||||
// [] - will need a way to create an empty layer
|
// [] - will need a way to create an empty layer
|
||||||
|
@ -10,6 +9,7 @@ typedef ANIMATION_PROC(animation_proc);
|
||||||
|
|
||||||
struct animation_block
|
struct animation_block
|
||||||
{
|
{
|
||||||
|
// TODO(Peter): Should we change this to frames??
|
||||||
r32 StartTime;
|
r32 StartTime;
|
||||||
r32 EndTime;
|
r32 EndTime;
|
||||||
animation_proc* Proc;
|
animation_proc* Proc;
|
||||||
|
@ -20,15 +20,15 @@ struct animation_block
|
||||||
struct animation_block_handle
|
struct animation_block_handle
|
||||||
{
|
{
|
||||||
s32 Index;
|
s32 Index;
|
||||||
// NOTE(Peter): Zero is invalid
|
// NOTE(Peter): Zero is invalid
|
||||||
u32 Generation;
|
u32 Generation;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct animation_block_entry
|
struct animation_block_entry
|
||||||
{
|
{
|
||||||
u32 Generation;
|
u32 Generation;
|
||||||
animation_block Block;
|
animation_block Block;
|
||||||
free_list Free;
|
free_list Free;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ANIMATION_SYSTEM_LAYERS_MAX 128
|
#define ANIMATION_SYSTEM_LAYERS_MAX 128
|
||||||
|
@ -37,17 +37,17 @@ struct animation_system
|
||||||
{
|
{
|
||||||
animation_block_entry Blocks[ANIMATION_SYSTEM_BLOCKS_MAX];
|
animation_block_entry Blocks[ANIMATION_SYSTEM_BLOCKS_MAX];
|
||||||
free_list FreeList;
|
free_list FreeList;
|
||||||
u32 BlocksCount;
|
u32 BlocksCount;
|
||||||
|
|
||||||
r32 Time;
|
r32 Time;
|
||||||
s32 LastUpdatedFrame;
|
s32 LastUpdatedFrame;
|
||||||
r32 SecondsPerFrame;
|
r32 SecondsPerFrame;
|
||||||
|
|
||||||
b32 TimelineShouldAdvance;
|
b32 TimelineShouldAdvance;
|
||||||
|
|
||||||
// :Temporary
|
// :Temporary
|
||||||
r32 AnimationStart;
|
r32 AnimationStart;
|
||||||
r32 AnimationEnd;
|
r32 AnimationEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
internal b32
|
internal b32
|
||||||
|
@ -80,10 +80,30 @@ AnimationBlockIsFree(animation_block_entry Entry)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal animation_block_entry*
|
||||||
|
GetEntryAtIndex(u32 Index, animation_system* System)
|
||||||
|
{
|
||||||
|
Assert(Index < System->BlocksCount);
|
||||||
|
animation_block_entry* Result = System->Blocks + Index;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal animation_block*
|
||||||
|
GetAnimationBlockWithHandle(animation_block_handle Handle, animation_system* System)
|
||||||
|
{
|
||||||
|
animation_block* Result = 0;
|
||||||
|
animation_block_entry* Entry = GetEntryAtIndex(Handle.Index, System);
|
||||||
|
if (Entry && Entry->Generation == Handle.Generation)
|
||||||
|
{
|
||||||
|
Result = &Entry->Block;
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
internal animation_block_handle
|
internal animation_block_handle
|
||||||
AddAnimationBlock(animation_block Block, animation_system* System)
|
AddAnimationBlock(animation_block Block, animation_system* System)
|
||||||
{
|
{
|
||||||
animation_block_handle Result = {0};
|
animation_block_handle Result = {0};
|
||||||
|
|
||||||
if (System->FreeList.Next != 0
|
if (System->FreeList.Next != 0
|
||||||
&& System->FreeList.Next != &System->FreeList)
|
&& System->FreeList.Next != &System->FreeList)
|
||||||
|
@ -94,21 +114,23 @@ animation_block_handle Result = {0};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Assert(System->BlocksCount < ANIMATION_SYSTEM_BLOCKS_MAX);
|
Assert(System->BlocksCount < ANIMATION_SYSTEM_BLOCKS_MAX);
|
||||||
Result.Index = System->BlocksCount++;
|
Result.Index = System->BlocksCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.Generation = ++System->Blocks[Result.Index].Generation;
|
animation_block_entry* Entry = GetEntryAtIndex(Result.Index, System);
|
||||||
|
Entry->Generation += 1;
|
||||||
|
Result.Generation = Entry->Generation;
|
||||||
System->Blocks[Result.Index].Block = Block;
|
System->Blocks[Result.Index].Block = Block;
|
||||||
System->Blocks[Result.Index].Free.Next = 0;
|
System->Blocks[Result.Index].Free.Next = 0;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
RemoveAnimationBlock(animation_block_handle Handle, animation_system* System)
|
RemoveAnimationBlock(animation_block_handle Handle, animation_system* System)
|
||||||
{
|
{
|
||||||
animation_block_entry* Entry = System->Blocks + Handle.Index;
|
animation_block_entry* Entry = GetEntryAtIndex(Handle.Index, System);
|
||||||
|
|
||||||
// NOTE(Peter): I'm pretty sure this doesn't need to be an assert but at the moment, there
|
// NOTE(Peter): I'm pretty sure this doesn't need to be an assert but at the moment, there
|
||||||
// is no reason why we shouldn't always be able to remove an entry when we request it.
|
// is no reason why we shouldn't always be able to remove an entry when we request it.
|
||||||
|
@ -123,5 +145,3 @@ RemoveAnimationBlock(animation_block_handle Handle, animation_system* System)
|
||||||
Entry->Free.Next = System->FreeList.Next;
|
Entry->Free.Next = System->FreeList.Next;
|
||||||
System->FreeList.Next = &Entry->Free;
|
System->FreeList.Next = &Entry->Free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,13 +70,15 @@ RenderPanel(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax,
|
||||||
|
|
||||||
v2 FooterMin = PanelMin;
|
v2 FooterMin = PanelMin;
|
||||||
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25};
|
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25};
|
||||||
v2 PanelViewMin = v2{PanelMin.x, FooterMax.y};
|
rect PanelBounds = rect{
|
||||||
v2 PanelViewMax = PanelMax;
|
v2{PanelMin.x, FooterMax.y},
|
||||||
|
PanelMax,
|
||||||
|
};
|
||||||
|
|
||||||
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
|
panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex];
|
||||||
|
|
||||||
|
|
||||||
Definition.Render(*Panel, PanelMin, PanelMax, RenderBuffer, State, Context, Mouse);
|
Definition.Render(*Panel, PanelBounds, RenderBuffer, State, Context, Mouse);
|
||||||
|
|
||||||
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
|
||||||
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, State->Interface, Mouse);
|
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, State->Interface, Mouse);
|
||||||
|
|
|
@ -206,7 +206,7 @@ typedef PANEL_INIT_PROC(panel_init_proc);
|
||||||
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel)
|
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel)
|
||||||
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
|
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
|
||||||
|
|
||||||
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
#define PANEL_RENDER_PROC(name) void name(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
|
||||||
typedef PANEL_RENDER_PROC(panel_render_proc);
|
typedef PANEL_RENDER_PROC(panel_render_proc);
|
||||||
|
|
||||||
#include "panels/foldhaus_panel_sculpture_view.h"
|
#include "panels/foldhaus_panel_sculpture_view.h"
|
||||||
|
|
|
@ -117,8 +117,7 @@ input_command UniverseViewCommands [] = {
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView)
|
FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView)
|
||||||
{
|
{
|
||||||
operation_mode* UniverseViewMode = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommands);
|
operation_mode* UniverseViewMode = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommands, RenderUniverseView);
|
||||||
UniverseViewMode->Render = RenderUniverseView;
|
|
||||||
|
|
||||||
// State Setup
|
// State Setup
|
||||||
universe_view_operation_state* OpState = CreateOperationState(UniverseViewMode,
|
universe_view_operation_state* OpState = CreateOperationState(UniverseViewMode,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
typedef struct operation_mode operation_mode;
|
typedef struct operation_mode operation_mode;
|
||||||
|
|
||||||
|
#define OPERATION_STATE_DEF(name) struct name
|
||||||
|
|
||||||
#define OPERATION_RENDER_PROC(name) void name(app_state* State, render_command_buffer* RenderBuffer, operation_mode Operation, mouse_state Mouse)
|
#define OPERATION_RENDER_PROC(name) void name(app_state* State, render_command_buffer* RenderBuffer, operation_mode Operation, mouse_state Mouse)
|
||||||
typedef OPERATION_RENDER_PROC(operation_render_proc);
|
typedef OPERATION_RENDER_PROC(operation_render_proc);
|
||||||
|
|
||||||
|
@ -23,8 +25,10 @@ struct operation_mode_system
|
||||||
};
|
};
|
||||||
|
|
||||||
internal operation_mode*
|
internal operation_mode*
|
||||||
ActivateOperationMode (operation_mode_system* System)
|
ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc)
|
||||||
{
|
{
|
||||||
|
operation_mode* Result = 0;
|
||||||
|
|
||||||
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
|
Assert(System->ActiveModesCount < OPERATION_MODES_MAX);
|
||||||
s32 ModeIndex = System->ActiveModesCount++;
|
s32 ModeIndex = System->ActiveModesCount++;
|
||||||
|
|
||||||
|
@ -33,16 +37,18 @@ ActivateOperationMode (operation_mode_system* System)
|
||||||
operation_mode NewMode = {};
|
operation_mode NewMode = {};
|
||||||
System->ActiveModes[ModeIndex] = NewMode;
|
System->ActiveModes[ModeIndex] = NewMode;
|
||||||
|
|
||||||
return &System->ActiveModes[ModeIndex];
|
Result = &System->ActiveModes[ModeIndex];
|
||||||
|
Result->Render = RenderProc;
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ActivateOperationModeWithCommands(sys, cmds) \
|
#define ActivateOperationModeWithCommands(sys, cmds, render) \
|
||||||
ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0])));
|
ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0])), render);
|
||||||
|
|
||||||
internal operation_mode*
|
internal operation_mode*
|
||||||
ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount)
|
ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount, operation_render_proc* RenderProc)
|
||||||
{
|
{
|
||||||
operation_mode* NewMode = ActivateOperationMode(System);
|
operation_mode* NewMode = ActivateOperationMode(System, RenderProc);
|
||||||
|
|
||||||
InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena);
|
InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena);
|
||||||
for (s32 i = 0; i < CommandsCount; i++)
|
for (s32 i = 0; i < CommandsCount; i++)
|
||||||
|
|
|
@ -7,6 +7,23 @@
|
||||||
// [] - displaying multiple layers
|
// [] - displaying multiple layers
|
||||||
// [] -
|
// [] -
|
||||||
|
|
||||||
|
inline r32
|
||||||
|
GetTimeFromPointInAnimationPanel(v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame)
|
||||||
|
{
|
||||||
|
r32 StartFrameTime = (r32)StartFrame * SecondsPerFrame;
|
||||||
|
r32 EndFrameTime = (r32)EndFrame * SecondsPerFrame;
|
||||||
|
r32 TimeAtPoint = GSRemap(Point.x, PanelBounds.Min.x, PanelBounds.Max.x, StartFrameTime, EndFrameTime);
|
||||||
|
return TimeAtPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s32
|
||||||
|
GetFrameFromPointInAnimationPanel (v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame)
|
||||||
|
{
|
||||||
|
r32 TimeAtPoint = GetTimeFromPointInAnimationPanel(Point, PanelBounds, StartFrame, EndFrame, SecondsPerFrame);
|
||||||
|
s32 FrameAtPoint = (s32)(TimeAtPoint * SecondsPerFrame);
|
||||||
|
return FrameAtPoint;
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
DeleteAnimationBlock(animation_block_handle AnimationBlockHandle, app_state* State)
|
DeleteAnimationBlock(animation_block_handle AnimationBlockHandle, app_state* State)
|
||||||
{
|
{
|
||||||
|
@ -20,13 +37,6 @@ SelectAnimationBlock(animation_block_handle BlockHandle, app_state* State)
|
||||||
State->SelectedAnimationBlockHandle = BlockHandle;
|
State->SelectedAnimationBlockHandle = BlockHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
SelectAndBeginDragAnimationBlock(animation_block_handle BlockHandle, app_state* State)
|
|
||||||
{
|
|
||||||
SelectAnimationBlock(BlockHandle, State);
|
|
||||||
// TODO(Peter): Begin Dragging Mode
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
DeselectCurrentAnimationBlock(app_state* State)
|
DeselectCurrentAnimationBlock(app_state* State)
|
||||||
{
|
{
|
||||||
|
@ -41,6 +51,63 @@ FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Drag Animation Clip
|
||||||
|
//
|
||||||
|
|
||||||
|
OPERATION_STATE_DEF(drag_animation_clip_state)
|
||||||
|
{
|
||||||
|
r32 AnimationPanel_StartFrame;
|
||||||
|
r32 AnimationPanel_EndFrame;
|
||||||
|
r32 SelectedClip_InitialStartTime;
|
||||||
|
r32 SelectedClip_InitialEndTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
OPERATION_RENDER_PROC(UpdateDragAnimationClip)
|
||||||
|
{
|
||||||
|
drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory;
|
||||||
|
|
||||||
|
panel_and_bounds AnimationPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelLayout, State->WindowBounds);
|
||||||
|
Assert(AnimationPanel.Panel);
|
||||||
|
|
||||||
|
r32 TimeAtMouseDownX = GetTimeFromPointInAnimationPanel(Mouse.DownPos, AnimationPanel.Bounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame);
|
||||||
|
r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.Pos, AnimationPanel.Bounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame);
|
||||||
|
r32 TimeOffset = TimeAtMouseX - TimeAtMouseDownX;
|
||||||
|
|
||||||
|
animation_block* AnimationBlock = GetAnimationBlockWithHandle(State->SelectedAnimationBlockHandle, &State->AnimationSystem);
|
||||||
|
AnimationBlock->StartTime = OpState->SelectedClip_InitialStartTime + TimeOffset;
|
||||||
|
AnimationBlock->EndTime = OpState->SelectedClip_InitialEndTime + TimeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
FOLDHAUS_INPUT_COMMAND_PROC(EndDragAnimationClip)
|
||||||
|
{
|
||||||
|
DeactivateCurrentOperationMode(&State->Modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_command DragAnimationClipCommands [] = {
|
||||||
|
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragAnimationClip },
|
||||||
|
};
|
||||||
|
|
||||||
|
internal void
|
||||||
|
SelectAndBeginDragAnimationBlock(animation_block_handle BlockHandle, s32 PanelStartFrame, s32 PanelEndFrame, app_state* State)
|
||||||
|
{
|
||||||
|
SelectAnimationBlock(BlockHandle, State);
|
||||||
|
|
||||||
|
operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip);
|
||||||
|
|
||||||
|
drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode,
|
||||||
|
&State->Modes,
|
||||||
|
drag_animation_clip_state);
|
||||||
|
OpState->AnimationPanel_StartFrame = PanelStartFrame;
|
||||||
|
OpState->AnimationPanel_EndFrame = PanelEndFrame ;
|
||||||
|
|
||||||
|
animation_block* SelectedBlock = GetAnimationBlockWithHandle(BlockHandle, &State->AnimationSystem);
|
||||||
|
OpState->SelectedClip_InitialStartTime = SelectedBlock->StartTime;
|
||||||
|
OpState->SelectedClip_InitialEndTime = SelectedBlock->EndTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
|
FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand)
|
||||||
{
|
{
|
||||||
panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelLayout, State->WindowBounds);
|
panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelLayout, State->WindowBounds);
|
||||||
|
@ -74,15 +141,15 @@ PANEL_CLEANUP_PROC(AnimationTimeline_Cleanup)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal r32
|
internal r32
|
||||||
DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBuffer, s32 StartFrame, s32 EndFrame, v2 PanelMin, v2 PanelMax, interface_config Interface, mouse_state Mouse)
|
DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBuffer, s32 StartFrame, s32 EndFrame, rect PanelBounds, interface_config Interface, mouse_state Mouse)
|
||||||
{
|
{
|
||||||
MakeStringBuffer(TempString, 256);
|
MakeStringBuffer(TempString, 256);
|
||||||
|
|
||||||
s32 FrameCount = EndFrame - StartFrame;
|
s32 FrameCount = EndFrame - StartFrame;
|
||||||
|
|
||||||
r32 FrameBarHeight = 24;
|
r32 FrameBarHeight = 24;
|
||||||
v2 FrameBarMin = v2{PanelMin.x, PanelMax.y - FrameBarHeight};
|
v2 FrameBarMin = v2{PanelBounds.Min.x, PanelBounds.Max.y - FrameBarHeight};
|
||||||
v2 FrameBarMax = PanelMax;
|
v2 FrameBarMax = PanelBounds.Max;
|
||||||
|
|
||||||
PushRenderQuad2D(RenderBuffer, FrameBarMin, FrameBarMax, v4{.16f, .16f, .16f, 1.f});
|
PushRenderQuad2D(RenderBuffer, FrameBarMin, FrameBarMax, v4{.16f, .16f, .16f, 1.f});
|
||||||
|
|
||||||
|
@ -90,11 +157,8 @@ DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBu
|
||||||
if (MouseButtonHeldDown(Mouse.LeftButtonState)
|
if (MouseButtonHeldDown(Mouse.LeftButtonState)
|
||||||
&& PointIsInRange(Mouse.DownPos, FrameBarMin, FrameBarMax))
|
&& PointIsInRange(Mouse.DownPos, FrameBarMin, FrameBarMax))
|
||||||
{
|
{
|
||||||
r32 MouseX = Mouse.DownPos.x;
|
r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.DownPos, PanelBounds, StartFrame, EndFrame, AnimationSystem->SecondsPerFrame);
|
||||||
r32 StartFrameTime = (r32)StartFrame * AnimationSystem->SecondsPerFrame;
|
AnimationSystem->Time = TimeAtMouseX;
|
||||||
r32 EndFrameTime = (r32)EndFrame * AnimationSystem->SecondsPerFrame;
|
|
||||||
r32 MouseTime = GSRemap(MouseX, FrameBarMin.x, FrameBarMax.x, StartFrameTime, EndFrameTime);
|
|
||||||
AnimationSystem->Time = MouseTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frame Ticks
|
// Frame Ticks
|
||||||
|
@ -104,13 +168,13 @@ DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBu
|
||||||
PrintF(&TempString, "%d", Frame);
|
PrintF(&TempString, "%d", Frame);
|
||||||
|
|
||||||
r32 FramePercent = (r32)f / (r32)FrameCount;
|
r32 FramePercent = (r32)f / (r32)FrameCount;
|
||||||
r32 FrameX = GSLerp(PanelMin.x, PanelMax.x, FramePercent);
|
r32 FrameX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, FramePercent);
|
||||||
v2 FrameTextPos = v2{FrameX, FrameBarMin.y + 2};
|
v2 FrameTextPos = v2{FrameX, FrameBarMin.y + 2};
|
||||||
DrawString(RenderBuffer, TempString, Interface.Font, FrameTextPos, WhiteV4);
|
DrawString(RenderBuffer, TempString, Interface.Font, FrameTextPos, WhiteV4);
|
||||||
|
|
||||||
// Frame Vertical Slices
|
// Frame Vertical Slices
|
||||||
v2 LineTop = v2{FrameX, FrameBarMin.y};
|
v2 LineTop = v2{FrameX, FrameBarMin.y};
|
||||||
v2 LineBottom = v2{FrameX + 1, PanelMin.y};
|
v2 LineBottom = v2{FrameX + 1, PanelBounds.Min.y};
|
||||||
PushRenderQuad2D(RenderBuffer, LineTop, LineBottom, v4{.16f, .16f, .16f, 1.f});
|
PushRenderQuad2D(RenderBuffer, LineTop, LineBottom, v4{.16f, .16f, .16f, 1.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,15 +206,15 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, r32 SecondsPe
|
||||||
}
|
}
|
||||||
|
|
||||||
internal animation_block_handle
|
internal animation_block_handle
|
||||||
DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 EndFrame, v2 PanelMin, v2 PanelMax, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse)
|
DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 EndFrame, rect PanelBounds, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse)
|
||||||
{
|
{
|
||||||
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
|
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
|
||||||
s32 FrameCount = EndFrame - StartFrame;
|
s32 FrameCount = EndFrame - StartFrame;
|
||||||
|
|
||||||
animation_block_handle Result = SelectedBlockHandle;
|
animation_block_handle Result = SelectedBlockHandle;
|
||||||
|
|
||||||
r32 AnimationPanelHeight = PanelMax.y - PanelMin.y;
|
r32 AnimationPanelHeight = PanelBounds.Max.y - PanelBounds.Min.y;
|
||||||
r32 AnimationPanelWidth = PanelMax.x - PanelMin.x;
|
r32 AnimationPanelWidth = PanelBounds.Max.x - PanelBounds.Min.x;
|
||||||
|
|
||||||
{
|
{
|
||||||
s32 FirstPlayableFrame = (AnimationSystem->AnimationStart / AnimationSystem->SecondsPerFrame);
|
s32 FirstPlayableFrame = (AnimationSystem->AnimationStart / AnimationSystem->SecondsPerFrame);
|
||||||
|
@ -159,29 +223,29 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
|
||||||
r32 FirstPlayablePercentX = ((r32)(FirstPlayableFrame - StartFrame) / (r32)FrameCount);
|
r32 FirstPlayablePercentX = ((r32)(FirstPlayableFrame - StartFrame) / (r32)FrameCount);
|
||||||
r32 LastPlayablePercentX = ((r32)(LastPlayableFrame - StartFrame) / (r32)FrameCount);
|
r32 LastPlayablePercentX = ((r32)(LastPlayableFrame - StartFrame) / (r32)FrameCount);
|
||||||
|
|
||||||
v2 PlayableMin = v2{(FirstPlayablePercentX * AnimationPanelWidth) + PanelMin.x, PanelMin.y };
|
v2 PlayableMin = v2{(FirstPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Min.y };
|
||||||
v2 PlayableMax = v2{(LastPlayablePercentX * AnimationPanelWidth) + PanelMin.x, PanelMax.y };
|
v2 PlayableMax = v2{(LastPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Max.y };
|
||||||
|
|
||||||
PushRenderQuad2D(RenderBuffer, PanelMin, PanelMax, v4{.16f, .16f, .16f, 1.f});
|
PushRenderQuad2D(RenderBuffer, PanelBounds.Min, PanelBounds.Max, v4{.16f, .16f, .16f, 1.f});
|
||||||
PushRenderQuad2D(RenderBuffer, PlayableMin, PlayableMax, v4{.22f, .22f, .22f, 1.f});
|
PushRenderQuad2D(RenderBuffer, PlayableMin, PlayableMax, v4{.22f, .22f, .22f, 1.f});
|
||||||
}
|
}
|
||||||
|
|
||||||
r32 FrameBarBottom = DrawFrameBar(AnimationSystem, RenderBuffer, StartFrame, EndFrame, PanelMin, PanelMax, State->Interface, Mouse);
|
r32 FrameBarBottom = DrawFrameBar(AnimationSystem, RenderBuffer, StartFrame, EndFrame, PanelBounds, State->Interface, Mouse);
|
||||||
|
|
||||||
// Animation Blocks
|
// Animation Blocks
|
||||||
v2 TimelineMin = PanelMin;
|
v2 TimelineMin = PanelBounds.Min;
|
||||||
v2 TimelineMax = v2{PanelMax.x, FrameBarBottom};
|
v2 TimelineMax = v2{PanelBounds.Max.x, FrameBarBottom};
|
||||||
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState);
|
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState);
|
||||||
for (u32 i = 0; i < AnimationSystem->BlocksCount; i++)
|
for (u32 i = 0; i < AnimationSystem->BlocksCount; i++)
|
||||||
{
|
{
|
||||||
animation_block_entry AnimationBlockEntry = AnimationSystem->Blocks[i];
|
animation_block_entry* AnimationBlockEntry = GetEntryAtIndex(i, AnimationSystem);
|
||||||
if (AnimationBlockIsFree(AnimationBlockEntry)) { continue; }
|
if (AnimationBlockIsFree(*AnimationBlockEntry)) { continue; }
|
||||||
|
|
||||||
animation_block_handle CurrentBlockHandle = {};
|
animation_block_handle CurrentBlockHandle = {};
|
||||||
CurrentBlockHandle.Index = i;
|
CurrentBlockHandle.Index = i;
|
||||||
CurrentBlockHandle.Generation = AnimationBlockEntry.Generation;
|
CurrentBlockHandle.Generation = AnimationBlockEntry->Generation;
|
||||||
|
|
||||||
animation_block AnimationBlockAt = AnimationBlockEntry.Block;
|
animation_block AnimationBlockAt = AnimationBlockEntry->Block;
|
||||||
|
|
||||||
v4 BlockColor = BlackV4;
|
v4 BlockColor = BlackV4;
|
||||||
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
|
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
|
||||||
|
@ -195,23 +259,23 @@ DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 En
|
||||||
&& MouseButtonTransitionedDown(Mouse.LeftButtonState))
|
&& MouseButtonTransitionedDown(Mouse.LeftButtonState))
|
||||||
{
|
{
|
||||||
MouseDownAndNotHandled = false;
|
MouseDownAndNotHandled = false;
|
||||||
SelectAndBeginDragAnimationBlock(CurrentBlockHandle, State);
|
SelectAndBeginDragAnimationBlock(CurrentBlockHandle, StartFrame, EndFrame, State);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time Slider
|
// Time Slider
|
||||||
s32 SliderFrame = AnimationSystem->Time / AnimationSystem->SecondsPerFrame;
|
s32 SliderFrame = AnimationSystem->Time / AnimationSystem->SecondsPerFrame;
|
||||||
r32 TimePercent = (r32)(SliderFrame - StartFrame) / (r32)FrameCount;
|
r32 TimePercent = (r32)(SliderFrame - StartFrame) / (r32)FrameCount;
|
||||||
r32 SliderX = PanelMin.x + (AnimationPanelWidth * TimePercent);
|
r32 SliderX = PanelBounds.Min.x + (AnimationPanelWidth * TimePercent);
|
||||||
v2 SliderMin = v2{SliderX, PanelMin.y};
|
v2 SliderMin = v2{SliderX, PanelBounds.Min.y};
|
||||||
v2 SliderMax = v2{SliderX + 1, PanelMax.y - 25};
|
v2 SliderMax = v2{SliderX + 1, PanelBounds.Max.y - 25};
|
||||||
v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f};
|
v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f};
|
||||||
|
|
||||||
PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, TimeSliderColor);
|
PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, TimeSliderColor);
|
||||||
|
|
||||||
r32 SliderHalfWidth = 10;
|
r32 SliderHalfWidth = 10;
|
||||||
v2 HeadMin = v2{SliderX - SliderHalfWidth, SliderMax.y};
|
v2 HeadMin = v2{SliderX - SliderHalfWidth, SliderMax.y};
|
||||||
v2 HeadMax = v2{SliderX + SliderHalfWidth, PanelMax.y};
|
v2 HeadMax = v2{SliderX + SliderHalfWidth, PanelBounds.Max.y};
|
||||||
PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
|
PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor);
|
||||||
|
|
||||||
PrintF(&TempString, "%d", SliderFrame);
|
PrintF(&TempString, "%d", SliderFrame);
|
||||||
|
@ -229,21 +293,23 @@ PANEL_RENDER_PROC(AnimationTimeline_Render)
|
||||||
animation_block_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
|
animation_block_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
|
||||||
|
|
||||||
r32 OptionsRowHeight = 25;
|
r32 OptionsRowHeight = 25;
|
||||||
v2 TimelineMin = PanelMin;
|
rect TimelineBounds = rect{
|
||||||
v2 TimelineMax = v2{PanelMax.x, PanelMax.y - OptionsRowHeight};
|
PanelBounds.Min,
|
||||||
if (TimelineMax.y - TimelineMin.y > 0)
|
v2{PanelBounds.Max.x, PanelBounds.Max.y - OptionsRowHeight}
|
||||||
|
};
|
||||||
|
if (Height(TimelineBounds) > 0)
|
||||||
{
|
{
|
||||||
s32 FrameStart = (s32)(State->AnimationSystem.AnimationStart / State->AnimationSystem.SecondsPerFrame);
|
s32 FrameStart = (s32)(State->AnimationSystem.AnimationStart / State->AnimationSystem.SecondsPerFrame);
|
||||||
s32 FrameEnd = (s32)(State->AnimationSystem.AnimationEnd / State->AnimationSystem.SecondsPerFrame);
|
s32 FrameEnd = (s32)(State->AnimationSystem.AnimationEnd / State->AnimationSystem.SecondsPerFrame);
|
||||||
SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem,
|
SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem,
|
||||||
FrameStart - 20, FrameEnd + 20,
|
FrameStart - 20, FrameEnd + 20,
|
||||||
TimelineMin, TimelineMax,
|
TimelineBounds,
|
||||||
SelectedBlockHandle,
|
SelectedBlockHandle,
|
||||||
RenderBuffer, State, Mouse);
|
RenderBuffer, State, Mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 OptionsRowMin = v2{ PanelMin.x, TimelineMax.y };
|
v2 OptionsRowMin = v2{ PanelBounds.Min.x, TimelineBounds.Max.y };
|
||||||
v2 OptionsRowMax = PanelMax;
|
v2 OptionsRowMax = PanelBounds.Max;
|
||||||
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax,
|
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax,
|
||||||
0, State->Interface);
|
0, State->Interface);
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,18 @@ PANEL_CLEANUP_PROC(HierarchyView_Cleanup)
|
||||||
|
|
||||||
PANEL_RENDER_PROC(HierarchyView_Render)
|
PANEL_RENDER_PROC(HierarchyView_Render)
|
||||||
{
|
{
|
||||||
r32 PanelWidth = PanelMax.x - PanelMin.x;
|
r32 PanelWidth = PanelBounds.Max.x - PanelBounds.Min.x;
|
||||||
r32 PanelHeight = PanelMax.y - PanelMin.y;
|
r32 PanelHeight = PanelBounds.Max.y - PanelBounds.Min.y;
|
||||||
|
|
||||||
s32 LineBGColorsCount = 2;
|
s32 LineBGColorsCount = 2;
|
||||||
v4 LineBGColors[] = {
|
v4 LineBGColors[] = {
|
||||||
{ .16f, .16f, .16f, 1.f },
|
{ .16f, .16f, .16f, 1.f },
|
||||||
{ .18f, .18f, .18f, 1.f },
|
{ .18f, .18f, .18f, 1.f },
|
||||||
};
|
};
|
||||||
v4 LineBGHoverColor = { .22f, .22f, .22f, 1.f };
|
v4 LineBGHoverColor = { .22f, .22f, .22f, 1.f };
|
||||||
|
|
||||||
r32 LineHeight = State->Interface.Font->PixelHeight + 8;
|
r32 LineHeight = State->Interface.Font->PixelHeight + 8;
|
||||||
v2 LineMin = v2{PanelMin.x, PanelMax.y - LineHeight};
|
v2 LineMin = v2{PanelBounds.Min.x, PanelBounds.Max.y - LineHeight};
|
||||||
v2 LineMax = LineMin + v2{PanelWidth, LineHeight};
|
v2 LineMax = LineMin + v2{PanelWidth, LineHeight};
|
||||||
v2 TextOffset = v2{10, 4};
|
v2 TextOffset = v2{10, 4};
|
||||||
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
|
string TempString = MakeString(PushArray(&State->Transient, char, 256), 256);
|
||||||
|
@ -34,12 +34,12 @@ v4 LineBGColors[] = {
|
||||||
{
|
{
|
||||||
Color = LineBGHoverColor;
|
Color = LineBGHoverColor;
|
||||||
}
|
}
|
||||||
PushRenderQuad2D(RenderBuffer, LineMin, LineMax, Color);
|
PushRenderQuad2D(RenderBuffer, LineMin, LineMax, Color);
|
||||||
if (i < State->ActiveAssemblyIndecies.Used)
|
if (i < State->ActiveAssemblyIndecies.Used)
|
||||||
{
|
{
|
||||||
array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
|
||||||
assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList);
|
assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList);
|
||||||
PrintF(&TempString, "%S", Assembly.Name);
|
PrintF(&TempString, "%S", Assembly.Name);
|
||||||
|
|
||||||
DrawString(RenderBuffer, TempString, State->Interface.Font, LineMin + TextOffset, WhiteV4);
|
DrawString(RenderBuffer, TempString, State->Interface.Font, LineMin + TextOffset, WhiteV4);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LineMin.y = GSMax(PanelMin.y, LineMin.y - LineHeight);
|
LineMin.y = GSMax(PanelBounds.Min.y, LineMin.y - LineHeight);
|
||||||
LineMax.y = GSMax(PanelMin.y, LineMax.y - LineHeight);
|
LineMax.y = GSMax(PanelBounds.Min.y, LineMax.y - LineHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -110,13 +110,13 @@ RenderProfiler_ListVisualization(render_command_buffer* RenderBuffer,
|
||||||
PANEL_RENDER_PROC(ProfilerView_Render)
|
PANEL_RENDER_PROC(ProfilerView_Render)
|
||||||
{
|
{
|
||||||
memory_arena* Memory = &State->Transient;
|
memory_arena* Memory = &State->Transient;
|
||||||
string String = InitializeEmptyString(PushArray(Memory, char, 256), 256);
|
string String = InitializeEmptyString(PushArray(Memory, char, 256), 256);
|
||||||
|
|
||||||
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
|
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
|
||||||
|
|
||||||
r32 FrameListHeight = 64;
|
r32 FrameListHeight = 64;
|
||||||
v2 FrameListMin = v2{PanelMin.x + 16, PanelMax.y - (16 + FrameListHeight)};
|
v2 FrameListMin = v2{PanelBounds.Min.x + 16, PanelBounds.Max.y - (16 + FrameListHeight)};
|
||||||
v2 FrameListMax = v2{PanelMax.x - 16, PanelMax.y - 16};
|
v2 FrameListMax = v2{PanelBounds.Max.x - 16, PanelBounds.Max.y - 16};
|
||||||
|
|
||||||
r32 FrameListPadding = 4;
|
r32 FrameListPadding = 4;
|
||||||
r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2);
|
r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2);
|
||||||
|
@ -181,7 +181,7 @@ string String = InitializeEmptyString(PushArray(Memory, char, 256), 256);
|
||||||
if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; }
|
if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; }
|
||||||
if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; }
|
if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; }
|
||||||
|
|
||||||
v2 ViewModeMin = v2{FrameListMin.x, PanelMin.y};
|
v2 ViewModeMin = v2{FrameListMin.x, PanelBounds.Min.y};
|
||||||
v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96};
|
v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96};
|
||||||
|
|
||||||
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
|
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
// 3D Mouse View
|
// 3D Mouse View
|
||||||
|
|
||||||
struct mouse_rotate_view_operation_state
|
OPERATION_STATE_DEF(mouse_rotate_view_operation_state)
|
||||||
{
|
{
|
||||||
v4 CameraStartPos;
|
v4 CameraStartPos;
|
||||||
};
|
};
|
||||||
|
@ -30,9 +30,7 @@ input_command MouseRotateViewCommands [] = {
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
|
FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate)
|
||||||
{
|
{
|
||||||
operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands);
|
operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate);
|
||||||
RotateViewMode->Render = Update3DViewMouseRotate;
|
|
||||||
|
|
||||||
mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode,
|
mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode,
|
||||||
&State->Modes,
|
&State->Modes,
|
||||||
mouse_rotate_view_operation_state);
|
mouse_rotate_view_operation_state);
|
||||||
|
@ -122,8 +120,8 @@ PANEL_RENDER_PROC(SculptureView_Render)
|
||||||
{
|
{
|
||||||
DEBUG_TRACK_SCOPE(RenderSculpture);
|
DEBUG_TRACK_SCOPE(RenderSculpture);
|
||||||
|
|
||||||
r32 PanelWidth = PanelMax.x - PanelMin.x;
|
r32 PanelWidth = PanelBounds.Max.x - PanelBounds.Min.x;
|
||||||
r32 PanelHeight = PanelMax.y - PanelMin.y;
|
r32 PanelHeight = PanelBounds.Max.y - PanelBounds.Min.y;
|
||||||
State->Camera.AspectRatio = PanelWidth / PanelHeight;
|
State->Camera.AspectRatio = PanelWidth / PanelHeight;
|
||||||
|
|
||||||
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
|
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
|
||||||
|
@ -131,7 +129,7 @@ PANEL_RENDER_PROC(SculptureView_Render)
|
||||||
|
|
||||||
r32 LEDHalfWidth = .5f;
|
r32 LEDHalfWidth = .5f;
|
||||||
|
|
||||||
PushRenderPerspective(RenderBuffer, PanelMin.x, PanelMin.y, PanelWidth, PanelHeight, State->Camera);
|
PushRenderPerspective(RenderBuffer, PanelBounds.Min.x, PanelBounds.Min.y, PanelWidth, PanelHeight, State->Camera);
|
||||||
|
|
||||||
// TODO(Peter): Pretty sure this isn't working right now
|
// TODO(Peter): Pretty sure this isn't working right now
|
||||||
m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1));
|
m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1));
|
||||||
|
|
Loading…
Reference in New Issue