diff options
author | Fox Caminiti <fox@foxcam.net> | 2022-10-25 23:47:17 -0400 |
---|---|---|
committer | Fox Caminiti <fox@foxcam.net> | 2022-10-25 23:47:17 -0400 |
commit | bf01cea7274d9ac8ae13fd447c8568c95da31614 (patch) | |
tree | ed3b9fb4ae56f1e19cf3514280249954b1043070 | |
parent | 87c3fbb37141827622eeadb89189c267ed4baf87 (diff) |
graph development
-rw-r--r-- | bezier.cpp | 37 | ||||
-rw-r--r-- | createcalls.cpp | 21 | ||||
-rw-r--r-- | functions.h | 1 | ||||
-rw-r--r-- | main.cpp | 125 | ||||
-rw-r--r-- | main.h | 22 | ||||
-rw-r--r-- | my_imgui_widgets.cpp | 411 |
6 files changed, 440 insertions, 177 deletions
@@ -1,3 +1,39 @@ +static real32 Tau = 0.9; // tension + +static real32 +Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 TargetX) { + + real32 Y = 0; + + v2 m1 = (Point_P2 - Point_P0) / (2 * Tau); + v2 m2 = (Point_P3 - Point_P1) / (2 * Tau); + + real32 Precision = 0.001; + real32 t = (TargetX - Point_P0.x) / (Point_P3.x - Point_P0.x); + + for (;;) { + real32 t2 = t * t; + real32 t3 = t2 * t; + real32 mt = 1-t; + real32 mt2 = mt * mt; + real32 mt3 = mt2 * mt; + v2 Point = (Point_P0 * mt3) + (3 * Point_P1 * mt2 * t) + (3 * Point_P2 * mt * t2) + (Point_P3 * t3); + + bool32 Cond1 = (Point.x <= (TargetX - Precision)); + bool32 Cond2 = (Point.x >= (TargetX + Precision)); + + if (Cond1 || Cond2) { + t = t * TargetX / Point.x; + } else { + Y = Point.y; + break; + } + } + + return Y; +} + +#if 0 // A modified version of the bezier code in ImGui with extra features for bitmap and path interaction. // Function to convert a ratio back into a point for the bezier handles. @@ -307,3 +343,4 @@ void Mask_TriangulateAndRasterize(memory *Memory, project_layer *Layer, mask *Ma GL_RasterizeShape(Layer, Mask); } +#endif diff --git a/createcalls.cpp b/createcalls.cpp index c2122c2..d0ca03e 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -65,6 +65,27 @@ Property_GetInfo(memory *Memory, property_channel *Property) return PropertyInfo; } +static graph_info +Graph_GetInfo(project_data *File, memory *Memory) +{ + graph_info GraphInfo = {}; + 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->Keyframe_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; + } + } + GraphInfo.LowestOffset = (Layer->Vertical_Offset > GraphInfo.LowestOffset) ? Layer->Vertical_Offset : GraphInfo.LowestOffset; + } + return GraphInfo; +} + 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/functions.h b/functions.h index 4fe5a0e..07cfc25 100644 --- a/functions.h +++ b/functions.h @@ -5,6 +5,7 @@ static void Arbitrary_Zero(uint8 *Address_Write, uint64 Size); static void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size); static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction); +static real32 Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 X); # if 0 // Buffer management @@ -70,11 +70,11 @@ static uint32 RandomGlobalIncrement = 0; #include "my_imgui_widgets.cpp" #include "prenderer.cpp" #include "gl_calls.cpp" +#include "bezier.cpp" #if 0 #include "effects.cpp" #include "keyframes.cpp" #include "layer.cpp" -#include "bezier.cpp" #include "bitmap_calls.cpp" #endif @@ -226,6 +226,38 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io // for (int a = 0; a < Layer->Block_Effect_Count; a++) { // } + property_channel *Property = &Layer->x; + + if (Property->Keyframe_Count) { + bezier_point *FirstPoint = Bezier_Lookup(Memory, Property, 0); + bezier_point *LastPoint = Bezier_Lookup(Memory, Property, Property->Keyframe_Count - 1); + if (FirstPoint->Pos[0].x >= State->Frame_Current) { + Property->CurrentValue = FirstPoint->Pos[0].y; + } else if (LastPoint->Pos[0].x <= State->Frame_Current) { + Property->CurrentValue = LastPoint->Pos[0].y; + } else { + int KeyframeIndex = 0; + for (;;) { + bezier_point *Point = Bezier_Lookup(Memory, Property, KeyframeIndex + 1); + if (Point->Pos[0].x >= State->Frame_Current) + break; + KeyframeIndex++; + } + 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); + } + } + + /* + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->Keyframe_Count) { + Property->CurrentValue = State->Frame_Current * 2; + } + } + */ + transform_info T = Transform_Calculate(State, Memory, File, Layer, Comp); T.SourceBuffer = BitmapAddress; rectangle RenderRegion = {0, 0, Comp->Width, Comp->Height}; @@ -233,7 +265,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io bool32 IsRendering = true; Renderer_Start((void *)&T, CompBuffer, RenderRegion); while (IsRendering) { - SDL_Delay(2); + SDL_Delay(1); Renderer_Check(&IsRendering); // TODO(fox): Make interruptable if the render time gets too long. } @@ -328,6 +360,7 @@ int main(int argc, char *argv[]) { File->Occupied = 1; ui UI = {}; + UI.Test = ImDrawListSplitter(); block_composition *MainComp = (block_composition *)Memory_Block_AllocateAddress(&Memory, F_Precomps); @@ -369,6 +402,7 @@ int main(int argc, char *argv[]) { Layer->Col[1] = 0; Layer->Col[2] = 0; Layer->Block_Composition_Index = 0; + Layer->IsSelected = true; property_channel *Property = &Layer->x; Property->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); @@ -389,6 +423,7 @@ 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; property_channel *Property2 = &Layer->opacity; @@ -402,7 +437,6 @@ int main(int argc, char *argv[]) { Bezier2->Point[1].Pos[0] = V2(20, 1); 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; @@ -423,7 +457,6 @@ int main(int argc, char *argv[]) { Bezier3->Point[1].Type = interpolation_type_bezier; Bezier3->Point[2].Type = interpolation_type_bezier; Property3->Keyframe_Count = 3; - */ } // { // Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End); @@ -439,15 +472,75 @@ 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); - // { - // Layer_CreateFromSource(File, State, &Memory, SourceIndex, MainComp->Frame_End); - // block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(&Memory, F_Layers, File->Layer_Count - 1); - // Layer->Vertical_Offset = 5; - // Layer->Col[0] = 0; - // Layer->Col[1] = 0; - // Layer->Col[2] = 1; - // Layer->Block_Composition_Index = 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); + Layer->Vertical_Offset = 5; + Layer->Col[0] = 0; + Layer->Col[1] = 0; + Layer->Col[2] = 1; + Layer->Block_Composition_Index = 0; + Layer->IsSelected = true; + + property_channel *Property = &Layer->x; + Property->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); + Property->Block_Bezier_Count = 1; + + block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(&Memory, F_Bezier, Property->Block_Bezier_Index[0]); + Bezier->Occupied = 1; + + Bezier->Point[0].Pos[0] = V2(30, 0); + Bezier->Point[1].Pos[0] = V2(33, 250); + Bezier->Point[2].Pos[0] = V2(35, -50); + Bezier->Point[3].Pos[0] = V2(55, 0); + Bezier->Point[0].Pos[1] = V2(-1, 0); + Bezier->Point[1].Pos[1] = V2(-1, 0); + Bezier->Point[2].Pos[1] = V2(-1, 0); + Bezier->Point[3].Pos[1] = V2(-1, 0); + Bezier->Point[0].Pos[2] = V2(1, 0); + Bezier->Point[1].Pos[2] = V2(1, 0); + Bezier->Point[2].Pos[2] = V2(1, 0); + Bezier->Point[3].Pos[2] = V2(1, 0); + Bezier->Point[0].Type = interpolation_type_bezier; + 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; + + property_channel *Property2 = &Layer->opacity; + Property2->Block_Bezier_Index[0] = Memory_Block_AllocateNew(&Memory, F_Bezier); + Property2->Block_Bezier_Count = 1; + + block_bezier *Bezier2 = (block_bezier *)Memory_Block_AddressAtIndex(&Memory, F_Bezier, Property2->Block_Bezier_Index[0]); + Bezier2->Occupied = 1; + + 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; + */ + } } { @@ -609,6 +702,12 @@ int main(int argc, char *argv[]) { { Main_InputTest(File, State, &Memory, &UI, window, textureID); + if (State->IsPlaying) { + block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(&Memory, F_Precomps, File->PrincipalCompIndex); + State->Frame_Current = ((State->Frame_Current + 1) >= MainComp->Frame_Count) ? 0 : State->Frame_Current + 1; + State->UpdateFrame = true; + } + if (State->UpdateFrame) { Main_Renderer(File, State, &Memory, window, textureID, io); } @@ -77,10 +77,11 @@ enum interpolation_type }; struct bezier_point { + uint8 Occupied; v2 Pos[3]; interpolation_type Type; - uint16 ImguiID; - uint8 IsSelected; + uint8 IsSelected; //[3] + uint8 Color; }; struct block_bezier { @@ -125,15 +126,25 @@ struct sorted_layer uint16 Block_Layer_Index; }; +enum timeline_mode +{ + timeline_mode_default, + timeline_mode_graph +}; + struct ui { ImVec2 CompZoom; // In screen pixels, not percentage. ImVec2 CompPos; + ImDrawListSplitter Test; + // Under 1 is zoomed in! ImVec2 TimelinePercentZoomed; ImVec2 TimelinePercentOffset; + timeline_mode TimelineMode = timeline_mode_graph; + bool32 BoxSelect; ImVec2 DragDelta_Prev; // TODO(fox): Make native ImGui? @@ -267,6 +278,13 @@ struct property_header real32 MaxVal; }; +struct graph_info +{ + real32 MinVal = FLT_MAX; + real32 MaxVal = FLT_MIN; + real32 LowestOffset = FLT_MIN; +}; + struct property_info { real32 MinVal = FLT_MAX; diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 9589abd..545af4e 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -157,14 +157,12 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, } static void -ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp) +ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp, + ImVec2 TimelineZoomSize, ImVec2 TimelineMoveSize) { uint32 LineColor = IM_COL32(200, 200, 200, 40); - real32 TimelineZoomSize = TimelineSizeWithBorder.x / UI->TimelinePercentZoomed.x ; - real32 TimelineMoveSize = TimelineSizeWithBorder.x * UI->TimelinePercentOffset.x / UI->TimelinePercentZoomed.x; - - Assert(TimelineZoomSize > 0.0f); + Assert(TimelineZoomSize.x > 0.0f); real32 x = 0; bool32 RightmostEdge = false; @@ -175,7 +173,7 @@ ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 Time Increment *= 2; while (!RightmostEdge) { - ImVec2 Min = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + x*TimelineZoomSize, TimelineAbsolutePos.y); + ImVec2 Min = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize.x + x*TimelineZoomSize.x, TimelineAbsolutePos.y); ImVec2 Max = ImVec2(Min.x + 2, TimelineAbsolutePos.y + TimelineSizeWithBorder.y); if (Min.x < TimelineAbsolutePos.x + TimelineSizeWithBorder.x) { draw_list->AddLine(Min, Max, LineColor); @@ -196,32 +194,53 @@ ImGui_TimelineHorizontalIncrementDraw(ui *UI, ImDrawList *draw_list, ImVec2 Time } - static void -ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, uint16 CompIndex, - ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, - ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement, - sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray) +ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) { - block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); - sorted_comp_info SortedCompInfo = SortedCompArray[CompIndex]; - sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex); - - ImGui::PushID(CompIndex); + bool open = true; + ImGui::Begin("Graph info", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); - for (int i = 0; i < SortedCompInfo.LayerCount; i++) + for (int a = 0; a < File->Layer_Count; a++) { - ImGui::PushID(i); + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); + if (!Layer->IsSelected) + continue; - sorted_layer SortEntry = SortedLayerInfo[i]; - uint32 Index_Physical = SortEntry.Block_Layer_Index; - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); + ImGui::Text(String->Char); + + ImGui::PushID(a); + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + if (Property->Keyframe_Count) { + ImGui::PushID(Property); + ImGui::Text(Property->Name); + ImGui::PopID(); + } + } + + ImGui::PopID(); + } + + ImGui::End(); +} + +static void +ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, graph_info GraphInfo, + ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, + ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement) +{ + UI->Test.Split(draw_list, 2); + + 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; int32 Frame_Start = Layer->Frame_Start; int32 Frame_End = Layer->Frame_End; - real32 Vertical_Offset = Layer->Vertical_Offset; - if (Layer->IsSelected) - Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset); + real32 Vertical_Offset = GraphInfo.LowestOffset; // Layer->Vertical_Offset; ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); @@ -231,33 +250,166 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; - if (UI->BoxSelect) { - bool32 Test = 0; - if (io.MouseClickedPos[0].y < io.MousePos.y) - Test = (Layer_ScreenPos_Min.y >= io.MouseClickedPos[0].y && Layer_ScreenPos_Min.y <= io.MousePos.y); - else - Test = (Layer_ScreenPos_Max.y <= io.MouseClickedPos[0].y && Layer_ScreenPos_Max.y >= io.MousePos.y); + ImGui::PushID(a); - if (Test) { - if (!Layer->IsSelected) { - Layer->IsSelected = true; + ImU32 col = IM_COL32(255, 255, 255, 255); + + for (int h = 0; h < AmountOf(Layer->Property); h++) { + property_channel *Property = &Layer->Property[h]; + ImGui::PushID(Property); + if (Property->Keyframe_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 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]) }; + 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); + } + + 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); + + 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); + } + + UI->Test.SetCurrentChannel(draw_list, 0); + + if (k != 0) { + if (PointAddress[0]->Type == interpolation_type_bezier && PointAddress[1]->Type == interpolation_type_bezier) { + draw_list->AddBezierCubic(Keyframe_ScreenPos[OldIdx], Keyframe_ScreenPos[OldIdx + 2], + Keyframe_ScreenPos[NewIdx + 1], Keyframe_ScreenPos[NewIdx], col, 1.0f, 0); + } else { + draw_list->AddLine(Keyframe_ScreenPos[0], Keyframe_ScreenPos[3], col, 1.0f); + } + } } - } else if (!io.KeyShift) { - Layer->IsSelected = false; } + ImGui::PopID(); } + ImGui::PopID(); + } + UI->Test.Merge(draw_list); +} + + +static void +ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, uint16 CompIndex, + ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, + ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement, + sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_info SortedCompInfo = SortedCompArray[CompIndex]; + sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex); + + ImGui::PushID(CompIndex); - ImVec2 ResizeSize = ImVec2(Increment.x * 0.45 * TimelineZoomSize.x, Layer_ScreenSize.y); - ImVec2 ResizePos[2] = { Layer_ScreenPos_Min, ImVec2(Layer_ScreenPos_Max.x - ResizeSize.x, Layer_ScreenPos_Min.y) }; - for (int b = 0; b < 2; b++) { - ImGui::PushID(b); - ImGui::SetCursorScreenPos(ResizePos[b]); - ImGui::Button("##layer_resize", ResizeSize); + if (UI->TimelineMode == timeline_mode_default) { - if (ImGui::IsItemHovered()) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + for (int i = 0; i < SortedCompInfo.LayerCount; i++) + { + sorted_layer SortEntry = SortedLayerInfo[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + + int32 Frame_Start = Layer->Frame_Start; + int32 Frame_End = Layer->Frame_End; + real32 Vertical_Offset = Layer->Vertical_Offset; + if (Layer->IsSelected) + Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Frame_Start, &Frame_End, &Vertical_Offset); + ImVec2 Layer_LocalPos = ImVec2(Frame_Start, Vertical_Offset); + ImVec2 Layer_LocalSize = ImVec2(Frame_End - Frame_Start, Layer->Vertical_Height); + + ImVec2 Layer_LocalPos_Ratio = (Layer_LocalPos * Increment); + ImVec2 Layer_LocalSize_Ratio = Layer_LocalSize * Increment; + ImVec2 Layer_ScreenPos_Min = TimelineAbsolutePos + TimelineMoveSize + (Layer_LocalPos_Ratio * TimelineZoomSize); + ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); + ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; + + ImGui::PushID(i); + + if (UI->BoxSelect && UI->TimelineMode == timeline_mode_default) { + bool32 Test = 0; + if (io.MouseClickedPos[0].y < io.MousePos.y) + Test = (Layer_ScreenPos_Min.y >= io.MouseClickedPos[0].y && Layer_ScreenPos_Min.y <= io.MousePos.y); + else + Test = (Layer_ScreenPos_Max.y <= io.MouseClickedPos[0].y && Layer_ScreenPos_Max.y >= io.MousePos.y); + + if (Test) { + if (!Layer->IsSelected) { + Layer->IsSelected = true; + } + } else if (!io.KeyShift) { + Layer->IsSelected = false; + } + } + + + ImVec2 ResizeSize = ImVec2(Increment.x * 0.45 * TimelineZoomSize.x, Layer_ScreenSize.y); + ImVec2 ResizePos[2] = { Layer_ScreenPos_Min, ImVec2(Layer_ScreenPos_Max.x - ResizeSize.x, Layer_ScreenPos_Min.y) }; + for (int b = 0; b < 2; b++) { + ImGui::PushID(b); + ImGui::SetCursorScreenPos(ResizePos[b]); + ImGui::Button("##layer_resize", ResizeSize); + + if (ImGui::IsItemHovered()) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + if (ImGui::IsItemActivated()) { + if (!Layer->IsSelected) { + if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count); + State->MostRecentlySelectedLayer = i; + Layer->IsSelected = true; + } + } + if (ImGui::IsItemActive()) { + if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)) { + State->Interact_Active = interact_type_layer_timeadjust; + ImVec2 DragDelta = ImGui::GetMouseDragDelta(); + DragDelta = DragDelta + (ImVec2(UI->Warp_X, UI->Warp_Y) * TimelineSize); + + State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) * Comp->Frame_Count; + State->Interact_Offset[1] = b; + DebugWatchVar("Offset1", &State->Interact_Offset[0], d_float); + } + } + if (ImGui::IsItemDeactivated()) { + if (State->Interact_Active == interact_type_layer_timeadjust) { + for (int a = 0; a < File->Layer_Count; a++) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); + if (Layer->IsSelected) { + Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End, &Layer->Vertical_Offset); + } + } + State->Interact_Active = interact_type_none; + State->Interact_Offset[0] = 0; + State->Interact_Offset[1] = 0; + } + } + + ImGui::PopID(); } + + ImGui::SetCursorScreenPos(Layer_ScreenPos_Min); + ImGui::InvisibleButton("##layer_mid", Layer_ScreenSize, ImGuiMouseButton_Left); + if (ImGui::IsItemActivated()) { if (!Layer->IsSelected) { if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count); @@ -265,19 +417,36 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem Layer->IsSelected = true; } } + if (ImGui::IsItemActive()) { if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)) { - State->Interact_Active = interact_type_layer_timeadjust; + if (State->Interact_Active == interact_type_none) { + State->Interact_Active = interact_type_layer_move; + // TODO(fox): Selected layers inside precomps will have interactions doubled, + // so I'm forcing interaction to only be with members of the same precomp. + // Could be made more intuitive later. + Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, Layer->Block_Composition_Index, File->PrincipalCompIndex); + } ImVec2 DragDelta = ImGui::GetMouseDragDelta(); DragDelta = DragDelta + (ImVec2(UI->Warp_X, UI->Warp_Y) * TimelineSize); State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) * Comp->Frame_Count; - State->Interact_Offset[1] = b; - DebugWatchVar("Offset1", &State->Interact_Offset[0], d_float); + State->Interact_Offset[1] = (DragDelta.y / TimelineSizeWithBorder.y * UI->TimelinePercentZoomed.y) * LayerIncrement; + + /* + if (UI->DragDelta_Prev.x != 0) { + ImVec2 Offset_Old = (UI->DragDelta_Prev / TimelineSizeWithBorder * UI->TimelinePercentZoomed) * ImVec2(MainComp->Frame_Count, LayerIncrement); + if ((int32)State->Interact_Offset[1] != (int32)Offset_Old.y) + State->UpdateFrame = true; + } + + UI->DragDelta_Prev = DragDelta; + */ } } + if (ImGui::IsItemDeactivated()) { - if (State->Interact_Active == interact_type_layer_timeadjust) { + if (State->Interact_Active == interact_type_layer_move) { for (int a = 0; a < File->Layer_Count; a++) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); if (Layer->IsSelected) { @@ -289,62 +458,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem State->Interact_Offset[1] = 0; } } - ImGui::PopID(); } - ImGui::SetCursorScreenPos(Layer_ScreenPos_Min); - ImGui::InvisibleButton("##layer_mid", Layer_ScreenSize, ImGuiMouseButton_Left); - - if (ImGui::IsItemActivated()) { - if (!Layer->IsSelected) { - if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count); - State->MostRecentlySelectedLayer = i; - Layer->IsSelected = true; - } - } - - if (ImGui::IsItemActive()) { - if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1)) { - if (State->Interact_Active == interact_type_none) { - State->Interact_Active = interact_type_layer_move; - // TODO(fox): Selected layers inside precomps will have interactions doubled, - // so I'm forcing interaction to only be with members of the same precomp. - // Could be made more intuitive later. - Layer_RecursiveDeselect(Memory, SortedCompArray, SortedLayerArray, Layer->Block_Composition_Index, File->PrincipalCompIndex); - } - ImVec2 DragDelta = ImGui::GetMouseDragDelta(); - DragDelta = DragDelta + (ImVec2(UI->Warp_X, UI->Warp_Y) * TimelineSize); - - State->Interact_Offset[0] = (DragDelta.x / TimelineSizeWithBorder.x * UI->TimelinePercentZoomed.x) * Comp->Frame_Count; - State->Interact_Offset[1] = (DragDelta.y / TimelineSizeWithBorder.y * UI->TimelinePercentZoomed.y) * LayerIncrement; - - /* - if (UI->DragDelta_Prev.x != 0) { - ImVec2 Offset_Old = (UI->DragDelta_Prev / TimelineSizeWithBorder * UI->TimelinePercentZoomed) * ImVec2(MainComp->Frame_Count, LayerIncrement); - if ((int32)State->Interact_Offset[1] != (int32)Offset_Old.y) - State->UpdateFrame = true; - } - - UI->DragDelta_Prev = DragDelta; - */ - } - } - - if (ImGui::IsItemDeactivated()) { - if (State->Interact_Active == interact_type_layer_move) { - for (int a = 0; a < File->Layer_Count; a++) { - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); - if (Layer->IsSelected) { - Layer_Interact_Evaluate(Memory, State, Index_Physical, SortedCompInfo, SortedLayerInfo, &Layer->Frame_Start, &Layer->Frame_End, &Layer->Vertical_Offset); - } - } - State->Interact_Active = interact_type_none; - State->Interact_Offset[0] = 0; - State->Interact_Offset[1] = 0; - } - } - ImGui::PopID(); } // Check if any layers are precomps; we want to test hit detection for them _after_ the layers in front. @@ -404,10 +520,9 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem // TODO(fox): Draw calls are executed in reverse order, so we need another iteration to draw layers on top of precomps. // The ImDrawListSplitter API can probably do this without another iteration. + for (int i = 0; i < SortedCompInfo.LayerCount; i++) { - ImGui::PushID(i); - sorted_layer SortEntry = SortedLayerInfo[i]; uint32 Index_Physical = SortEntry.Block_Layer_Index; block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); @@ -426,57 +541,18 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImVec2 Layer_ScreenPos_Max = TimelineAbsolutePos + TimelineMoveSize + ((Layer_LocalPos_Ratio + Layer_LocalSize_Ratio) * TimelineZoomSize); ImVec2 Layer_ScreenSize = Layer_ScreenPos_Max - Layer_ScreenPos_Min; - ImU32 col = IM_COL32(255, 255, 255, 255); - - int NumberOfActiveProperties = 0; - for (int h = 0; h < AmountOf(Layer->Property); h++) { - property_channel *Property = &Layer->Property[h]; - if (Property->Keyframe_Count) - NumberOfActiveProperties++; - } - - for (int h = 0; h < AmountOf(Layer->Property); h++) { - property_channel *Property = &Layer->Property[h]; - ImGui::PushID(Property); - if (Property->Keyframe_Count) { - property_info PropertyInfo = Property_GetInfo(Memory, Property); - real32 Y_Increment = 1 / (PropertyInfo.MaxVal - PropertyInfo.MinVal); - bezier_point *PointAddress[2] = {}; - ImVec2 Keyframe_ScreenPos[2] = {}; - ImVec2 Keyframe_ScreenPos_L[2] = {}; - ImVec2 Keyframe_ScreenPos_R[2] = {}; - for (int k = 0; k < (Property->Keyframe_Count + 1); k++) { - int Idx = k % 2; - 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]) }; - ImVec2 Keyframe_LocalPos_Ratio[3]; - for (int b = 0; b < 3; b++) { - Keyframe_LocalPos_Ratio[b] = (Keyframe_LocalPos[b] - ImVec2(0, PropertyInfo.MinVal)) * ImVec2(Increment.x, Y_Increment); - } - - Keyframe_ScreenPos[Idx] = Layer_ScreenPos_Min + ((Keyframe_LocalPos_Ratio[0] - ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); - Keyframe_ScreenPos_L[Idx] = Layer_ScreenPos_Min + ((Keyframe_LocalPos_Ratio[1] - ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); - Keyframe_ScreenPos_R[Idx] = Layer_ScreenPos_Min + ((Keyframe_LocalPos_Ratio[2] - ImVec2(0, 0.5)) * TimelineZoomSize) + ImVec2(0, Layer_ScreenSize.y/2); - - draw_list->AddCircle(Keyframe_ScreenPos[Idx], 2, col, 16, 1); - if (k != 0 && k != Property->Keyframe_Count) { - if (PointAddress[0]->Type == interpolation_type_bezier && PointAddress[1]->Type == interpolation_type_bezier) { - draw_list->AddBezierCubic(Keyframe_ScreenPos[!Idx], Keyframe_ScreenPos_R[!Idx], - Keyframe_ScreenPos_L[Idx], Keyframe_ScreenPos[Idx], col, 1.0f, 0); - } else { - draw_list->AddLine(Keyframe_ScreenPos[0], Keyframe_ScreenPos[1], col, 1.0f); - } - } - } - } - ImGui::PopID(); + ImU32 LayerColor = 0; + ImU32 BorderColor = 0; + if (UI->TimelineMode == timeline_mode_graph) { + LayerColor = ImColor(Layer->Col[0], Layer->Col[1], Layer->Col[2], 0.2f); + BorderColor = ImColor(0.3, 0.3, 0.3, 1.0f); + } else { + LayerColor = ImColor(Layer->Col[0], Layer->Col[1], Layer->Col[2], 1.0f); + BorderColor = ImColor(0.2, 0.2, 0.2, 1.0f); } - draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, - ImColor(Layer->Col[0], Layer->Col[1], Layer->Col[2], 1.0f)); - draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(1.0f, 1.0f, 1.0f, 0.5f), 2); + draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, LayerColor); + draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, BorderColor, 2); // block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); // draw_list->AddText(Layer_ScreenPos_Min, 0xFFFFFFFF, String->Char); @@ -484,16 +560,17 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem draw_list->AddRectFilled(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(0.25f, 0.25f, 0.25f, 0.5f), 2); draw_list->AddRect(Layer_ScreenPos_Min, Layer_ScreenPos_Max, ImColor(1.0f, 1.0f, 1.0f, 0.5f), 2); } - - - ImGui::PopID(); } + ImGui::PopID(); } static void ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io) { + if (UI->TimelineMode == timeline_mode_graph) + ImGui_GraphInfo(File, State, Memory, UI, io); + ImVec2 FramePadding = ImGui::GetStyle().FramePadding; ImVec2 ItemSpacing = ImGui::GetStyle().ItemSpacing; ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); @@ -551,11 +628,11 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, UI->TimelinePercentZoomed = ImVec2(1, 1); } - ImGui_TimelineHorizontalIncrementDraw(UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp); - ImVec2 TimelineZoomSize = TimelineSizeWithBorder / UI->TimelinePercentZoomed; ImVec2 TimelineMoveSize = TimelineSizeWithBorder * UI->TimelinePercentOffset / UI->TimelinePercentZoomed; + ImGui_TimelineHorizontalIncrementDraw(UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, *MainComp, TimelineZoomSize, TimelineMoveSize); + ImVec2 Increment = ImVec2((real32)1 / MainComp->Frame_Count, (real32)1 / LayerIncrement); uint64 SortSize = (sizeof(sorted_comp_info) * File->Comp_Count) + (sizeof(sorted_layer) * File->Layer_Count); @@ -570,6 +647,13 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, TimelineSize, TimelineSizeWithBorder, LayerIncrement, SortedCompArray, SortedLayerArray); + if (UI->TimelineMode == timeline_mode_graph) { + 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, SortSize); ImVec2 MouseDelta = io.MouseDelta / TimelineSize; @@ -730,7 +814,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, } if (IsItemActivated) { - if (!io.KeyShift) Layer_DeselectAll(Memory, File->Layer_Count); + if (!io.KeyShift && UI->TimelineMode == timeline_mode_default) Layer_DeselectAll(Memory, File->Layer_Count); UI->BoxSelect = true; } if (IsItemActive) { @@ -739,15 +823,15 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, IM_COL32(0, 0, 200, 50)); } + if (IsItemDeactivated) { + UI->BoxSelect = false; + } + if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) { UI->Warp_X = 0; UI->Warp_Y = 0; } - if (IsItemDeactivated) { - UI->BoxSelect = false; - } - draw_list->PopClipRect(); ImGui::PopClipRect(); @@ -770,6 +854,9 @@ ImGui_ProcessInputs(project_data *File, project_state *State, memory *Memory, Im if (ImGui::IsKeyPressed(ImGuiKey_A)) { State->UpdateFrame = true; } + if (ImGui::IsKeyPressed(ImGuiKey_Space)) { + State->IsPlaying ^= 1; + } if (ImGui::IsKeyPressed(ImGuiKey_T)) { for (int a = 0; a < File->Layer_Count; a++) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, a); @@ -1840,7 +1927,7 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, memory *Memory, Point1_ScreenPos, Point1_ScreenPos, col2, 6.0f, 0); } else if (Point1->HandleBezier) { draw_list->AddBezierCubic(Point0_ScreenPos, Point0_ScreenPos, - Point1_ScreenPos_Left, Point1_ScreenPos, col2, 6.0f, 0); + Point1_ScreenPos_Left, Point1_ScreenPos,col2, 6.0f, 0); } else { draw_list->AddLine(Point0_ScreenPos, Point1_ScreenPos, col2, 6.0f); } |