summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/createcalls.cpp90
-rw-r--r--src/imgui_ui.cpp6
-rw-r--r--src/imgui_ui_properties.cpp3
-rw-r--r--src/imgui_ui_timeline.cpp30
-rw-r--r--src/imgui_ui_viewport.cpp24
-rw-r--r--src/include/all.h16
-rw-r--r--src/include/functions.h128
-rw-r--r--src/include/layer.h3
-rw-r--r--src/include/main.h4
-rw-r--r--src/layer.cpp52
-rw-r--r--src/main.cpp204
-rw-r--r--src/prenderer.cpp82
-rw-r--r--src/sorted.cpp127
-rw-r--r--src/strings.cpp5
-rw-r--r--src/undo.cpp1
15 files changed, 446 insertions, 329 deletions
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)
{
@@ -107,36 +114,6 @@ TransformVec(layer_transforms T, real32 Width, real32 Height, v2 Point)
}
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)
{
real32 Rad = (Layer->rotation.CurrentValue * (PI / 180));
@@ -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
@@ -156,6 +156,93 @@ Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer_array *S
// 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,
uint32 LayerCount, uint32 CompCount)
@@ -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];