From bc1335ebbf68c805a19303469bb49759296a645f Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Sat, 1 Oct 2022 23:01:56 -0400 Subject: finally semi-stable graph offsetting --- createcalls.cpp | 6 +- keyframes.cpp | 8 +++ main.cpp | 3 + main.h | 16 ++++- my_imgui_widgets.cpp | 189 ++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 168 insertions(+), 54 deletions(-) diff --git a/createcalls.cpp b/createcalls.cpp index 91ae66a..fb949a9 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -294,9 +294,9 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory) Source_Generate(File, State, Memory, SourceString); Layer_CreateFromSource(File, State, Memory, &File->Source[0]); - Keyframe_Insert(&File->Layer[0]->x, Memory, 00, 00); - Keyframe_Insert(&File->Layer[0]->x, Memory, 05, 05); - Keyframe_Insert(&File->Layer[0]->x, Memory, 10, 10); + Keyframe_Insert(&File->Layer[0]->x, Memory, 00, -10); + Keyframe_Insert(&File->Layer[0]->x, Memory, 01, 0); + Keyframe_Insert(&File->Layer[0]->x, Memory, 05, 10); File->Layer[0]->x.IsToggled = true; SelectLayer(File->Layer[0], State, 0); // AddEffect(File->Layer[0], Memory, 1); diff --git a/keyframes.cpp b/keyframes.cpp index 451f2b6..2bcec9d 100644 --- a/keyframes.cpp +++ b/keyframes.cpp @@ -272,6 +272,14 @@ Keyframe_FindClosestIndex(property_channel *Property, int32 CurrentFrame, bool32 keyframe *Keyframe = KeyframeLookup(Property, Index); *Overlapping = (Keyframe->FrameNumber == CurrentFrame); return Index; + } else if (Index == 0) { + keyframe *CurrentKeyframe = KeyframeLookup(Property, Index); + if (CurrentKeyframe->FrameNumber == CurrentFrame) { + *Overlapping = true; + return Index; + } else { + Assert(0); + } } else { Index = Index / 2; } diff --git a/main.cpp b/main.cpp index 5d12d91..60504e1 100644 --- a/main.cpp +++ b/main.cpp @@ -182,6 +182,9 @@ int main(int argc, char *argv[]) { ui UI = {}; + UI.Y_TimelinePercentZoomed = UI.Default_Y_TimelinePercentZoomed; + UI.Y_TimelinePercentOffset = UI.Default_Y_TimelinePercentOffset; + // shm_unlink("/testl"); // int fd = shm_open("/testl", O_CREAT | O_EXCL | O_RDWR, // S_IRUSR | S_IWUSR); diff --git a/main.h b/main.h index 42befc8..30025b3 100644 --- a/main.h +++ b/main.h @@ -491,8 +491,20 @@ struct ui real32 TimelinePercentZoomed = 1.0f; real32 TimelinePercentOffset = 0.0f; - real32 Y_TimelinePercentZoomed = 1.0f; - real32 Y_TimelinePercentOffset = 0.0f; + real32 Default_Y_TimelinePercentZoomed = 2.0f; + real32 Default_Y_TimelinePercentOffset = 0.5f; + + real32 Y_TimelinePercentZoomed; + real32 Y_TimelinePercentOffset; + + bool32 IsDragging; + real32 TempVal; + + real32 Y_MaxVal; + real32 Y_MinVal; + + real32 Display_Y_MaxVal; + real32 Display_Y_MinVal; // Note that I don't use "zoom" to mean the scale in relation to the // original (i.e. default = 1.0f); it's the literal screen size in pixels diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index 737b7d2..d237b3c 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -229,11 +229,6 @@ ImGui_TimelineIncrementDraw(project_data *File, ui *UI, ImDrawList *draw_list, Assert(TimelineZoomSize > 0.0f); - DebugWatchVar("ZoomSize: ", &TimelineZoomSize, d_float); - DebugWatchVar("MoveSize: ", &TimelineMoveSize, d_float); - DebugWatchVar("Percent Offset: ", &UI->TimelinePercentOffset, d_float); - DebugWatchVar("Percent Zoom: ", &UI->TimelinePercentZoomed, d_float); - real32 x = 0; bool32 RightmostEdge = false; real32 Increment = (real32)1 / File->NumberOfFrames; @@ -282,32 +277,62 @@ ImGui_TimelineIncrementDraw(project_data *File, ui *UI, ImDrawList *draw_list, } static void -ImGui_TimelineIncrementDraw2(project_data *File, ui *UI, ImDrawList *draw_list, real32 MaxVal_Y, real32 MinVal_Y, +ImGui_TimelineIncrementDraw2(project_data *File, ImDrawList *draw_list, real32 MaxVal_Y, real32 MinVal_Y, + real32 Y_TimelinePercentZoomed, real32 Y_TimelinePercentOffset, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, bool32 IsText) { uint32 LineColor = IM_COL32(200, 200, 200, 40); - real32 TimelineZoomSize = TimelineSizeWithBorder.y / UI->Y_TimelinePercentZoomed; - real32 TimelineMoveSize = TimelineSizeWithBorder.y * UI->Y_TimelinePercentOffset / UI->Y_TimelinePercentZoomed; + real32 TimelineZoomSize = TimelineSizeWithBorder.y / Y_TimelinePercentZoomed; + real32 TimelineMoveSize = TimelineSizeWithBorder.y * Y_TimelinePercentOffset / Y_TimelinePercentZoomed; Assert(TimelineZoomSize > 0.0f); - DebugWatchVar("Y_ZoomSize: ", &TimelineZoomSize, d_float); - DebugWatchVar("Y_MoveSize: ", &TimelineMoveSize, d_float); - DebugWatchVar("Y_Percent Offset: ", &UI->Y_TimelinePercentOffset, d_float); - DebugWatchVar("Y_Percent Zoom: ", &UI->Y_TimelinePercentZoomed, d_float); - - real32 x = 0; + real32 Fraction = (MinVal_Y > 0) ? MinVal_Y - (int32)MinVal_Y : (int32)MinVal_Y - MinVal_Y; + real32 x = (int32)MinVal_Y; bool32 RightmostEdge = false; - real32 Increment = 1 / MaxVal_Y; + while (!RightmostEdge) { + real32 Ratio_Y = (x - MinVal_Y) / (MaxVal_Y - MinVal_Y); + ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineMoveSize + (1.0f - Ratio_Y)*TimelineZoomSize); + ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2); + if (Min.y > TimelineAbsolutePos.y) { + draw_list->AddLine(Min, Max, LineColor); + char buf2[6]; + sprintf(buf2, "%.2f", x); + draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2); + x += 1.0f; + } else { + RightmostEdge = true; + } + } + + x = (int32)MinVal_Y; + x -= 1.0f; + bool32 LeftmostEdge = false; + + while (!LeftmostEdge) { + real32 Ratio_Y = (x - MinVal_Y) / (MaxVal_Y - MinVal_Y); + ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineMoveSize + (1.0f - Ratio_Y)*TimelineZoomSize); + ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2); + if (Min.y < TimelineAbsolutePos.y + TimelineSizeWithBorder.y) { + draw_list->AddLine(Min, Max, LineColor); + char buf2[6]; + sprintf(buf2, "%.2f", x); + draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2); + x -= 1.0f; + } else { + LeftmostEdge = true; + } + } +#if 0 while (!RightmostEdge) { ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineZoomSize + TimelineMoveSize - x*TimelineZoomSize); ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2); if (Min.y > TimelineAbsolutePos.y) { draw_list->AddLine(Min, Max, LineColor); char buf2[6]; - sprintf(buf2, "%.2f", x / Increment); + sprintf(buf2, "%.2f", (x / Increment) + MinVal_Y); draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2); x += Increment; } else { @@ -315,18 +340,17 @@ ImGui_TimelineIncrementDraw2(project_data *File, ui *UI, ImDrawList *draw_list, } } -#if 0 - x = -0.25; + x = -Increment; bool32 LeftmostEdge = false; while (!LeftmostEdge) { - ImVec2 Min = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + x*TimelineZoomSize, TimelineStartingPos.y); - ImVec2 Max = ImVec2(Min.x + 2, WindowMaxAbs.y); - if (Min.x > TimelineAbsolutePos.x) { + ImVec2 Min = ImVec2(TimelineAbsolutePos.x, TimelineAbsolutePos.y + TimelineZoomSize + TimelineMoveSize - x*TimelineZoomSize); + ImVec2 Max = ImVec2(TimelineAbsolutePos.x + TimelineSizeWithBorder.x, Min.y + 2); + if (Min.y < TimelineAbsolutePos.y + TimelineSizeWithBorder.y) { draw_list->AddLine(Min, Max, LineColor); char buf2[6]; - sprintf(buf2, "%.2f", x); - draw_list->AddText(ImVec2(Min.x, TimelineAbsolutePos.y), IM_COL32(200, 200, 200, 130), buf2); - x -= 0.25; + sprintf(buf2, "%.2f", (x / Increment) + MinVal_Y); + draw_list->AddText(ImVec2(TimelineAbsolutePos.x, Min.y), IM_COL32(200, 200, 200, 130), buf2); + x -= Increment; } else { LeftmostEdge = true; } @@ -1226,7 +1250,8 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, project_layer *Layer = File->Layer[0]; property_channel *Property = &Layer->x; - real32 MaxVal_Y = 0; + + real32 MaxVal_Y = -10000; real32 MinVal_Y = 10000; for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) { keyframe *Keyframe = KeyframeLookup(Property, b); @@ -1234,42 +1259,81 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, MinVal_Y = (Keyframe->Value.f < MinVal_Y) ? Keyframe->Value.f : MinVal_Y; } + UI->Y_MaxVal = MaxVal_Y; + UI->Y_MinVal = MinVal_Y; + + if (!UI->IsDragging) { + UI->Display_Y_MinVal = UI->Y_MinVal; + UI->Display_Y_MaxVal = UI->Y_MaxVal; + } + + real32 Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed; + real32 Y_TimelinePercentOffset = UI->Y_TimelinePercentOffset; + MaxVal_Y = UI->Display_Y_MaxVal; + MinVal_Y = UI->Display_Y_MinVal; + + DebugWatchVar("offset: ", &Y_TimelinePercentOffset, d_float); + DebugWatchVar("zoom: ", &Y_TimelinePercentZoomed, d_float); + for (int b = 0; b < Property->NumberOfTotalKeyframes; b++) { ImGui::PushID(b); real32 TimelineZoomSize = TimelineSizeWithBorder.x / UI->TimelinePercentZoomed; real32 TimelineMoveSize = TimelineSizeWithBorder.x * UI->TimelinePercentOffset / UI->TimelinePercentZoomed; - real32 Y_TimelineZoomSize = TimelineSizeWithBorder.y / UI->Y_TimelinePercentZoomed; - real32 Y_TimelineMoveSize = TimelineSizeWithBorder.y * UI->Y_TimelinePercentOffset / UI->Y_TimelinePercentZoomed; + real32 Y_TimelineZoomSize = TimelineSizeWithBorder.y / Y_TimelinePercentZoomed; + real32 Y_TimelineMoveSize = TimelineSizeWithBorder.y * Y_TimelinePercentOffset / Y_TimelinePercentZoomed; keyframe *Keyframe = KeyframeLookup(Property, b); // Only used for drawing the bezier. keyframe *NextKeyframe = (b != Property->NumberOfTotalKeyframes - 1) ? KeyframeLookup(Property, b) : NULL; real32 Ratio_X = (real32)(Layer->BitmapInfo.FrameOffset + Keyframe->FrameNumber) / File->NumberOfFrames; - real32 Ratio_Y = 1.0f - ((Keyframe->Value.f - MinVal_Y) / MaxVal_Y); + real32 Ratio_Y = (Keyframe->Value.f - MinVal_Y) / (MaxVal_Y - MinVal_Y); ImVec2 KeyframePos = ImVec2(TimelineAbsolutePos.x + TimelineMoveSize + Ratio_X*TimelineZoomSize, - TimelineAbsolutePos.y + Y_TimelineMoveSize + Ratio_Y*Y_TimelineZoomSize); + TimelineAbsolutePos.y + Y_TimelineMoveSize + (1.0f - Ratio_Y)*Y_TimelineZoomSize); ImGui::SetCursorScreenPos(KeyframePos); ImGui::Button("##keyframe", ImVec2(FontHeight, FontHeight)); + if (ImGui::IsItemActivated()) { + UI->IsDragging = true; + UI->TempVal = Keyframe->Value.f; + } + if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))) - // if ((ImGui::IsItemHovered() && ImGui::IsKeyPressed(ImGuiKey_A))) { - real32 MouseDeltaRatio = -io.MouseDelta.y / TimelineSizeWithBorder.y; - // real32 MouseDeltaRatio = 0.2; - Keyframe->Value.f += MouseDeltaRatio*MaxVal_Y*UI->TimelinePercentZoomed; - if ((Ratio_Y == 0) || Keyframe->Value.f > MaxVal_Y) { - UI->Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed/(1+MouseDeltaRatio); - real32 Part1 = (1.0f - UI->Y_TimelinePercentOffset*MouseDeltaRatio)/(1+MouseDeltaRatio); - UI->Y_TimelinePercentOffset -= 1.0f - Part1; + real32 MouseDeltaRatio = -io.MouseDelta.y / TimelineSizeWithBorder.y * Y_TimelinePercentZoomed; + if (io.KeyShift) + Ratio_Y = (real32)((int32)(Ratio_Y * 1000) / 10) / 100; + real32 Test = ((MaxVal_Y - MinVal_Y) * (Ratio_Y + MouseDeltaRatio)) + MinVal_Y; + DebugWatchVar("RatioY", &Ratio_Y, d_float); + DebugWatchVar("NewRatioY", &UI->Y_MaxVal, d_float); + Keyframe->Value.f = Test; + } + + // TODO(fox): This is kind of a mess. I built the graph around the + // ratios of the keyframes/timeline to make the bars straightforward, + // meaning the position/offset have to be transformed into a new space + // when a new min/max value is reached. + + if (ImGui::IsItemDeactivated()) { + if ((UI->TempVal >= MaxVal_Y) || Keyframe->Value.f == UI->Y_MaxVal) { + real32 Min = ((Ratio_Y <= 0.0f) && (UI->TempVal >= MaxVal_Y)) ? MinVal_Y : UI->Y_MinVal; + real32 RealRatio_Y = (UI->Y_MaxVal - UI->Y_MinVal) / (MaxVal_Y - MinVal_Y); + UI->Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed / RealRatio_Y; + UI->Y_TimelinePercentOffset = (1.0f/RealRatio_Y + UI->Y_TimelinePercentOffset/RealRatio_Y - 1.0f); + } else if (UI->TempVal <= MinVal_Y || Keyframe->Value.f == UI->Y_MinVal) { + real32 RealRatio_Y = (UI->Y_MinVal - MinVal_Y) / (MaxVal_Y - MinVal_Y); + UI->Y_TimelinePercentOffset = UI->Y_TimelinePercentOffset / (1 - RealRatio_Y); + UI->Y_TimelinePercentZoomed = UI->Y_TimelinePercentZoomed / (1 - RealRatio_Y); } + UI->IsDragging = false; } + ImGui::PopID(); } ImGui_TimelineIncrementDraw(File, UI, draw_list, TimelineSizeWithBorder, TimelineAbsolutePos, 0); - ImGui_TimelineIncrementDraw2(File, UI, draw_list, MaxVal_Y, MinVal_Y, TimelineSizeWithBorder, TimelineAbsolutePos, 0); + ImGui_TimelineIncrementDraw2(File, draw_list, MaxVal_Y, MinVal_Y, Y_TimelinePercentZoomed, Y_TimelinePercentOffset, TimelineSizeWithBorder, TimelineAbsolutePos, 0); #if DEBUG draw_list->AddCircle(TimelineAbsolutePos + ImVec2(TimelineSizeWithBorder.x * 0.25, TimelineSizeWithBorder.y - 50), @@ -1284,6 +1348,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, real32 BarHandleSize = FontHeight; real32 BarThickness = 50; + real32 BarMinZoom = 0.01; real32 BarH_Pos = -TimelineSizeWithBorder.x * UI->TimelinePercentOffset; real32 BarH_Size = TimelineSizeWithBorder.x / (1 / UI->TimelinePercentZoomed); @@ -1291,8 +1356,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, // I use "UI" to denote the size/position after clipping the bar so that it // doesn't go out of bounds and the handles are always selectable at the edges. - real32 BarH_Offset = (BarH_Pos > 0) ? BarH_Pos : 0; - ImVec2 BarH_PosUI = TimelineAbsolutePos + ImVec2(BarH_Offset, TimelineSize.y - BarThickness); + real32 BarH_Offset = Max(BarH_Pos, 0); real32 BarH_SizeUI = (BarH_Size + BarH_Pos > TimelineSizeWithBorder.x) ? TimelineSizeWithBorder.x - BarH_Pos : @@ -1303,13 +1367,20 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, BarH_SizeUI = BarH_SizeUI - BarHandleSize*2; + BarH_SizeUI = Max(BarH_SizeUI, FontHeight*4); + + BarH_Offset = Min(BarH_Offset, TimelineSize.x - BarH_SizeUI - BarHandleSize*4); + ImVec2 BarH_PosUI = TimelineAbsolutePos + ImVec2(BarH_Offset, TimelineSize.y - BarThickness); + ImGui::SetCursorScreenPos(BarH_PosUI); ImGui::Button("##scrollbarleft", ImVec2(BarHandleSize, BarThickness)); if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))) { - UI->TimelinePercentZoomed -= MouseDelta.x; - UI->TimelinePercentOffset -= MouseDelta.x; + if ((UI->TimelinePercentZoomed - MouseDelta.x) > BarMinZoom) { + UI->TimelinePercentZoomed -= MouseDelta.x; + UI->TimelinePercentOffset -= MouseDelta.x; + } } ImGui::SetCursorScreenPos(BarH_PosUI + ImVec2(BarHandleSize, 0)); @@ -1325,15 +1396,19 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, if ((ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1))) { - UI->TimelinePercentZoomed += MouseDelta.x; + if ((UI->TimelinePercentZoomed + MouseDelta.x) > BarMinZoom) { + UI->TimelinePercentZoomed += MouseDelta.x; + } } + Assert(UI->TimelinePercentZoomed > BarMinZoom); + real32 BarV_MaxSize = TimelineSizeWithBorder.y - BarThickness/2; - real32 BarV_Pos = -BarV_MaxSize * UI->Y_TimelinePercentOffset; - real32 BarV_Size = BarV_MaxSize / (1 / UI->Y_TimelinePercentZoomed); + real32 BarV_Pos = -BarV_MaxSize * Y_TimelinePercentOffset; + real32 BarV_Size = BarV_MaxSize / (1 / Y_TimelinePercentZoomed); + BarV_Size = Max(BarV_Size, FontHeight*4); - real32 BarV_Offset = (BarV_Pos > 0) ? BarV_Pos : 0; - ImVec2 BarV_PosUI = TimelineAbsolutePos + ImVec2(TimelineSize.x - BarThickness, BarV_Offset); + real32 BarV_Offset = Max(BarV_Pos, 0); real32 BarV_SizeUI = (BarV_Size + BarV_Pos > BarV_MaxSize) ? BarV_MaxSize - BarV_Pos : @@ -1344,6 +1419,11 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, BarV_SizeUI = BarV_SizeUI - BarHandleSize*2; + BarV_SizeUI = Max(BarV_SizeUI, FontHeight*4); + + BarV_Offset = Min(BarV_Offset, BarV_MaxSize - BarV_SizeUI - BarHandleSize*4); + ImVec2 BarV_PosUI = TimelineAbsolutePos + ImVec2(TimelineSize.x - BarThickness, BarV_Offset); + ImGui::SetCursorScreenPos(BarV_PosUI); ImGui::Button("##h-scrollbarleft", ImVec2(BarThickness, BarHandleSize)); @@ -1369,6 +1449,7 @@ ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, UI->Y_TimelinePercentZoomed += MouseDelta.y; } + UI->Y_TimelinePercentZoomed = Max(UI->Y_TimelinePercentZoomed, 0.01); draw_list->PopClipRect(); ImGui::PopClipRect(); @@ -1464,9 +1545,19 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB { if (io.KeysData[ImGuiKey_Q].Down) { State->IsRunning = false; + } #if DEBUG // ImGui::SaveIniSettingsToDisk("asda"); #endif + if (ImGui::IsKeyPressed(ImGuiKey_R)) { + UI->Y_TimelinePercentZoomed = UI->Default_Y_TimelinePercentZoomed; + UI->Y_TimelinePercentOffset = UI->Default_Y_TimelinePercentOffset; + keyframe *Keyframe = KeyframeLookup(&File->Layer[0]->x, 0); + Keyframe->Value.f = -10; + Keyframe = KeyframeLookup(&File->Layer[0]->x, 1); + Keyframe->Value.f = 0; + Keyframe = KeyframeLookup(&File->Layer[0]->x, 2); + Keyframe->Value.f = 10; } if (ImGui::IsKeyPressed(ImGuiKey_D)) { @@ -1514,8 +1605,8 @@ ImGui_ProcessInputs(project_data *File, project_state *State, comp_buffer *CompB State->UpdateKeyframes = true; } - if (ImGui::IsKeyPressed(ImGuiKey_R) && State->NumberOfSelectedLayers) - TransformsInteract(File, State, Memory, UI, sliding_rotation); + // if (ImGui::IsKeyPressed(ImGuiKey_R) && State->NumberOfSelectedLayers) + // TransformsInteract(File, State, Memory, UI, sliding_rotation); if (ImGui::IsKeyPressed(ImGuiKey_S) && State->NumberOfSelectedLayers) TransformsInteract(File, State, Memory, UI, sliding_scale); if (ImGui::IsKeyPressed(ImGuiKey_G) && State->NumberOfSelectedLayers) -- cgit v1.2.3