From ee654e9217487f6fca12356ec8af82319c309592 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Tue, 7 Feb 2023 00:21:06 -0500 Subject: good changes --- .gitignore | 4 +- src/createcalls.cpp | 90 ++++++++++--------- src/imgui_ui.cpp | 6 +- src/imgui_ui_properties.cpp | 3 + src/imgui_ui_timeline.cpp | 30 +++++-- src/imgui_ui_viewport.cpp | 24 +++++- src/include/all.h | 16 ++-- src/include/functions.h | 128 --------------------------- src/include/layer.h | 3 - src/include/main.h | 4 + src/layer.cpp | 52 +++++++---- src/main.cpp | 204 ++++++++++++++++++++++++++++++++++++++++---- src/prenderer.cpp | 82 +++++------------- src/sorted.cpp | 127 +++++++++++++++++++-------- src/strings.cpp | 5 +- src/undo.cpp | 1 + 16 files changed, 447 insertions(+), 332 deletions(-) delete mode 100644 src/include/functions.h diff --git a/.gitignore b/.gitignore index 7513e10..4047fb0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ compile_commands.json build_ops imgui.ini test -test2 -test3 -test4 +test* tags .cache diff --git a/src/createcalls.cpp b/src/createcalls.cpp index e41a9d2..4761a94 100644 --- a/src/createcalls.cpp +++ b/src/createcalls.cpp @@ -683,15 +683,38 @@ Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *Arr return 0; } +// TODO(fox): Add different modes (all dupes on top, each dupe above its layer, two for bottom) +void +SortUnionTest(memory *Memory, sorted_layer_array *SortedLayerStart, block_layer *StartLayer, + int i, int FauxIncrement, int LayerCount, int Mode) +{ + block_layer *PrevLayer = StartLayer; + for (int a = i+1; a < LayerCount; a++) { + sorted_layer_array *NextSortEntry = &SortedLayerStart[a]; + uint32 NextIndex_Physical = NextSortEntry->Block_Layer_Index; + block_layer *NextLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, NextIndex_Physical); + if (NextLayer->Vertical_Offset == PrevLayer->Vertical_Offset) { + if (Mode == 0) { + History_Action_Swap(Memory, F_Layers, sizeof(NextLayer->Vertical_Offset), &NextLayer->Vertical_Offset); + NextLayer->Vertical_Offset -= 1; + } else { + NextSortEntry->SortedOffset -= 1; + } + } else { + break; + } + PrevLayer = NextLayer; + } +} + static void Project_Layer_Duplicate(project_data *File, project_state *State, memory *Memory, - sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, v2 Offset, bool32 FakeOnly) + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, v2 Offset, bool32 FakeOnly, bool32 NewPrecomp) { for (int c = 0; c < File->Comp_Count; c++) { sorted_comp_array SortedCompStart = SortedCompArray[c]; sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, c); int LayerCount = SortedCompStart.LayerCount + SortedCompStart.FakeLayerCount; - int Increment = 0; for (int i = 0; i < LayerCount; i++) { sorted_layer_array SortEntry = SortedLayerStart[i]; @@ -706,23 +729,16 @@ Project_Layer_Duplicate(project_data *File, project_state *State, memory *Memory History_Action_Block_Swap(Memory, F_Layers, NewLayer); *NewLayer = *Layer; + if (NewPrecomp && Layer->IsPrecomp) { + NewLayer->Block_Source_Index = Layer_Precomp_CopyContents(); + } + Assert(Layer->Block_Effect_Count == 0); Layer_Select(Memory, State, Memory_Block_LazyIndexAtAddress(Memory, F_Layers, NewLayer)); NewLayer->Vertical_Offset--; - for (int a = i+1; a < LayerCount; a++) { - sorted_layer_array PrevSortEntry = SortedLayerStart[a-1]; - uint32 PrevIndex_Physical = PrevSortEntry.Block_Layer_Index; - block_layer *PrevLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, PrevIndex_Physical); - sorted_layer_array NextSortEntry = SortedLayerStart[a]; - uint32 NextIndex_Physical = NextSortEntry.Block_Layer_Index; - block_layer *NextLayer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, NextIndex_Physical); - if (NextLayer->Vertical_Offset == PrevLayer->Vertical_Offset) - NextLayer->Vertical_Offset -= 1; - else - break; - } + SortUnionTest(Memory, SortedLayerStart, NewLayer, i, 0, LayerCount, 0); Assert(!NewLayer->x.Keyframe_Count); Assert(!NewLayer->y.Keyframe_Count); @@ -738,15 +754,18 @@ Project_Layer_Duplicate(project_data *File, project_state *State, memory *Memory History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count); File->Layer_Count++; - Increment++; } else { - // History_Action_Swap(Memory, F_Layers, sizeof(Layer->Vertical_Offset), &Layer->Vertical_Offset); Layer->IsSelected = false; } } } } +// TODO(fox): We may need a way to recalculate width/height when points are +// moved since selection depends on it. +// TODO(fox): We could also write better selection code for shapes that +// actually tests using the bezier path (preferrable). + static void Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory) { @@ -767,6 +786,14 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory) shape_layer *Shape = &File->UI.Shape; + Layer->Block_Composition_Index = File->PrincipalCompIndex; + if (State->MostRecentlySelectedLayer == -1) { + Layer->Block_Composition_Index = File->PrincipalCompIndex; + } else { + // LayerIterate_DeepestPrecomp(State, Memory, CompIndex, ExtraT, Center, + // SortedCompArray, SortedLayerArray, SelectionCount, SelectedLayerIndex, SelectedPrecompIndex) + } + // Rect mode if (State->Interact_Modifier == 1) { v2 *CompPoint = (v2 *)&State->Interact_Offset[0]; for (int i = 0; i < 4; i++) { @@ -896,37 +923,6 @@ void Source_UICreateButton(project_data *File, project_state *State, memory *Mem Source_DeselectAll(File, Memory); } -void Precomp_UIDuplicate(project_data *File, project_state *State, memory *Memory, uint16 CompIndex, - sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart) -{ - block_layer *Layer = NULL; - for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) - { - sorted_layer_array SortEntry = SortedLayerStart[i]; - uint32 Index_Physical = SortEntry.Block_Layer_Index; - Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); - if (Layer->IsSelected) { - break; - } - } - if (Layer) { - block_layer *DupeLayer = Layer_Init(File, Memory); - *DupeLayer = *Layer; - DupeLayer->Vertical_Offset += 1; - for (int h = 0; h < AmountOf(Layer->Property); h++) { - property_channel *Property = &Layer->Property[h]; - if (Property->Block_Bezier_Count) { - property_channel *DupeProperty = &DupeLayer->Property[h]; - DupeProperty->Block_Bezier_Index[0] = Memory_Block_AllocateNew(Memory, F_Bezier); - block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Property->Block_Bezier_Index[0]); - block_bezier *DupeBezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, DupeProperty->Block_Bezier_Index[0], 0); - Bezier->Occupied = true; - *DupeBezier = *Bezier; - } - } - } -} - void Precomp_UIDelete(project_data *File, project_state *State, memory *Memory, uint16 CompIndex, sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart) { diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp index c24571c..a07854e 100644 --- a/src/imgui_ui.cpp +++ b/src/imgui_ui.cpp @@ -444,11 +444,7 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me } if (ImGui::IsKeyPressed(ImGuiKey_D)) { if (io.KeyShift && State->Interact_Active == interact_type_none) { - History_Entry_Commit(Memory, "Duplicate layers"); - v2 Offset = V2(State->Interact_Dup_Previous[0], State->Interact_Dup_Previous[1]); - Project_Layer_Duplicate(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Offset, 0); - State->Interact_Transform = {}; - History_Entry_End(Memory); + State->HotkeyInput = hotkey_duplicatelayer; } else { State->Tool = tool_pen; } diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp index 43c4a79..345f612 100644 --- a/src/imgui_ui_properties.cpp +++ b/src/imgui_ui_properties.cpp @@ -21,6 +21,7 @@ ImGui_Properties_Slider(project_state *State, memory *Memory, property_channel * { if (ImGui::IsItemActive()) { State->UpdateFrame = true; + State->Interact_Transform = {}; // ImGui_WarpMouse(State, io.MousePos, WindowMinAbs, WindowMaxAbs, 1); } @@ -433,10 +434,12 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index); ImGui::DragScalar("Width", ImGuiDataType_U16, &Comp->Width); if (ImGui::IsItemActive()) { + State->Interact_Transform = {}; State->UpdateFrame = true; } ImGui::DragScalar("Height", ImGuiDataType_U16, &Comp->Height); if (ImGui::IsItemActive()) { + State->Interact_Transform = {}; State->UpdateFrame = true; } } diff --git a/src/imgui_ui_timeline.cpp b/src/imgui_ui_timeline.cpp index dcb3bc2..f8c5258 100644 --- a/src/imgui_ui_timeline.cpp +++ b/src/imgui_ui_timeline.cpp @@ -468,9 +468,15 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index); char buf[128]; #if DEBUG - sprintf(buf, "%s, (idx: %i so: %.1f di: %.1f", String->Char, Index_Physical, SortEntry.SortedOffset, SortEntry. DisplayOffset); + if (SortEntry.IsFake) + sprintf(buf, "%s (duplicate), (idx: %i so: %.1f di: %.1f", String->Char, Index_Physical, SortEntry.SortedOffset, SortEntry. DisplayOffset); + else + sprintf(buf, "%s, (idx: %i so: %.1f di: %.1f", String->Char, Index_Physical, SortEntry.SortedOffset, SortEntry. DisplayOffset); #else - sprintf(buf, "%s", String->Char); + if (SortEntry.IsFake) + sprintf(buf, "%s (duplicate)", String->Char); + else + sprintf(buf, "%s", String->Char); #endif if (UI->TimelinePercentZoomed.y <= 1.0f) { real32 TextX = (Layer_ScreenPos_Min.x > TimelineAbsolutePos.x) ? Layer_ScreenPos_Min.x : TimelineAbsolutePos.x; @@ -522,7 +528,11 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImGui::Button("##layer_resize", ResizeSize); if (ImGui::IsItemHovered()) { - ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + if (Layer->IsLocked) { + ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); + } else { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } } if (ImGui::IsItemActivated()) { if (!Layer->IsSelected && !Layer->IsLocked) { @@ -568,6 +578,12 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem ImGui::SetCursorScreenPos(Layer_ScreenPos_Min); ImGui::InvisibleButton("##layer_mid", Layer_ScreenSize, ImGuiMouseButton_Left); + if (ImGui::IsItemHovered()) { + if (Layer->IsLocked) { + ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); + } + } + if (ImGui::IsItemActivated()) { if (!Layer->IsSelected && !Layer->IsLocked) { if (!io.KeyShift) Layer_DeselectAll(File, State, Memory); @@ -602,7 +618,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem int h = 0, z = 0, i = 0; while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &z, &i)) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); - if (Layer->IsSelected) { + if (Layer->IsSelected == 1 || Layer->IsLocked) { if (!Commit) { History_Entry_Commit(Memory, "Toggle lock"); Commit = true; @@ -621,10 +637,10 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem State->UpdateKeyframes = true; } if (ImGui::MenuItem("Duplicate layer")) { - Precomp_UIDuplicate(File, State, Memory, CompIndex, SortedCompStart, SortedLayerStart); + State->HotkeyInput = hotkey_duplicatelayer; } if (ImGui::MenuItem("Delete layer")) { - Precomp_UICreateButton(File, State, Memory, CompIndex, SortedCompStart, SortedLayerStart); + State->HotkeyInput = hotkey_deletelayer; State->UpdateKeyframes = true; } if (ImGui::BeginMenu("Layer color")) @@ -639,7 +655,7 @@ ImGui_Timeline_DrawPrecomp(project_data *File, project_state *State, memory *Mem int h = 0, z = 0, i = 0; while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &z, &i)) { block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); - if (Layer->IsSelected) { + if (Layer->IsSelected == 1) { Layer->ColIndex = c; } } diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index 946edec..2489cd5 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -279,11 +279,11 @@ T_FindBestFit(int PointCount, v2 *PointData, v2 *Center, v2 *NewCenter, v2 *Best int a = 0; return 0; } + static void LayerIterate(project_state *State, memory *Memory, uint32 CompIndex, layer_transforms ExtraT, v2 Center, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray); - static void ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO &io, ImDrawList *draw_list, int *PointCount, v2 *PointData, ImVec2 ViewportMin, uint32 CompWidth, uint32 CompHeight, @@ -653,12 +653,20 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me } layer_transforms T = {}; + T.scale = 1.0f; LayerIterate(State, Memory, File->PrincipalCompIndex, T, Center, SortedCompArray, SortedLayerArray); History_Entry_End(Memory); State->UpdateFrame = true; State->UncommitedKeyframe = 1; } else { - int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); + // int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); + layer_transforms T = {}; + T.scale = 1.0f; + + v2 CompPoint = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos) * V2(CompWidth, CompHeight); + int32 Selection = LayerIterate_TestSelection(State, Memory, File->PrincipalCompIndex, T, CompPoint, + SortedCompArray, SortedLayerArray, io.KeyShift); + Assert(State->Tool == tool_default); if (!io.KeyShift) { Layer_DeselectAll(File, State, Memory); @@ -1258,7 +1266,11 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, BoxMax.y = (MousePos.y > ClickedPos.y) ? MousePos.y : ClickedPos.y; if (io.MouseDelta.x || io.MouseDelta.y) { if (State->Tool == tool_default && State->Interact_Active == interact_type_none) { - int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); + layer_transforms T = {}; + T.scale = 1.0f; + v2 CompPoint = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos) * V2(MainComp->Width, MainComp->Height); + int32 Selection = LayerIterate_TestSelection(State, Memory, File->PrincipalCompIndex, T, CompPoint, + SortedCompArray, SortedLayerArray, io.KeyShift); if (!State->InteractTransformMode && Selection != -1) { if (!io.KeyShift) Layer_DeselectAll(File, State, Memory); @@ -1296,7 +1308,11 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, State->Interact_OutOfDrag = 0; } else { // Layer selection - int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); + layer_transforms T = {}; + T.scale = 1.0f; + v2 CompPoint = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos) * V2(MainComp->Width, MainComp->Height); + int32 Selection = LayerIterate_TestSelection(State, Memory, File->PrincipalCompIndex, T, CompPoint, + SortedCompArray, SortedLayerArray, io.KeyShift); if (State->Tool == tool_default && State->Interact_Active == interact_type_none) { if (!io.KeyShift && State->Interact_Active == interact_type_none) { Layer_DeselectAll(File, State, Memory); diff --git a/src/include/all.h b/src/include/all.h index 7d7557a..82731ff 100644 --- a/src/include/all.h +++ b/src/include/all.h @@ -1,3 +1,9 @@ + +static int32 +LayerIterate_TestSelection(project_state *State, memory *Memory, uint32 PrincipalIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, bool32 BelowOnly); + + // TODO(fox);: Incorporate sorting for non-continuous shapes. static uint32 Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, @@ -353,13 +359,13 @@ Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height) static v2 Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 LayerIndex); -// TODO(fox);: Precomps? -static int32 -Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex, bool32 BelowOnly); - static bool32 Shape_TestBoxSelect(v2 Min, v2 Max, bezier_point *BezierPointData, uint32 BezierCount); +static int32 +LayerIterate_TestSelection(project_state *State, memory *Memory, uint32 PrincipalIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, bool32 BelowOnly); + static bool32 Transform_TestBox(block_layer *Layer, uint32 Width, uint32 Height, v2 Min, v2 Max); @@ -601,7 +607,7 @@ static void CopyStrings(void *Dest, void *Data); static uint16 -String_AddToFile(memory *Memory, char *Char); +String_AddToFile(memory *Memory, char *Char, bool32 NoUndo = 1); static bool32 String_Compare(char *String1, char *String2, uint32 Length); diff --git a/src/include/functions.h b/src/include/functions.h deleted file mode 100644 index 3826824..0000000 --- a/src/include/functions.h +++ /dev/null @@ -1,128 +0,0 @@ - -// Memory - -static void Memory_Copy(uint8 *Address_Write, uint8 *Address_Read, uint64 Size); -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); - -void AV_Init(block_source *Source, av_info *AV, memory *Memory); - -// Rudimentary guess-until-correct solver for bezier curves, used to evaluate -// the keyframe graph. Similar to the Catmull-Rom solver in CurvesSolver(). - -static real32 Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 TargetX); -static bezier_point * Bezier_LookupAddress(memory *Memory, property_channel *Property, uint16 Index, bool32 AssertExists = 1); -static bezier_point * Bezier_LookupAddress(memory *Memory, uint16 *Block_Bezier_Index, uint16 Index, bool32 AssertExists); -static void Bezier_Interact_Evaluate(project_state *State, bezier_point *PointAddress, v2 *Pos, real32 GraphZoomHeight = 1, real32 Y_Increment = 1); -// NOTE(fox): GraphZoomHeight and Y_Increment don't have to be specified if the Y value isn't needed, i.e. in Property_SortAll(). -static void Bezier_Add(memory *Memory, memory_table_list TableName, property_channel *Property, bezier_point PointData, uint16 *ArrayLocation); -static void Bezier_Add(memory *Memory, memory_table_list TableName, uint16 *Block_Bezier_Index, uint16 *Block_Bezier_Count, uint16 *PointCount, bezier_point PointData); - -static void -Render_UI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, - sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, - sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current); - -static void * -Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists = 1); - -static bool32 -Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index); - -static void -File_SaveAs(project_data *File, project_state *State, memory *Memory, char *Filename); - -static uint32 -Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, - project_state *State, layer_transforms T, int Width, int Height, - int CompWidth, int CompHeight, bool32 Interact); - -void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size); - -static layer_transforms Transform_Inverse(layer_transforms T); - -static v2 T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y); - -static layer_transforms -Transform_TestInteracts(project_state *State, block_layer *Layer, sorted_layer_array SortEntry, layer_transforms T); - -static layer_transforms -Transform_Add(layer_transforms T, layer_transforms ExtraT, real32 Width, real32 Height); - -inline void -ImGui_DrawCenteredRect(ImDrawList *draw_list, ImVec2 Point, real32 Width, uint32 col) - -static void ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_file Sorted); -static void ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray); -static void -ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID, - sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray); -static void ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray); - -static void ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray); -static void ImGui_EffectsPanel(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io); -static void ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io); - -static void ImGui_Menu(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io); -static void ImGui_Popups(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io); -static void ImGui_KeybindUI(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io); - -#if DEBUG -static void ImGui_DebugMemoryViewer(memory *Memory, project_state *State); -static void ImGui_DebugRenderQueue(project_state *State); -static void ImGui_DebugUndoTree(memory *Memory, project_state *State); -#endif -#if SD -static void ImGui_SD_Thumbnail(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 *SourceArray, uint16 SourceCount); -static void ImGui_SD_Prompt(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray); -#endif - -// Widgets not involving drawing UI. - -static v2 ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 MousePos); -static void ImGui_WarpMouse(project_state *State, ImVec2 MousePos, ImVec2 Min, ImVec2 Max, int Direction = 3); -static void ImGui_WarpMouseFinish(project_state *State, ImVec2 MousePos); -static ImVec2 ImGui_Brush_CalcMousePos(project_state *State, ImGuiIO &io, ImVec2 MouseDelta, int32 i, real32 DeltaDistance, real32 DeltaSlope); -static bool32 ImGui_TestBoxSelection_Point(ImVec2 Pos, ImGuiIO &io, bool32 *Test); - - -static void -Render_Main(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, - void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion); - -static void Effect_Curves_Init(block_effect *Effect, property_channel *Property); - -void AV_IsFileSupported(char *filename, bool32 *IsVideo, bool32 *HasAudio); - -static v2 T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV); -static header_effect* Effect_EntryFromID(project_state *State, char *ID); - -void Effect_Curves_Sort(memory *Memory, block_effect *Effect, uint16 *SortedPointStart, uint16 Which); -inline v2 Effect_V2(memory *Memory, block_effect *Effect, int Offset); - -static void Interact_Transform_Begin(project_data *File, memory *Memory, project_state *State, ImVec2 OGPos, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray); - -static v2 Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 ViewportMin, ImVec2 Point); -static ImVec2 Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point); - -static v2 TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point); - -static void Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height); - -static void * Memory_PushScratch(memory *Memory, uint64 Size); - -static void Memory_PopScratch(memory *Memory, uint64 Size); - -void Bitmap_SwapData(uint8 *Address_0, uint8 *Address_1, uint64 Size, uint16 BytesPerPixel); -void GL_DeleteHWBuffer(gl_effect_layer *Test); - -void GL_UpdateTexture(gl_effect_layer *Test, void *Data, uint16 Width, uint16 Height, uint16 BytesPerPixel, bool32 Multisample); - -static void Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale); - -static layer_transforms Layer_GetTransforms(block_layer *Layer); -void GL_GenAndBindTexture(GLuint *GLTexture, int Width, int Height, int BytesPerPixel, void *BufferAddress); - -static real32 Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 X); - diff --git a/src/include/layer.h b/src/include/layer.h index d059bb6..d354c89 100644 --- a/src/include/layer.h +++ b/src/include/layer.h @@ -42,9 +42,6 @@ Layer_Select_Traverse(uint16 PrincipalCompIndex, memory *Memory, project_state * static v2 Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 LayerIndex); -static int32 -Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex, bool32 BelowOnly); - static void Layer_RecursiveDeselect(memory *Memory, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex); diff --git a/src/include/main.h b/src/include/main.h index 1f04d41..0ee8511 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -367,6 +367,7 @@ enum hotkey_input hotkey_newlayer_paint, hotkey_newlayer_shape, hotkey_deletelayer, + hotkey_duplicatelayer, hotkey_undo, hotkey_redo, }; @@ -533,6 +534,9 @@ struct project_state void *Interact_Address; int Interact_Count; + // whether duplicated layers get created above or below + int DuplicateDirection = -1; + ImGuiID RightDock; // NOTE(fox): We need to keep track of when the user changes the CurrentValue of a diff --git a/src/layer.cpp b/src/layer.cpp index dfe91a4..4c94987 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -211,7 +211,12 @@ Layer_DeselectAll(project_data *File, project_state *State, memory *Memory) { 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); - Layer->IsSelected = false; + // stupid way to preserve this + if (Layer->IsSelected == -1) { + Layer->IsSelected = 2; + } else { + Layer->IsSelected = false; + } } State->Interact_Transform = {}; State->MostRecentlySelectedLayer = -1; @@ -372,11 +377,11 @@ Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, // TODO(fox): Precomps? static bool32 -Layer_TestForPoint(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex, v2 CompUV) +Layer_TestForPoint(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 CompIndex, v2 CompUV) { - block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); - sorted_comp_array SortedCompStart = SortedCompArray[PrincipalIndex]; - sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, PrincipalIndex); + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_array SortedCompStart = SortedCompArray[CompIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) { sorted_layer_array SortEntry = SortedLayerStart[i]; uint32 Index_Physical = SortEntry.Block_Layer_Index; @@ -385,7 +390,7 @@ Layer_TestForPoint(memory *Memory, project_state *State, ui *UI, sorted_comp_arr Layer_GetDimensions(Memory, Layer, &Width, &Height); layer_transforms T = Layer_GetTransforms(Layer); v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, CompUV); - if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected) + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && (Layer->IsSelected || Layer->IsPrecomp) && !Layer->IsLocked) { return 1; } @@ -393,15 +398,16 @@ Layer_TestForPoint(memory *Memory, project_state *State, ui *UI, sorted_comp_arr return 0; } +// Same loop as Render_UI and ImGui_Viewport_SelectedLayerUI except we're // NOTE(fox): We loop twice to allow for convenient down-travelling when only // one layer is selected, toggleable by the BelowOnly bool (i.e. shift held). -// TODO(fox): Precomps? +#if 0 static int32 -Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex, bool32 BelowOnly) +Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 CompIndex, bool32 BelowOnly) { - block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex); - sorted_comp_array SortedCompStart = SortedCompArray[PrincipalIndex]; - sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, PrincipalIndex); + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_array SortedCompStart = SortedCompArray[CompIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); int SelectionCount = 0; int SelectedLayerIndex = 0; for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) { @@ -427,16 +433,27 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar Layer_GetDimensions(Memory, Layer, &Width, &Height); layer_transforms T = Layer_GetTransforms(Layer); v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, State->LastClickedPoint); - if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected && !Layer->IsLocked) + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && (!Layer->IsSelected || (Layer->IsPrecomp && Layer->IsSelected)) && !Layer->IsLocked) { - if (!BelowOnly && SelectionCount == 1) { - if (i < SelectedLayerIndex) { + if (Layer->IsPrecomp) { + layer_transforms T = Layer_GetTransforms(Layer); + if (ExtraT.scale != 0) { + T = Transform_Add(T, ExtraT, Comp->Width, Comp->Height); + } + T = Transform_TestInteracts(State, Layer, SortEntry, T); + LayerIndex = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, Layer->Block_Source_Index, BelowOnly); + if (LayerIndex != -1) + break; + } else { + if (!BelowOnly && SelectionCount == 1) { + if (i < SelectedLayerIndex) { + LayerIndex = Index_Physical; + break; + } + } else { LayerIndex = Index_Physical; break; } - } else { - LayerIndex = Index_Physical; - break; } } // if (Layer->IsPrecomp) { @@ -448,6 +465,7 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar } return LayerIndex; } +#endif // TODO(fox): learn this; stop stealing from stackoverflow bool32 Line_TestIntersect(real32 p0_x, real32 p0_y, real32 p1_x, real32 p1_y, diff --git a/src/main.cpp b/src/main.cpp index c7e4808..f8dd546 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,7 @@ uint32 BitmapFill = 0x00000001; #include "imgui_helper.cpp" #include "imgui_ui_properties.cpp" #include "imgui_ui_timeline.cpp" + #include "imgui_ui_viewport.cpp" #if DEBUG #include "imgui_ui_debug.cpp" @@ -345,6 +346,158 @@ GL_Test(const ImDrawList* parent_list, const ImDrawCmd* cmd) GL_DeleteHWBuffer(&MSBuffer); } +// TODO(fox): We have five functions that essentially do this same precomp loop +// that carries over transform data; wrap the loop into a function like Block_Loop. + +// Find the precomp the user most likely wants to insert a shape into, the +// precomp that is or contains MostRecentlySelectedLayer. +static void +LayerIterate_DeepestPrecomp(project_state *State, memory *Memory, uint32 CompIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, int *SelectionCount, int *SelectedLayerIndex, int *SelectedPrecompIndex) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); + int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount; + for (int i = LayerCount - 1; i >= 0; i--) + { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + Assert(Layer->Block_Composition_Index == CompIndex); + int Width = 0, Height = 0; + Layer_GetDimensions(Memory, Layer, &Width, &Height); + if (Layer->IsPrecomp) { + // only like 20% sure how this works... + layer_transforms NewExtraT = Layer_GetTransforms(Layer); + v2 NewCenter = T_CompPosToLayerPos(NewExtraT, Comp->Width, Comp->Height, Width, Height, Center.x, Center.y); + NewExtraT.rotation = ExtraT.rotation - NewExtraT.rotation; + NewExtraT.scale = ExtraT.scale / NewExtraT.scale; + Assert(0); + // LayerIterate_Te(State, Memory, Layer->Block_Source_Index, NewExtraT, NewCenter, SortedCompArray, SortedLayerArray); + } + v2 Position = State->Interact_Transform.Position; + real32 Rad = (ExtraT.rotation * (PI / 180)); + v2 XAxis = Position.x * ExtraT.scale * V2(cos(Rad), sin(Rad)); + v2 YAxis = Position.y * -ExtraT.scale * V2(sin(Rad), -cos(Rad)); + Position = XAxis + YAxis; + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, Center / V2(Comp->Width, Comp->Height)); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected) + { + *SelectionCount += 1; + *SelectedLayerIndex = i; + *SelectedPrecompIndex = Layer->Block_Composition_Index; + } + } +} + +// We have to loop over the layers a second time when testing selection because +// we want to change the behavior if the mouse is clicking on a layer that is +// already selected. +static void +LayerIterate_SelectionStatus(project_state *State, memory *Memory, uint32 CompIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, int *SelectionCount, int *SelectedLayerIndex, int *SelectedPrecompIndex) +{ + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); + int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount; + for (int i = LayerCount - 1; i >= 0; i--) + { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + Assert(Layer->Block_Composition_Index == CompIndex); + int Width = 0, Height = 0; + Layer_GetDimensions(Memory, Layer, &Width, &Height); + if (Layer->IsPrecomp) { + // only like 20% sure how this works... + layer_transforms NewExtraT = Layer_GetTransforms(Layer); + v2 NewCenter = T_CompPosToLayerPos(NewExtraT, Comp->Width, Comp->Height, Width, Height, Center.x, Center.y); + NewExtraT.rotation = ExtraT.rotation - NewExtraT.rotation; + NewExtraT.scale = ExtraT.scale / NewExtraT.scale; + LayerIterate_SelectionStatus(State, Memory, Layer->Block_Source_Index, NewExtraT, NewCenter, SortedCompArray, SortedLayerArray, SelectionCount, SelectedLayerIndex, SelectedPrecompIndex); + } + v2 Position = State->Interact_Transform.Position; + real32 Rad = (ExtraT.rotation * (PI / 180)); + v2 XAxis = Position.x * ExtraT.scale * V2(cos(Rad), sin(Rad)); + v2 YAxis = Position.y * -ExtraT.scale * V2(sin(Rad), -cos(Rad)); + Position = XAxis + YAxis; + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, Center / V2(Comp->Width, Comp->Height)); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected && !Layer->IsLocked) + { + *SelectionCount += 1; + *SelectedLayerIndex = i; + *SelectedPrecompIndex = Layer->Block_Composition_Index; + } + } +} + +static int32 +LayerIterate_SelectionAct(project_state *State, memory *Memory, uint32 CompIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, int SelectionCount, int SelectedLayerIndex, int SelectedPrecompIndex, bool32 BelowOnly) +{ + int32 LayerIndex = -1; + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex); + sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex]; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex); + int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount; + for (int i = LayerCount - 1; i >= 0; i--) + { + sorted_layer_array SortEntry = SortedLayerStart[i]; + uint32 Index_Physical = SortEntry.Block_Layer_Index; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); + Assert(Layer->Block_Composition_Index == CompIndex); + int Width = 0, Height = 0; + Layer_GetDimensions(Memory, Layer, &Width, &Height); + if (Layer->IsPrecomp && Layer->IsSelected) { + // only like 20% sure how this works... + layer_transforms NewExtraT = Layer_GetTransforms(Layer); + v2 NewCenter = T_CompPosToLayerPos(NewExtraT, Comp->Width, Comp->Height, Width, Height, Center.x, Center.y); + NewExtraT.rotation = ExtraT.rotation - NewExtraT.rotation; + NewExtraT.scale = ExtraT.scale / NewExtraT.scale; + LayerIndex = LayerIterate_SelectionAct(State, Memory, Layer->Block_Source_Index, NewExtraT, NewCenter, SortedCompArray, SortedLayerArray, SelectionCount, SelectedLayerIndex, SelectedPrecompIndex, BelowOnly); + if (LayerIndex != -1) { + Layer->IsSelected = -1; + return LayerIndex; + } + } + v2 Position = State->Interact_Transform.Position; + real32 Rad = (ExtraT.rotation * (PI / 180)); + v2 XAxis = Position.x * ExtraT.scale * V2(cos(Rad), sin(Rad)); + v2 YAxis = Position.y * -ExtraT.scale * V2(sin(Rad), -cos(Rad)); + Position = XAxis + YAxis; + layer_transforms T = Layer_GetTransforms(Layer); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, Center / V2(Comp->Width, Comp->Height)); + if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected && !Layer->IsLocked) + { + if (!BelowOnly && SelectionCount == 1) { + if (i < SelectedLayerIndex || SelectedPrecompIndex != CompIndex) { + LayerIndex = Index_Physical; + break; + } + } else { + LayerIndex = Index_Physical; + break; + } + } + } + return LayerIndex; +} + +static int32 +LayerIterate_TestSelection(project_state *State, memory *Memory, uint32 PrincipalIndex, layer_transforms ExtraT, v2 Center, + sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, bool32 BelowOnly) +{ + int SelectionCount = 0; + int SelectedLayerIndex = 0; + int SelectedPrecompIndex = 0; + LayerIterate_SelectionStatus(State, Memory, PrincipalIndex, ExtraT, Center, SortedCompArray, SortedLayerArray, &SelectionCount, &SelectedLayerIndex, &SelectedPrecompIndex); + return LayerIterate_SelectionAct(State, Memory, PrincipalIndex, ExtraT, Center, SortedCompArray, SortedLayerArray, SelectionCount, SelectedLayerIndex, SelectedPrecompIndex, BelowOnly); +} + // Same loop as Render_UI and ImGui_Viewport_SelectedLayerUI except we're // finding the inverse transform-- i.e. transforming the layers locally rather // than transforming them in comp space. @@ -367,17 +520,8 @@ LayerIterate(project_state *State, memory *Memory, uint32 CompIndex, layer_trans // only like 20% sure how this works... layer_transforms NewExtraT = Layer_GetTransforms(Layer); v2 NewCenter = T_CompPosToLayerPos(NewExtraT, Comp->Width, Comp->Height, Width, Height, Center.x, Center.y); - if (State->Interact_Transform.Radians != 0.0f) - NewExtraT.rotation = -NewExtraT.rotation; - if (ExtraT.scale) { - NewExtraT = Transform_Add2(ExtraT, NewExtraT, Comp->Width, Comp->Height); - v2 NewPos = T_CompPosToLayerPos(NewExtraT, Comp->Width, Comp->Height, Width, Height, NewExtraT.x, NewExtraT.y); - NewExtraT.x = NewPos.x; - NewExtraT.y = NewPos.y; - } else { - NewExtraT.rotation = -NewExtraT.rotation; - NewExtraT.scale = 1.0f / NewExtraT.scale; - } + NewExtraT.rotation = ExtraT.rotation - NewExtraT.rotation; + NewExtraT.scale = ExtraT.scale / NewExtraT.scale; LayerIterate(State, Memory, Layer->Block_Source_Index, NewExtraT, NewCenter, SortedCompArray, SortedLayerArray); } if (Layer->IsSelected == 1) { @@ -385,12 +529,17 @@ LayerIterate(project_state *State, memory *Memory, uint32 CompIndex, layer_trans if (Layer->IsPrecomp) PostMsg(State, "DEBUG: Precomp transformed!"); #endif + v2 Position = State->Interact_Transform.Position; + real32 Rad = (ExtraT.rotation * (PI / 180)); + v2 XAxis = Position.x * ExtraT.scale * V2(cos(Rad), sin(Rad)); + v2 YAxis = Position.y * -ExtraT.scale * V2(sin(Rad), -cos(Rad)); + Position = XAxis + YAxis; layer_transforms T = Layer_GetTransforms(Layer); History_Action_Swap(Memory, F_Layers, sizeof(Layer->x.CurrentValue), &Layer->x.CurrentValue); History_Action_Swap(Memory, F_Layers, sizeof(Layer->y.CurrentValue), &Layer->y.CurrentValue); History_Action_Swap(Memory, F_Layers, sizeof(Layer->scale.CurrentValue), &Layer->scale.CurrentValue); History_Action_Swap(Memory, F_Layers, sizeof(Layer->rotation.CurrentValue), &Layer->rotation.CurrentValue); - Transform_ApplyLocal(State->Interact_Transform, T, ExtraT, Center, Comp->Width, Comp->Height, Width, Height, + Transform_ApplyLocal(State->Interact_Transform, Position, Center, &Layer->x.CurrentValue, &Layer->y.CurrentValue, &Layer->rotation.CurrentValue, &Layer->scale.CurrentValue); } } @@ -862,7 +1011,7 @@ int main(int argc, char *argv[]) { MainComp->Frame_Count = 80; MainComp->Frame_End = 79; MainComp->Occupied = 1; - MainComp->Name_String_Index = String_AddToFile(&Memory, "Main comp"); + MainComp->Name_String_Index = String_AddToFile(&Memory, "Main comp", 0); File->Comp_Count = 1; @@ -1014,7 +1163,7 @@ int main(int argc, char *argv[]) { State->UpdateFrame = true; State->MostRecentlySelectedLayer = 0; } - + // File->PrincipalCompIndex = 1; #else // uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/yu.webm"); // block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, SourceIndex); @@ -1082,6 +1231,14 @@ int main(int argc, char *argv[]) { // NOTE(fox): These commands affect sorting, and should not be executed // in any UI or the renderer. + + // TODO(fox): Even though they affect sorting there are some of them + // that _need_ sort info in order to be able to be wrapped in one + // HistoryEntry, so we can either create a new sort info in place or + // execute the command right before the sort info used by the + // UI/renderer is popped, and I'm choosing the latter. + int State_ExecuteAtEnd = 0; + if (State->HotkeyInput) { switch (State->HotkeyInput) { case hotkey_none: @@ -1104,13 +1261,17 @@ int main(int argc, char *argv[]) { } break; case hotkey_newlayer_shape: { - Project_ShapeLayer_New(File, State, &Memory); + State_ExecuteAtEnd = 1; } break; case hotkey_newlayer_source: { Source_UICreateButton(File, State, &Memory); State->UpdateKeyframes = true; } break; + case hotkey_duplicatelayer: + { + State_ExecuteAtEnd = 2; + } break; case hotkey_deletelayer: { Project_Layer_Delete(File, State, &Memory); @@ -1223,6 +1384,19 @@ int main(int argc, char *argv[]) { Arbitrary_Zero((uint8 *)State->Queue.Item, sizeof(State->Queue.Item)); #endif + if (State_ExecuteAtEnd) { + if (State_ExecuteAtEnd == 1) { + Project_ShapeLayer_New(File, State, &Memory); + } else if (State_ExecuteAtEnd == 2) { + History_Entry_Commit(&Memory, "Duplicate layers"); + v2 Offset = V2(State->Interact_Dup_Previous[0], State->Interact_Dup_Previous[1]); + Project_Layer_Duplicate(File, State, &Memory, Sorted.CompArray, Sorted.LayerArray, Offset, 0); + State->Interact_Transform = {}; + History_Entry_End(&Memory); + } + State->UpdateFrame = true; + } + File_Sort_Pop(&Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize); // NOTE(fox): We could theoretically allow scratch to persist between diff --git a/src/prenderer.cpp b/src/prenderer.cpp index 11f72f6..0af9911 100644 --- a/src/prenderer.cpp +++ b/src/prenderer.cpp @@ -63,20 +63,9 @@ Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHe // Transform given data based on state's Interact data. static void -Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale) +Transform_ApplyLocal(interact_transform Interact, v2 Position, v2 Center, + real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale) { - v2 BoxLength = Interact.Max - Interact.Min; - v2 Center = Interact.Max - (BoxLength/2); - if (Interact.RadianOffset != 0.0f) { - v2 LocalCenter = Interact.NewCenter; - real32 Rad = Interact.RadianOffset; - real32 Point0X = Center.x - Interact.OGCenter.x; - real32 Point0Y = Center.y - Interact.OGCenter.y; - v2 XAxis = (Point0X * 1.0f)*V2(cos(Rad), sin(Rad)); - v2 YAxis = (Point0Y * 1.0f)*V2(sin(Rad), -cos(Rad)); - Center = Interact.OGCenter + XAxis + YAxis; - } - real32 Point0X = Center.x - *OutputX; real32 Point0Y = Center.y - *OutputY; @@ -89,13 +78,31 @@ Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 real32 X0 = -XAxis.x - YAxis.x + Center.x; real32 Y0 = -XAxis.y - YAxis.y + Center.y; - *OutputX = X0 + Interact.Position.x; - *OutputY = Y0 + Interact.Position.y; + *OutputX = X0 + Position.x; + *OutputY = Y0 + Position.y; *OutputRotation += Rotation; - // *OutputScale += Interact.Scale - 1.0f; *OutputScale *= Interact.Scale; } +// TODO(fox): Clean up function to do the RadianOffset rotation earlier in the loops of where the function is called +static void +Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale) +{ + v2 BoxLength = Interact.Max - Interact.Min; + v2 Center = Interact.Max - (BoxLength/2); + if (Interact.RadianOffset != 0.0f) { + v2 LocalCenter = Interact.NewCenter; + real32 Rad = Interact.RadianOffset; + real32 Point0X = Center.x - Interact.OGCenter.x; + real32 Point0Y = Center.y - Interact.OGCenter.y; + v2 XAxis = (Point0X * 1.0f)*V2(cos(Rad), sin(Rad)); + v2 YAxis = (Point0Y * 1.0f)*V2(sin(Rad), -cos(Rad)); + Center = Interact.OGCenter + XAxis + YAxis; + } + + Transform_ApplyLocal(Interact, Interact.Position, Center, OutputX, OutputY, OutputRotation, OutputScale); +} + static v2 TransformVec(layer_transforms T, real32 Width, real32 Height, v2 Point) { @@ -106,36 +113,6 @@ TransformVec(layer_transforms T, real32 Width, real32 Height, v2 Point) return V2(LocalPoint.x, LocalPoint.y); } -static void -Transform_ApplyLocal(interact_transform Interact, layer_transforms T, layer_transforms ExtraT, v2 Center, - real32 CompWidth, real32 CompHeight, real32 Width, real32 Height, - real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale) -{ - v2 Position = Interact.Position; - if (ExtraT.scale) { - v2 CompPosition = TransformVec(ExtraT, CompWidth, CompHeight, Interact.Position); - Position = CompPosition; - } - - real32 Point0X = Center.x - *OutputX; - real32 Point0Y = Center.y - *OutputY; - - real32 Rad = Interact.Radians; - real32 Rotation = Rad / (PI / 180); - - v2 XAxis = (Point0X * Interact.Scale)*V2(cos(Rad), sin(Rad)); - v2 YAxis = (Point0Y * -Interact.Scale)*V2(sin(Rad), -cos(Rad)); - - real32 X0 = -XAxis.x - YAxis.x + Center.x; - real32 Y0 = -XAxis.y - YAxis.y + Center.y; - - *OutputX = X0 + Position.x; - *OutputY = Y0 + Position.y; - *OutputRotation += Rotation; - // *OutputScale += Interact.Scale - 1.0f; - *OutputScale *= Interact.Scale; -} - static void Transform_IterateOuterBounds(block_layer *Layer, uint32 Width, uint32 Height, real32 *MinX, real32 *MinY, real32 *MaxX, real32 *MaxY) { @@ -353,19 +330,6 @@ Transform_Add(layer_transforms T, layer_transforms ExtraT, real32 Width, real32 return T; } -static layer_transforms -Transform_Add2(layer_transforms T, layer_transforms ExtraT, real32 Width, real32 Height) -{ - v2 NewPos = TransformPoint(ExtraT, Width, Height, V2(T.x, T.y)); - T.x = NewPos.x; - T.y = NewPos.y; - T.ax = T.ax; - T.ay = T.ay; - T.rotation = T.rotation - ExtraT.rotation; - T.scale = T.scale / ExtraT.scale; - return T; -} - static ImVec2 Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point) { diff --git a/src/sorted.cpp b/src/sorted.cpp index 1d2b4f2..5826e68 100644 --- a/src/sorted.cpp +++ b/src/sorted.cpp @@ -155,6 +155,93 @@ Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer_array *S // second is for sorting the layers by offset, and the third is for applying // interactivity if the user is moving any layers. +static void +Layer_Sort_Shift(project_state *State, memory *Memory, + sorted_layer_array *LayerArrayStart, sorted_comp_array *CompArrayStart, + uint32 LayerCount, uint32 CompCount) +{ + int32 Offset = (int32)State->Interact_Offset[1]; + bool32 Direction = (Offset > 0) ? 1 : -1; + for (uint32 c = 0; c < CompCount; c++) { + sorted_comp_array *SortedCompStart = &CompArrayStart[c]; + if (!SortedCompStart->LayerCount) + continue; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompArrayStart, c); + int i = (Direction > 0) ? SortedCompStart->LayerCount - 1 : 0; + bool32 Case = 1; + while (Case) { + int32 EntriesPassed = 0; + sorted_layer_array *LayerEntry = &SortedLayerStart[i]; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index); + Assert(LayerEntry->SortedOffset == Layer->Vertical_Offset); + if (Layer->IsSelected) { + int32 SpacesToMove = Offset * Direction; + while (SpacesToMove) { + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerStart, *SortedCompStart, &EntriesPassed, LayerEntry, 0); + LayerEntry->SortedOffset -= Direction; + SpacesToMove--; + } + } + int b = 0; + while (b < EntriesPassed) { + sorted_layer_array *FrontEntry = &SortedLayerStart[i+(b*Direction)]; + sorted_layer_array *BackEntry = &SortedLayerStart[i+((b+1)*Direction)]; + sorted_layer_array Swap = *FrontEntry; + *FrontEntry = *BackEntry; + *BackEntry = Swap; + b++; + } + i -= Direction; + Case = (Direction > 0) ? (i >= 0) : (i < SortedCompStart->LayerCount); + } + } +} + +#if 0 +static void +Layer_Sort_Shift2(project_state *State, memory *Memory, + sorted_layer_array *LayerArrayStart, sorted_comp_array *CompArrayStart, + uint32 LayerCount, uint32 CompCount, int32 Offset) +{ + bool32 Direction = (Offset > 0) ? 1 : -1; + for (uint32 c = 0; c < CompCount; c++) { + sorted_comp_array *SortedCompStart = &CompArrayStart[c]; + if (!SortedCompStart->LayerCount) + continue; + sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompArrayStart, c); + int i = (Direction > 0) ? SortedCompStart->LayerCount - 1 : 0; + int FauxIncrement = 0; + bool32 Case = 1; + while (Case) { + int Idx = i + FauxIncrement; + int32 EntriesPassed = 0; + sorted_layer_array *LayerEntry = &SortedLayerStart[Idx]; + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index); + Assert(LayerEntry->SortedOffset == Layer->Vertical_Offset); + if (Layer->IsSelected) { + int32 SpacesToMove = Offset * Direction; + Assert(SpacesToMove == 1); + while (SpacesToMove) { + Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerStart, *SortedCompStart, &EntriesPassed, LayerEntry, 0); + SpacesToMove--; + } + int b = 0; + while (b < EntriesPassed) { + sorted_layer_array *FrontEntry = &SortedLayerStart[i+(b*Direction)]; + sorted_layer_array *BackEntry = &SortedLayerStart[i+((b+1)*Direction)]; + sorted_layer_array Swap = *FrontEntry; + *FrontEntry = *BackEntry; + *BackEntry = Swap; + b++; + } + } + i -= Direction; + Case = (Direction > 0) ? (i >= 0) : (i < SortedCompStart->LayerCount); + } + } +} +#endif + static void Layer_SortAll(project_state *State, memory *Memory, sorted_layer_array *LayerArrayStart, sorted_comp_array *CompArrayStart, @@ -166,7 +253,7 @@ Layer_SortAll(project_state *State, memory *Memory, Assert(Layer->Block_Composition_Index < CompCount); sorted_comp_array *SortedCompStart = &CompArrayStart[Layer->Block_Composition_Index]; SortedCompStart->LayerCount++; - if (State->Interact_Active == interact_type_viewport_duplicate && Layer->IsSelected) { + if (State->Interact_Active == interact_type_viewport_duplicate && Layer->IsSelected == 1) { SortedCompStart->FakeLayerCount++; } } @@ -197,41 +284,7 @@ Layer_SortAll(project_state *State, memory *Memory, SortedCompStart->CurrentSortIndex++; } if (State->Interact_Active == interact_type_layer_move) { - int32 Offset = (int32)State->Interact_Offset[1]; - bool32 Direction = (Offset > 0) ? 1 : -1; - for (uint32 c = 0; c < CompCount; c++) { - sorted_comp_array *SortedCompStart = &CompArrayStart[c]; - if (!SortedCompStart->LayerCount) - continue; - sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompArrayStart, c); - int i = (Direction > 0) ? SortedCompStart->LayerCount - 1 : 0; - bool32 Case = 1; - while (Case) { - int32 EntriesPassed = 0; - sorted_layer_array *LayerEntry = &SortedLayerStart[i]; - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index); - Assert(LayerEntry->SortedOffset == Layer->Vertical_Offset); - if (Layer->IsSelected) { - int32 SpacesToMove = Offset * Direction; - while (SpacesToMove) { - Layer_Sort_CheckPrev(Memory, i, Direction, SortedLayerStart, *SortedCompStart, &EntriesPassed, LayerEntry, 0); - LayerEntry->SortedOffset -= Direction; - SpacesToMove--; - } - } - int b = 0; - while (b < EntriesPassed) { - sorted_layer_array *FrontEntry = &SortedLayerStart[i+(b*Direction)]; - sorted_layer_array *BackEntry = &SortedLayerStart[i+((b+1)*Direction)]; - sorted_layer_array Swap = *FrontEntry; - *FrontEntry = *BackEntry; - *BackEntry = Swap; - b++; - } - i -= Direction; - Case = (Direction > 0) ? (i >= 0) : (i < SortedCompStart->LayerCount); - } - } + Layer_Sort_Shift(State, Memory, LayerArrayStart, CompArrayStart, LayerCount, CompCount); } else if (State->Interact_Active == interact_type_viewport_duplicate) { for (uint32 c = 0; c < CompCount; c++) { @@ -245,7 +298,7 @@ Layer_SortAll(project_state *State, memory *Memory, int Idx = i + FauxIncrement; sorted_layer_array *LayerEntry = &SortedLayerStart[Idx]; block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index); - if (Layer->IsSelected) { + if (Layer->IsSelected == 1) { for (int a = i+1; a < SortedCompStart->LayerCount; a++) { int PrevIdx = a + FauxIncrement - 1; sorted_layer_array *PrevLayerEntry = &SortedLayerStart[PrevIdx]; diff --git a/src/strings.cpp b/src/strings.cpp index e6c3ec5..73adf8a 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -28,11 +28,12 @@ CopyStrings(void *Dest, void *Data) } static uint16 -String_AddToFile(memory *Memory, char *Char) +String_AddToFile(memory *Memory, char *Char, bool32 NoUndo) { uint16 FileIndex = Memory_Block_AllocateNew(Memory, F_Strings); block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, FileIndex, 0); - History_Action_Block_Swap(Memory, F_Strings, String); + if (NoUndo) + History_Action_Block_Swap(Memory, F_Strings, String); String->Occupied = 1; uint16 i = 0; while (Char[i] != '\0') { diff --git a/src/undo.cpp b/src/undo.cpp index 38c22ef..c26ab1b 100644 --- a/src/undo.cpp +++ b/src/undo.cpp @@ -271,6 +271,7 @@ History_Purge(memory *Memory, history_entry_list *History, uint64 ActionCount_To static void History_Action_Add(memory *Memory, history_action ActionData, void *ReferenceData = NULL) { + Assert(Debug.UndoState == 1); // This action wasn't preceded by a History_Undo_Start! history_entry_list *History = &Memory->History; history_entry *Entry = &History->Entry[History->EntryPlayhead - 1]; -- cgit v1.2.3