From 36a51c19b411206213b27e30106fff161251b652 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Sun, 27 Nov 2022 11:45:11 -0500 Subject: graph fixes --- .gitignore | 3 + createcalls.cpp | 35 +++++++++ imgui_helper_widgets.cpp | 19 +++++ main.cpp | 11 +++ main.h | 14 ++-- my_imgui_widgets.cpp | 183 ++++++++++++++++++++++------------------------- 6 files changed, 161 insertions(+), 104 deletions(-) diff --git a/.gitignore b/.gitignore index 87b5b14..caf2550 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ compile_commands.json build_ops imgui.ini test +test2 +test3 +test4 diff --git a/createcalls.cpp b/createcalls.cpp index de81c1e..d6cfc6c 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -203,6 +203,7 @@ Bezier_EvaluateValue(project_state *State, bezier_point *PointAddress, v2 *Pos, } } + static void Bezier_Add(memory *Memory, property_channel *Property, bezier_point PointData) { @@ -481,6 +482,40 @@ Property_GetSortedArray(uint16 *SortedPropertyArray, int i, int h) return SortedPropertyArray + (i * 8 * MAX_KEYFRAMES_PER_BLOCK) + (h * MAX_KEYFRAMES_PER_BLOCK); } +static void +Bezier_Commit(project_data *File, project_state *State, memory *Memory, uint16 *SortedPropertyArray) { + History_Entry_Commit(Memory, "Move keyframe"); + int h = 0, c = 0, i = 0; + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + if (!Layer->IsSelected) + continue; + for (int h = 0; h < AmountOf(Layer->Property); h++) { + uint16 *ArrayLocation = Property_GetSortedArray(SortedPropertyArray, i, h); + property_channel *Property = &Layer->Property[h]; + for (int p = 0; p < Property->Keyframe_Count; p++) { + int k = ArrayLocation[p]; + bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, k); + if (PointAddress->IsSelected) { + v2 NewPos[3]; + Bezier_EvaluateValue(State, PointAddress, NewPos); + History_Action_Swap(Memory, F_Bezier, sizeof(PointAddress->Pos), &PointAddress->Pos); + PointAddress->Pos[0] = NewPos[0]; + PointAddress->Pos[1] = NewPos[1]; + PointAddress->Pos[2] = NewPos[2]; + } + } + } + } + History_Entry_End(Memory); + 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; + State->Interact_Modifier = 0; +} + void Clipboard_Store(project_data *File, project_state *State, memory *Memory, sorted_comp_info *SortedCompInfo, sorted_layer *SortedLayerInfo, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { int LocalOffset = 0; diff --git a/imgui_helper_widgets.cpp b/imgui_helper_widgets.cpp index c27e947..e55a5e7 100644 --- a/imgui_helper_widgets.cpp +++ b/imgui_helper_widgets.cpp @@ -84,3 +84,22 @@ ImGui_Brush_CalcMousePos(project_state *State, ImGuiIO &io, ImVec2 MouseDelta, i } return MousePos; } + +static void +ImGui_TestBoxSelection_Point(ImVec2 Pos, ImGuiIO &io, bool32 *Test) +{ + 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 (Pos.y >= Y_Top && Pos.y <= Y_Bottom && + Pos.x >= X_Left && Pos.x <= X_Right) + { + if (!(*Test)) { + *Test = 1; + } + } else if (!io.KeyShift) { + *Test = 0; + } +} diff --git a/main.cpp b/main.cpp index 61bdd03..a7788ad 100644 --- a/main.cpp +++ b/main.cpp @@ -177,7 +177,15 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, #endif ImGui_Popups(File, State, UI, Memory, io); + if (State->FocusedWindow == focus_viewport && State->SetFocus) { + ImGui::SetNextWindowFocus(); + State->SetFocus = false; + } ImGui_Viewport(File, State, UI, Memory, io, textureID, Sorted.CompArray, Sorted.LayerArray); + if (State->FocusedWindow == focus_timeline && State->SetFocus) { + ImGui::SetNextWindowFocus(); + State->SetFocus = false; + } ImGui_Timeline(File, State, Memory, UI, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyInfo, Sorted.PropertyArray); ImGui_File(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray); ImGui_PropertiesPanel(File, State, UI, Memory, io); @@ -762,6 +770,9 @@ int main(int argc, char *argv[]) { ImGui::StyleColorsDark(); + ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, + ImGui::ColorConvertFloat4ToU32(ImVec4(0.0f, 0.0f, 0.0f, 0.1f))); + ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); diff --git a/main.h b/main.h index b2f2ed3..3b9cd38 100644 --- a/main.h +++ b/main.h @@ -80,7 +80,7 @@ struct bezier_point { uint8 Occupied; v2 Pos[3]; interpolation_type Type; - uint8 IsSelected; + bool32 IsSelected; uint8 PointSelect[3]; uint8 Color; }; @@ -94,10 +94,7 @@ enum selection_type { selection_none, selection_layer, - selection_effect, - selection_keyframe, - selection_maskpoint, - selection_source + selection_keyframe }; struct clipboard_channel { @@ -366,7 +363,11 @@ struct project_state uint64 ClipboardSize; int16 MostRecentlySelectedLayer = -1; - // selection_type RecentSelectionType = selection_none; + + // NOTE(fox): Try to use this only where you actually need it (the + // ambiguous case of copying keyframes versus layers), since this state + // transfer will get buggy if you expand it to everything. + selection_type RecentSelectionType = selection_none; interact_type Interact_Active; int32 Interact_Modifier; @@ -400,6 +401,7 @@ struct project_state bool32 BoxSelect; focused_window FocusedWindow; // Convenience for adding window-specific hotkeys. + bool32 SetFocus; v2 TempZoomRatio = V2(1, 1); }; diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 16be2e1..cd23b98 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -1004,8 +1004,10 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, bool open = true; ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) + if (ImGui::IsWindowHovered(ImGuiFocusedFlags_ChildWindows)) { + State->SetFocus = true; State->FocusedWindow = focus_viewport; + } block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); @@ -1138,6 +1140,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, UI->CompPos.y += io.MouseDelta.y; } + bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z) || ImGui::IsMouseDown(ImGuiMouseButton_Right); if (State->Tool == tool_brush && State->Interact_Active == interact_type_brush) { Assert(State->Brush.LayerToPaint_Index != -1); @@ -1184,6 +1187,13 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, } } + if (ImGui::IsKeyDown(ImGuiKey_Z)) { + if (IsActive) + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); + else + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + } + real32 Distance = 0; if (IsActive) { if (ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f)) @@ -1312,7 +1322,7 @@ static void ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { bool open = true; - ImGui::Begin("Graph info", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + ImGui::Begin("Graph info"); int h = 0, c = 0, i = 0; while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) @@ -1348,10 +1358,11 @@ ImGui_GraphInfo(project_data *File, project_state *State, memory *Memory, ui *UI static void ImGui_Timeline_DrawKeySheet(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, ImDrawList *draw_list, property_channel *Property, uint16 *ArrayLocation, - ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, + ImVec2 Increment, ImVec2 TimelineAbsolutePos, ImVec2 GraphPos, ImVec2 TimelineMoveSize, ImVec2 TimelineZoomSize, ImVec2 TimelineSize, ImVec2 TimelineSizeWithBorder, real32 LayerIncrement) { ImGui::PushID(Property); + for (int p = 0; p < Property->Keyframe_Count; p++) { int k = ArrayLocation[p]; bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, k); @@ -1360,48 +1371,60 @@ ImGui_Timeline_DrawKeySheet(project_data *File, project_state *State, memory *Me Bezier_EvaluateValue(State, PointAddress, PointPos); real32 LocalPos_Ratio_X = PointPos[0].x * Increment.x; - real32 Keyframe_ScreenPos_X = TimelineAbsolutePos.x + TimelineMoveSize.x + LocalPos_Ratio_X * TimelineZoomSize.x; - - ImVec2 Keyframe_ScreenPos(Keyframe_ScreenPos_X, TimelineAbsolutePos.y); - - if (State->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.y >= Y_Top && Keyframe_ScreenPos.y <= Y_Bottom && - Keyframe_ScreenPos.x >= X_Left && Keyframe_ScreenPos.x <= X_Right) - { - if (!PointAddress->IsSelected) { - PointAddress->IsSelected = 1; - } - } else if (!io.KeyShift) { - PointAddress->IsSelected = 0; - } - } - - ImVec2 ButtonSize(16, 16); - - ImGui::PushID(p); - - ImU32 PointCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f); - ImU32 LineCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.5f, 1.0f) : ImColor(0.4f, 0.4f, 0.4f, 1.0f); - ImGui::SetCursorScreenPos(Keyframe_ScreenPos - (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) { - PointAddress->IsSelected = 1; - } + real32 Keyframe_ScreenPos_X = GraphPos.x + TimelineMoveSize.x + LocalPos_Ratio_X * TimelineZoomSize.x; + + ImVec2 Keyframe_ScreenPos(Keyframe_ScreenPos_X, GraphPos.y); + + if (State->BoxSelect) { + ImGui_TestBoxSelection_Point(Keyframe_ScreenPos, io, &PointAddress->IsSelected); + } + + ImVec2 ButtonSize(16, 16); + + ImGui::PushID(p); + + ImU32 PointCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f); + ImU32 LineCol = (PointAddress->IsSelected) ? ImColor(0.8f, 0.5f, 0.5f, 1.0f) : ImColor(0.4f, 0.4f, 0.4f, 1.0f); + ImGui::SetCursorScreenPos(Keyframe_ScreenPos - (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); + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + } + + if (IsItemActivated) { + PointAddress->IsSelected = 1; + } + + if (IsItemActive) { + if (State->Interact_Active == interact_type_none) { + State->Interact_Offset[2] = io.MousePos.x; + State->Interact_Offset[3] = io.MousePos.y; + State->Interact_Active = interact_type_keyframe_move; + } else { + Assert(State->Interact_Active == interact_type_keyframe_move); + ImGui_WarpMouse(State, io.MousePos, TimelineAbsolutePos, TimelineAbsolutePos + TimelineSizeWithBorder); + ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); + DragDelta = DragDelta + (ImVec2(State->Warp_X, State->Warp_Y) * TimelineSize); + if (io.MouseDelta.x || io.MouseDelta.y) { + State->UpdateFrame = true; + } + if (State->Interact_Active == interact_type_keyframe_move) { + State->Interact_Offset[0] = (DragDelta.x / TimelineZoomSize.x) / Increment.x; + State->Interact_Offset[1] = DragDelta.y; + } + } + } + + if (IsItemDeactivated) { + } draw_list->AddCircleFilled(Keyframe_ScreenPos, 4, PointCol); @@ -1453,6 +1476,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor State->Interact_Offset[0] = atan((Slope_Old - Slope_New) / (1 + Slope_Old * Slope_New)); */ } + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); } for (int h = 0; h < AmountOf(Layer->Property); h++) { @@ -1505,20 +1529,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor } if (State->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 (!PointAddress[Idx]->IsSelected) { - PointAddress[Idx]->IsSelected = 1; - } - } else if (!io.KeyShift) { - PointAddress[Idx]->IsSelected = 0; - } + ImGui_TestBoxSelection_Point(Keyframe_ScreenPos[NewIdx], io, &PointAddress[Idx]->IsSelected); } State->Test.SetCurrentChannel(draw_list, 1); @@ -1540,8 +1551,10 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left); bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right); - if (IsHovered) + if (IsHovered) { PointCol = ImColor(1.0f, 0.8f, 0.8f, 1.0f); + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + } if (IsItemActivated) { PointAddress[Idx]->IsSelected = b+1; @@ -1862,7 +1875,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem uint16 *ArrayLocation = Property_GetSortedArray(SortedPropertyArray, i, h); ImVec2 GraphPos(TimelineAbsolutePos.x, Layer_ScreenPos_Min.y + (Layer_ScreenSize.y * 2) + (Layer_ScreenSize.y * Channel)); ImGui_Timeline_DrawKeySheet(File, State, Memory, UI, io, draw_list, Property, ArrayLocation, - Increment, GraphPos, TimelineMoveSize, TimelineZoomSize, + Increment, TimelineAbsolutePos, GraphPos, TimelineMoveSize, TimelineZoomSize, TimelineSize, TimelineSizeWithBorder, LayerIncrement); Channel++; } @@ -1917,17 +1930,19 @@ static void ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_comp_info *SortedCompArray, sorted_layer *SortedLayerArray, sorted_property_info *SortedPropertyInfo, uint16 *SortedPropertyArray) { - if (State->TimelineMode == timeline_mode_graph) - ImGui_GraphInfo(File, State, Memory, UI, io, SortedPropertyInfo, SortedPropertyArray); - ImVec2 FramePadding = ImGui::GetStyle().FramePadding; ImVec2 ItemSpacing = ImGui::GetStyle().ItemSpacing; ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); // makes setting up the layout easier ImGui::Begin("Timeline", NULL); - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) + if (ImGui::IsWindowHovered(ImGuiFocusedFlags_ChildWindows)) { + State->SetFocus = true; State->FocusedWindow = focus_timeline; + } + + if (State->TimelineMode == timeline_mode_graph) + ImGui_GraphInfo(File, State, Memory, UI, io, SortedPropertyInfo, SortedPropertyArray); real32 FontHeight = ImGui::GetFontSize(); @@ -2188,36 +2203,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, if (State->Interact_Active == interact_type_keyframe_move || State->Interact_Active == interact_type_keyframe_rotate || State->Interact_Active == interact_type_keyframe_scale) { - History_Entry_Commit(Memory, "Move keyframe"); - int h = 0, c = 0, i = 0; - while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); - if (!Layer->IsSelected) - continue; - for (int h = 0; h < AmountOf(Layer->Property); h++) { - uint16 *ArrayLocation = Property_GetSortedArray(SortedPropertyArray, i, h); - property_channel *Property = &Layer->Property[h]; - for (int p = 0; p < Property->Keyframe_Count; p++) { - int k = ArrayLocation[p]; - bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, k); - if (PointAddress->IsSelected) { - v2 NewPos[3]; - Bezier_EvaluateValue(State, PointAddress, NewPos); - History_Action_Swap(Memory, F_Bezier, sizeof(PointAddress->Pos), &PointAddress->Pos); - PointAddress->Pos[0] = NewPos[0]; - PointAddress->Pos[1] = NewPos[1]; - PointAddress->Pos[2] = NewPos[2]; - } - } - } - } - History_Entry_End(Memory); - 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; - State->Interact_Modifier = 0; + Bezier_Commit(File, State, Memory, SortedPropertyArray); } State->BoxSelect = true; } @@ -2393,15 +2379,16 @@ ImGui_Popups(project_data *File, project_state *State, ui *UI, memory *Memory, I { ImGui::OpenPopup("Save as"); ImVec2 Size(300, 300); - Assert(0); - ImGui::SetNextWindowPos(ImVec2(300, 800)); + ImGuiViewport *Viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(Viewport->GetCenter(), 0, ImVec2(0.5, 0.5)); ImGui::SetNextWindowSize(Size); ImGui::SetKeyboardFocusHere(); } break; case popup_keybinds: { ImGui::OpenPopup("Keybinds"); - ImGui::SetNextWindowPos(ImVec2(300, 800)); + ImGuiViewport *Viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(Viewport->GetCenter(), 0, ImVec2(0.5, 0.5)); ImGui::SetNextWindowSize(ImVec2(500, 300)); ImGui::SetKeyboardFocusHere(); } break; -- cgit v1.2.3