From 7435ce70153572e9f2dec316406e6ebb53334b51 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Wed, 26 Oct 2022 22:20:09 -0400 Subject: graph work --- bezier.cpp | 6 +- createcalls.cpp | 27 ++++++- main.cpp | 101 +++++++++++++------------ main.h | 10 ++- memory.cpp | 3 +- my_imgui_widgets.cpp | 203 +++++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 279 insertions(+), 71 deletions(-) diff --git a/bezier.cpp b/bezier.cpp index 42ed04d..f476986 100644 --- a/bezier.cpp +++ b/bezier.cpp @@ -8,9 +8,10 @@ Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 Tar v2 m1 = (Point_P2 - Point_P0) / (2 * Tau); v2 m2 = (Point_P3 - Point_P1) / (2 * Tau); - real32 Precision = 0.001; + real32 Precision = 0.000001; real32 t = (TargetX - Point_P0.x) / (Point_P3.x - Point_P0.x); + int Iterations = 0; for (;;) { real32 t2 = t * t; real32 t3 = t2 * t; @@ -22,8 +23,9 @@ Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 Tar bool32 Cond1 = (Point.x <= (TargetX - Precision)); bool32 Cond2 = (Point.x >= (TargetX + Precision)); - if (Cond1 || Cond2) { + if ((Cond1 || Cond2) && Iterations < 10) { t = t * TargetX / Point.x; + Iterations++; } else { Y = Point.y; break; diff --git a/createcalls.cpp b/createcalls.cpp index d0ca03e..5c569fb 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -57,10 +57,14 @@ static property_info Property_GetInfo(memory *Memory, property_channel *Property) { property_info PropertyInfo = {}; - for (int k = 0; k < Property->Keyframe_Count; k++) { + int k = 0; + for (;;) { bezier_point *Point = Bezier_Lookup(Memory, Property, k); + if (!Point->Occupied) + break; PropertyInfo.MinVal = (Point->Pos[0].y < PropertyInfo.MinVal) ? Point->Pos[0].y : PropertyInfo.MinVal; PropertyInfo.MaxVal = (Point->Pos[0].y > PropertyInfo.MaxVal) ? Point->Pos[0].y : PropertyInfo.MaxVal; + k++; } return PropertyInfo; } @@ -75,7 +79,7 @@ Graph_GetInfo(project_data *File, memory *Memory) continue; for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; - if (Property->Keyframe_Count) { + if (Property->Block_Bezier_Count) { property_info PropertyInfo = Property_GetInfo(Memory, Property); GraphInfo.MinVal = (PropertyInfo.MinVal < GraphInfo.MinVal) ? PropertyInfo.MinVal : GraphInfo.MinVal; GraphInfo.MaxVal = (PropertyInfo.MaxVal > GraphInfo.MaxVal) ? PropertyInfo.MaxVal : GraphInfo.MaxVal; @@ -86,6 +90,25 @@ Graph_GetInfo(project_data *File, memory *Memory) return GraphInfo; } +static void +Keyframe_Interact_Evaluate(memory *Memory, project_state *State, uint8 IsSelected, v2 Pos_Initial[3], v2 Pos_New[3]) +{ + Assert(Pos_New[0].y == Pos_Initial[0].y); + v2 Offset = V2(State->Interact_Offset[0], State->Interact_Offset[1]); + if (State->Interact_Active == interact_type_keyframe_move) { + Pos_New[0] = Pos_New[0] + Offset; + } else if (State->Interact_Active == interact_type_keyframe_scale) { + Pos_New[1].x += (IsSelected - 1 == 0 || IsSelected - 1 == 1) ? Offset.x : 0; + Pos_New[2].x -= (IsSelected - 1 == 0 || IsSelected - 1 == 2) ? Offset.x : 0; + } else if (State->Interact_Active == interact_type_keyframe_rotate) { + real32 Rad = State->Interact_Offset[0]; + v2 XAxis = V2(8, 8) * V2(cos(Rad), sin(Rad)); + v2 YAxis = V2(sin(Rad), -cos(Rad)); + Pos_New[2].x += XAxis.x + XAxis.y; + Pos_New[2].y += YAxis.x + YAxis.y; + } +} + static void Layer_Interact_Evaluate(memory *Memory, project_state *State, uint16 Layer_Index_Physical, sorted_comp_info SortedCompInfo, sorted_layer *SortedLayerInfo, int32 *Frame_Start, int32 *Frame_End, real32 *Vertical_Offset) diff --git a/main.cpp b/main.cpp index 74a9e4a..7920727 100644 --- a/main.cpp +++ b/main.cpp @@ -128,7 +128,7 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, ImGui::DockSpaceOverViewport(); if (!io.WantCaptureKeyboard) - ImGui_ProcessInputs(File, State, Memory, io); + ImGui_ProcessInputs(File, State, UI, Memory, io); #if 0 @@ -154,7 +154,7 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, if (Debug.ToggleWindow) { ImGui::ShowDemoWindow(); - ImGui_DebugMemoryViewer(State); + ImGui_DebugMemoryViewer(Memory, State); } // ImGui::ShowDemoWindow(); @@ -165,12 +165,18 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, ImGui::EndFrame(); } -static void +static void * Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, uint32 CompIndex) { block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, State->Render.Entry, cache_entry_type_comp, CompIndex, State->Frame_Current); void *CompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex); + + if (Entry_Main->IsCached) + return CompBuffer; + + uint64 Comp_TimeStart = GetTime(); + sorted_comp_info *SortedCompInfo = &SortedCompArray[CompIndex]; sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex); for (int i = 0; i < SortedCompInfo->LayerCount; i++) { @@ -205,6 +211,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io Entry->CycleTime = GetTime() - Src_TimeStart; Layer->x.CurrentValue = (Layer->Block_Source_Index == 0) ? 200 : Comp->Width/2; Layer->y.CurrentValue = Comp->Height/2; + Entry->IsCached = true; } BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); } else { @@ -228,9 +235,16 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io property_channel *Property = &Layer->x; - if (Property->Keyframe_Count) { + if (Property->Block_Bezier_Count) { bezier_point *FirstPoint = Bezier_Lookup(Memory, Property, 0); - bezier_point *LastPoint = Bezier_Lookup(Memory, Property, Property->Keyframe_Count - 1); + int k = 0; + for (;;) { + bezier_point *Point = Bezier_Lookup(Memory, Property, k); + if (!Point->Occupied) + break; + k++; + } + bezier_point *LastPoint = Bezier_Lookup(Memory, Property, k - 1); if (FirstPoint->Pos[0].x >= State->Frame_Current) { Property->CurrentValue = FirstPoint->Pos[0].y; } else if (LastPoint->Pos[0].x <= State->Frame_Current) { @@ -245,7 +259,11 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io } bezier_point *Point = Bezier_Lookup(Memory, Property, KeyframeIndex); bezier_point *NextPoint = Bezier_Lookup(Memory, Property, KeyframeIndex + 1); - Property->CurrentValue = Bezier_SolveYForX(Point->Pos[0], Point->Pos[0] + Point->Pos[2], NextPoint->Pos[0] + NextPoint->Pos[1], NextPoint->Pos[0], State->Frame_Current); + v2 Pos_New[3] = { Point->Pos[0], Point->Pos[1], Point->Pos[2] }; + v2 NextPos_New[3] = { NextPoint->Pos[0], NextPoint->Pos[1], NextPoint->Pos[2] }; + Keyframe_Interact_Evaluate(Memory, State, Point->IsSelected, Point->Pos, Pos_New); + Keyframe_Interact_Evaluate(Memory, State, NextPoint->IsSelected, NextPoint->Pos, NextPos_New); + Property->CurrentValue = Bezier_SolveYForX(Pos_New[0], Pos_New[0] + Pos_New[2], NextPos_New[0] + NextPos_New[1], NextPos_New[0], State->Frame_Current); } } @@ -271,6 +289,9 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io } } } + Entry_Main->CycleTime = GetTime() - Comp_TimeStart; + Entry_Main->IsCached = true; + return CompBuffer; } static void @@ -278,11 +299,7 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Wind { State->UpdateFrame = false; - uint64 Comp_TimeStart = GetTime(); - block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); - cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, State->Render.Entry, cache_entry_type_comp, File->PrincipalCompIndex, State->Frame_Current); - void *MainCompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex); // NOTE(fox): All layers are given a slot here uint64 SortSize = (sizeof(sorted_comp_info) * File->Comp_Count) + (sizeof(sorted_layer) * File->Layer_Count); @@ -292,19 +309,19 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, SDL_Wind sorted_layer *SortedLayerArray = (sorted_layer *)((uint8 *)SortedArray + (sizeof(sorted_comp_info) * File->Comp_Count)); Layer_SortAll(Memory, SortedLayerArray, SortedCompArray, File->Layer_Count, File->Comp_Count); - Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex); + void *MainCompBuffer = Render_Comp(File, State, Memory, io, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex); Memory_PopScratch(Memory, SortSize); glBindTexture(GL_TEXTURE_2D, textureID); int ByteFlag2 = (MainComp->BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; - if (!Entry_Main->CycleTime) + if (State->FirstFrame) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MainComp->Width, MainComp->Height, 0, GL_RGBA, ByteFlag2, MainCompBuffer); + State->FirstFrame = false; + } glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MainComp->Width, MainComp->Height, GL_RGBA, ByteFlag2, MainCompBuffer); - Entry_Main->CycleTime = GetTime() - Comp_TimeStart; - // TODO(fox): garbage collect AV state! } @@ -340,7 +357,7 @@ int main(int argc, char *argv[]) { Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, F_Strings, "Strings", sizeof(block_string)); Memory_InitTable(&GlobalMemory, &Memory, (uint64)64 * 1024 * 1024, B_ScratchSpace, "Scratch"); - Memory_InitTable(&GlobalMemory, &Memory, (uint64)50 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer"); + Memory_InitTable(&GlobalMemory, &Memory, (uint64)200 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer"); #if ARM InstructionMode = instruction_mode_neon; @@ -412,8 +429,8 @@ int main(int argc, char *argv[]) { Bezier->Occupied = 1; Bezier->Point[0].Pos[0] = V2(0, 0); - Bezier->Point[1].Pos[0] = V2(10, 50); - Bezier->Point[2].Pos[0] = V2(20, -50); + Bezier->Point[1].Pos[0] = V2(20, 50); + Bezier->Point[2].Pos[0] = V2(40, -50); Bezier->Point[0].Pos[1] = V2(-4, 0); Bezier->Point[1].Pos[1] = V2(-4, 0); Bezier->Point[2].Pos[1] = V2(-4, 0); @@ -423,8 +440,10 @@ int main(int argc, char *argv[]) { Bezier->Point[0].Type = interpolation_type_bezier; Bezier->Point[1].Type = interpolation_type_bezier; Bezier->Point[2].Type = interpolation_type_bezier; - Bezier->Point[1].IsSelected = true; - Property->Keyframe_Count = 3; + Bezier->Point[1].IsSelected = false; + Bezier->Point[0].Occupied = true; + Bezier->Point[1].Occupied = true; + Bezier->Point[2].Occupied = true; property_channel *Property2 = &Layer->opacity; Property2->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); @@ -435,7 +454,8 @@ int main(int argc, char *argv[]) { Bezier2->Point[0].Pos[0] = V2(0, 0); Bezier2->Point[1].Pos[0] = V2(20, 1); - Property2->Keyframe_Count = 2; + Bezier2->Point[0].Occupied = true; + Bezier2->Point[1].Occupied = true; property_channel *Property3 = &Layer->y; Property3->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); @@ -445,8 +465,8 @@ int main(int argc, char *argv[]) { Bezier3->Occupied = 1; Bezier3->Point[0].Pos[0] = V2(0, -20); - Bezier3->Point[1].Pos[0] = V2(10, 300); - Bezier3->Point[2].Pos[0] = V2(20, 100); + Bezier3->Point[1].Pos[0] = V2(20, 300); + Bezier3->Point[2].Pos[0] = V2(40, 100); Bezier3->Point[0].Pos[1] = V2(-4, 0); Bezier3->Point[1].Pos[1] = V2(-4, 0); Bezier3->Point[2].Pos[1] = V2(-4, 0); @@ -456,7 +476,9 @@ int main(int argc, char *argv[]) { Bezier3->Point[0].Type = interpolation_type_bezier; Bezier3->Point[1].Type = interpolation_type_bezier; Bezier3->Point[2].Type = interpolation_type_bezier; - Property3->Keyframe_Count = 3; + Bezier3->Point[0].Occupied = true; + Bezier3->Point[1].Occupied = true; + Bezier3->Point[2].Occupied = true; } // { // Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End); @@ -472,6 +494,7 @@ int main(int argc, char *argv[]) { { uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/b.jpg"); block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, 1); +#if 0 { Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End); block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1); @@ -505,7 +528,10 @@ int main(int argc, char *argv[]) { Bezier->Point[1].Type = interpolation_type_bezier; Bezier->Point[2].Type = interpolation_type_bezier; Bezier->Point[3].Type = interpolation_type_bezier; - Property->Keyframe_Count = 4; + Bezier->Point[0].Occupied = true; + Bezier->Point[1].Occupied = true; + Bezier->Point[2].Occupied = true; + Bezier->Point[3].Occupied = true; property_channel *Property2 = &Layer->opacity; Property2->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); @@ -516,31 +542,10 @@ int main(int argc, char *argv[]) { Bezier2->Point[0].Pos[0] = V2(25, 1); Bezier2->Point[1].Pos[0] = V2(40, 0); - Property2->Keyframe_Count = 2; - - /* - property_channel *Property3 = &Layer->y; - Property3->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); - Property3->Block_Bezier_Count = 1; - - block_bezier *Bezier3 = (block_bezier *)Memory_Block_AddressAtIndex(&Memory, F_Bezier, Property3->Block_Bezier_Index[0]); - Bezier3->Occupied = 1; - - Bezier3->Point[0].Pos[0] = V2(0, -20); - Bezier3->Point[1].Pos[0] = V2(10, 300); - Bezier3->Point[2].Pos[0] = V2(20, 100); - Bezier3->Point[0].Pos[1] = V2(-4, 0); - Bezier3->Point[1].Pos[1] = V2(-4, 0); - Bezier3->Point[2].Pos[1] = V2(-4, 0); - Bezier3->Point[0].Pos[2] = V2(4, 0); - Bezier3->Point[1].Pos[2] = V2(4, 0); - Bezier3->Point[2].Pos[2] = V2(4, 0); - Bezier3->Point[0].Type = interpolation_type_bezier; - Bezier3->Point[1].Type = interpolation_type_bezier; - Bezier3->Point[2].Type = interpolation_type_bezier; - Property3->Keyframe_Count = 3; - */ + Bezier2->Point[0].Occupied = true; + Bezier2->Point[1].Occupied = true; } +#endif } { diff --git a/main.h b/main.h index 00d97c9..7e07597 100644 --- a/main.h +++ b/main.h @@ -80,7 +80,8 @@ struct bezier_point { uint8 Occupied; v2 Pos[3]; interpolation_type Type; - uint8 IsSelected; //[3] + uint8 IsSelected; + uint8 PointSelect[3]; uint8 Color; }; @@ -187,7 +188,10 @@ enum interact_type { interact_type_none, interact_type_layer_move, - interact_type_layer_timeadjust + interact_type_layer_timeadjust, + interact_type_keyframe_move, + interact_type_keyframe_scale, + interact_type_keyframe_rotate, }; struct project_state @@ -204,6 +208,7 @@ struct project_state bool32 IsRunning = 1; bool32 IsPlaying; + bool32 FirstFrame = 1; int16 MostRecentlySelectedLayer = -1; // selection_type RecentSelectionType = selection_none; @@ -295,7 +300,6 @@ struct property_channel { char *Name; uint16 Block_Bezier_Index[MAX_KEYFRAME_BLOCKS]; uint16 Block_Bezier_Count; - uint16 Keyframe_Count; real32 CurrentValue; real32 MaxVal; diff --git a/memory.cpp b/memory.cpp index 1dd7ae6..3037eb0 100644 --- a/memory.cpp +++ b/memory.cpp @@ -84,11 +84,12 @@ Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entr } break; } + uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; + Assert(Blocks_Max > LastBlock); return LastBlock + LastEntry_BlockCount; /* uint32 Blocks_Needed = (NewSize / BitmapBlockSize) + 1; - uint32 Blocks_Max = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; uint32 Block_Index_Available = 0; */ diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 545af4e..c5a4049 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -4,16 +4,51 @@ #include "imgui_helper_widgets.cpp" static void -ImGui_DebugMemoryViewer(project_state *State) +ImGui_DebugMemoryViewer(memory *Memory, project_state *State) { ImGui::Begin("Memory viewer"); + + ImVec2 ViewportMin = ImGui::GetCursorScreenPos(); + ImVec2 ViewportScale = ImGui::GetContentRegionAvail(); + ImVec2 ViewportMax = ImVec2(ViewportMin.x + ViewportScale.x, ViewportMin.y + ViewportScale.y); + + // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + // ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + cache_entry *EntryArray = State->Render.Entry; char *Type[4] = { "unassigned", "comp", "source", "layer" }; int c = 0; - while (EntryArray[c].CycleTime != 0) { - ImGui::Text("Type - %s, Start - %i, Info - %i", Type[EntryArray[c].Type], EntryArray[c].Block_StartIndex, EntryArray[c].TypeInfo); + uint32 Blocks_Total = Memory->Slot[B_CachedBitmaps].Size / BitmapBlockSize; + uint32 PerRow = sqrt(Blocks_Total); + real32 BlockSize = ViewportScale.x / PerRow; + while (EntryArray[c+1].CycleTime != 0) { + ImGui::PushID(c); + cache_entry Entry = EntryArray[c]; + cache_entry NextEntry = EntryArray[c+1]; + uint32 BlockSpan = NextEntry.Block_StartIndex - Entry.Block_StartIndex; + ImVec2 ButtonPos = ViewportMin + ImVec2((Entry.Block_StartIndex % PerRow) * BlockSize, BlockSize * (Entry.Block_StartIndex / PerRow)); + ImVec2 ButtonSize = ImVec2(BlockSpan * BlockSize, BlockSize); + ImGui::SetCursorScreenPos(ButtonPos); + char size[20]; + sprintf(size, "%lu##uimemoryblock", EntryArray[c].CycleTime); + if (ButtonPos.x + ButtonSize.x > ViewportMax.x) { + real32 ButtonSizeSplit = ViewportMax.x - ButtonPos.x; + ImGui::Button(size, ImVec2(ButtonSizeSplit, ButtonSize.y)); + ImVec2 ButtonPos2 = ImVec2(ViewportMin.x, ButtonPos.y + BlockSize); + ImGui::SetCursorScreenPos(ButtonPos2); + ImGui::Button("##uimemoryblockpad", ImVec2(ButtonSize.x - ButtonSizeSplit, ButtonSize.y)); + } else { + ImGui::Button(size, ButtonSize); + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("Type - %s, Start - %i, Info - %i, %i", Type[EntryArray[c].Type], EntryArray[c].Block_StartIndex, EntryArray[c].TypeInfo, EntryArray[c].TypeInfo_Sub); + ImGui::EndTooltip(); + } c++; + ImGui::PopID(); } + // ImGui::PopStyleVar(2); ImGui::End(); } @@ -212,7 +247,7 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI ImGui::PushID(a); for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; - if (Property->Keyframe_Count) { + if (Property->Block_Bezier_Count) { ImGui::PushID(Property); ImGui::Text(Property->Name); ImGui::PopID(); @@ -254,39 +289,117 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor ImU32 col = IM_COL32(255, 255, 255, 255); + if (State->Interact_Active == interact_type_keyframe_move) { + ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); + State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) / Increment.x; + State->Interact_Offset[1] = -1 * (DragDelta.y / TimelineSizeWithBorder.y * UI->TimelinePercentZoomed.y) * ((GraphInfo.MaxVal - GraphInfo.MinVal)); + } else if (State->Interact_Active == interact_type_keyframe_scale) { + ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); + State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) / Increment.x; + // TODO(fox): Pass min/max to sort to calculate this better! + } + + if ((io.MouseDelta.x || io.MouseDelta.y) && + (State->Interact_Active == interact_type_keyframe_move || + State->Interact_Active == interact_type_keyframe_rotate || + State->Interact_Active == interact_type_keyframe_scale)) + { + } + for (int h = 0; h < AmountOf(Layer->Property); h++) { property_channel *Property = &Layer->Property[h]; ImGui::PushID(Property); - if (Property->Keyframe_Count) { + if (Property->Block_Bezier_Count) { property_info PropertyInfo = Property_GetInfo(Memory, Property); real32 Y_Increment = 1 / (GraphInfo.MaxVal - GraphInfo.MinVal); bezier_point *PointAddress[2] = {}; ImVec2 Keyframe_ScreenPos[6] = {}; - for (int k = 0; k < Property->Keyframe_Count; k++) { + int k = 0; + for (;;) { int Idx = (k % 2); int NewIdx = Idx * 3; int OldIdx = (NewIdx == 3) ? 0 : 3; PointAddress[Idx] = Bezier_Lookup(Memory, Property, k); bezier_point *Point = PointAddress[Idx]; - ImVec2 Keyframe_LocalPos[3] = { V2(Point->Pos[0]), V2(Point->Pos[0] + Point->Pos[1]), V2(Point->Pos[0] + Point->Pos[2]) }; + if (!Point->Occupied) + break; + + v2 Keyframe_LocalPos_[3] = { Point->Pos[0], Point->Pos[1], Point->Pos[2] }; + + if (Point->IsSelected) { + if (State->Interact_Active == interact_type_keyframe_rotate) { + ImVec2 Keyframe_LocalPos_Ratio = (V2(Keyframe_LocalPos_[0]) - ImVec2(0, GraphInfo.MinVal)) * ImVec2(Increment.x, Y_Increment); + ImVec2 Keyframe_ScreenPos = Layer_ScreenPos_Min + ((ImVec2(1, -1) * Keyframe_LocalPos_Ratio + ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); + real32 Slope_Old = (Keyframe_ScreenPos.y - State->Interact_Offset[3]) / (Keyframe_ScreenPos.x - State->Interact_Offset[2]); + real32 Slope_New = (Keyframe_ScreenPos.y - io.MousePos.y) / (Keyframe_ScreenPos.x - io.MousePos.x); + State->Interact_Offset[0] = atan((Slope_Old - Slope_New) / (1 + Slope_Old * Slope_New)); + DebugWatchVar("Rotation: ", &State->Interact_Offset[0], d_float); + } + Keyframe_Interact_Evaluate(Memory, State, Point->IsSelected, Point->Pos, Keyframe_LocalPos_); + } + ImVec2 Keyframe_LocalPos[3] = { V2(Keyframe_LocalPos_[0]), V2(Keyframe_LocalPos_[0] + Keyframe_LocalPos_[1]), V2(Keyframe_LocalPos_[0] + Keyframe_LocalPos_[2]) }; + ImVec2 Keyframe_LocalPos_Ratio[3]; for (int b = 0; b < 3; b++) { Keyframe_LocalPos_Ratio[b] = (Keyframe_LocalPos[b] - ImVec2(0, GraphInfo.MinVal)) * ImVec2(Increment.x, Y_Increment); Keyframe_ScreenPos[NewIdx + b] = Layer_ScreenPos_Min + ((ImVec2(1, -1) * Keyframe_LocalPos_Ratio[b] + ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); } + if (UI->BoxSelect) { + real32 Y_Top = (io.MouseClickedPos[0].y < io.MousePos.y) ? io.MouseClickedPos[0].y : io.MousePos.y; + real32 Y_Bottom = (io.MouseClickedPos[0].y > io.MousePos.y) ? io.MouseClickedPos[0].y : io.MousePos.y; + real32 X_Left = (io.MouseClickedPos[0].x < io.MousePos.x) ? io.MouseClickedPos[0].x : io.MousePos.x; + real32 X_Right = (io.MouseClickedPos[0].x > io.MousePos.x) ? io.MouseClickedPos[0].x : io.MousePos.x; + + if (Keyframe_ScreenPos[NewIdx].y >= Y_Top && Keyframe_ScreenPos[NewIdx].y <= Y_Bottom && + Keyframe_ScreenPos[NewIdx].x >= X_Left && Keyframe_ScreenPos[NewIdx].x <= X_Right) + { + if (!Point->IsSelected) { + Point->IsSelected = 1; + } + } else if (!io.KeyShift) { + Point->IsSelected = 0; + } + } + UI->Test.SetCurrentChannel(draw_list, 1); - ImU32 PointCol = (Point->IsSelected) ? IM_COL32(255, 128, 0, 255) : IM_COL32(25 ,25, 25, 255); - draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx], 4, PointCol); + ImVec2 ButtonSize(16, 16); - if (Point->IsSelected) { - draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx+1], 4, PointCol); - draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx+2], 4, PointCol); - draw_list->AddLine(Keyframe_ScreenPos[NewIdx], Keyframe_ScreenPos[NewIdx+1], PointCol, 1.0f); - draw_list->AddLine(Keyframe_ScreenPos[NewIdx], Keyframe_ScreenPos[NewIdx+2], PointCol, 1.0f); + ImGui::PushID(k); + int Max = (Point->IsSelected) ? 2 : 0; + for (int b = Max; b >= 0; b--) { + ImU32 PointCol = ((Point->IsSelected - 1) == b) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f); + ImU32 LineCol = ((Point->IsSelected - 1) == b) ? ImColor(0.8f, 0.5f, 0.5f, 1.0f) : ImColor(0.4f, 0.4f, 0.4f, 1.0f); + ImGui::PushID(b); + ImGui::SetCursorScreenPos(Keyframe_ScreenPos[NewIdx + b] - (ButtonSize * 0.5)); + ImGui::InvisibleButton("##keyframemover", ButtonSize, ImGuiMouseButton_Left); + bool32 IsHovered = ImGui::IsItemHovered(); + bool32 IsItemActive = ImGui::IsItemActive(); + bool32 IsItemActivated = ImGui::IsItemActivated(); + bool32 IsItemDeactivated = ImGui::IsItemDeactivated(); + bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left); + bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right); + + if (IsHovered) + PointCol = ImColor(1.0f, 0.8f, 0.8f, 1.0f); + + if (IsItemActivated) { + Point->IsSelected = b+1; + } + + if (b != 0 && Point->IsSelected) + draw_list->AddLine(Keyframe_ScreenPos[NewIdx], Keyframe_ScreenPos[NewIdx + b], LineCol, 2.0f); + + if (b == 0) + draw_list->AddCircleFilled(Keyframe_ScreenPos[NewIdx + b], 4, PointCol); + else + draw_list->AddCircle(Keyframe_ScreenPos[NewIdx + b], 6, PointCol, 0, 2); + + ImGui::PopID(); } + ImGui::PopID(); UI->Test.SetCurrentChannel(draw_list, 0); @@ -298,6 +411,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor draw_list->AddLine(Keyframe_ScreenPos[0], Keyframe_ScreenPos[3], col, 1.0f); } } + k++; } } ImGui::PopID(); @@ -648,10 +762,14 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, SortedCompArray, SortedLayerArray); if (UI->TimelineMode == timeline_mode_graph) { + // uint64 Keyframe_SortSize = (sizeof(sorted_comp_info) * File->Comp_Count) + (sizeof(sorted_layer) * File->Layer_Count); + // void *SortedArray = Memory_PushScratch(Memory, Keyframe_SortSize); + // Arbitrary_Zero((uint8 *)SortedArray, SortSize); graph_info GraphInfo = Graph_GetInfo(File, Memory); ImGui_Timeline_DrawGraph(File, State, Memory, UI, io, draw_list, GraphInfo, Increment, TimelineAbsolutePos, TimelineMoveSize, TimelineZoomSize, TimelineSize, TimelineSizeWithBorder, LayerIncrement); + // Memory_PopScratch(Memory, Keyframe_SortSize); } Memory_PopScratch(Memory, SortSize); @@ -815,6 +933,35 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, if (IsItemActivated) { if (!io.KeyShift && UI->TimelineMode == timeline_mode_default) Layer_DeselectAll(Memory, File->Layer_Count); + if (State->Interact_Active == interact_type_keyframe_move || + State->Interact_Active == interact_type_keyframe_rotate || + State->Interact_Active == interact_type_keyframe_scale) { + for (int a = 0; a < File->Layer_Count; a++) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); + if (!Layer->IsSelected) + continue; + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->Block_Bezier_Count) { + int k = 0; + for (;;) { + bezier_point *Point = Bezier_Lookup(Memory, Property, k); + if (!Point->Occupied) + break; + if (Point->IsSelected) { + Keyframe_Interact_Evaluate(Memory, State, Point->IsSelected, Point->Pos, Point->Pos); + } + k++; + } + } + } + } + State->Interact_Offset[0] = 0; + State->Interact_Offset[1] = 0; + State->Interact_Offset[2] = 0; + State->Interact_Offset[3] = 0; + State->Interact_Active = interact_type_none; + } UI->BoxSelect = true; } if (IsItemActive) { @@ -846,7 +993,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, } static void -ImGui_ProcessInputs(project_data *File, project_state *State, memory *Memory, ImGuiIO io) +ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) { if (ImGui::IsKeyPressed(ImGuiKey_Q)) { State->IsRunning = false; @@ -854,6 +1001,32 @@ ImGui_ProcessInputs(project_data *File, project_state *State, memory *Memory, Im if (ImGui::IsKeyPressed(ImGuiKey_A)) { State->UpdateFrame = true; } + if (UI->TimelineMode == timeline_mode_graph) { + if (ImGui::IsKeyPressed(ImGuiKey_G)) { + State->Interact_Offset[2] = io.MousePos.x; + State->Interact_Offset[3] = io.MousePos.y; + State->Interact_Active = interact_type_keyframe_move; + } else if (ImGui::IsKeyPressed(ImGuiKey_R)) { + State->Interact_Offset[2] = io.MousePos.x; + State->Interact_Offset[3] = io.MousePos.y; + State->Interact_Active = interact_type_keyframe_rotate; + } else if (ImGui::IsKeyPressed(ImGuiKey_S)) { + State->Interact_Offset[2] = io.MousePos.x; + State->Interact_Offset[3] = io.MousePos.y; + State->Interact_Active = interact_type_keyframe_scale; + } + } + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { + if (State->Interact_Active == interact_type_keyframe_move || + State->Interact_Active == interact_type_keyframe_rotate || + State->Interact_Active == interact_type_keyframe_scale) { + State->Interact_Offset[0] = 0; + State->Interact_Offset[1] = 0; + State->Interact_Offset[2] = 0; + State->Interact_Offset[3] = 0; + State->Interact_Active = interact_type_none; + } + } if (ImGui::IsKeyPressed(ImGuiKey_Space)) { State->IsPlaying ^= 1; } -- cgit v1.2.3