From 84d04d391bc4bf9481106d4f5ac4d3dd8f27ed87 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Fri, 6 Jan 2023 17:44:22 -0500 Subject: round edges --- src/bezier.cpp | 42 ++++++++++++++++++++++ src/createcalls.cpp | 13 +++++++ src/imgui_ui.cpp | 1 + src/imgui_ui_viewport.cpp | 92 ++++++++++------------------------------------- src/include/main.h | 7 ++-- src/include/my_math.h | 1 + src/layer.cpp | 2 -- 7 files changed, 80 insertions(+), 78 deletions(-) diff --git a/src/bezier.cpp b/src/bezier.cpp index 6bb1541..1585495 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -34,6 +34,48 @@ Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 Tar return Y; } +// TODO(fox): Incorporate sorting for non-continuous shapes. +static uint32 +Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData) +{ + real32 Radius = Shape->Opt.Roundness; + bezier_point *PointStart = PointData; + for (int i = 0; i < Shape->Point_Count; i++) { + bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); + if (Radius <= 0 && Point->Type == interpolation_type_linear) { + v2 Pos = Point->Pos[0]; + int Index_Prev = (i != 0) ? i-1 : Shape->Point_Count-1; + int Index_Next = (i != Shape->Point_Count-1) ? i+1 : 0; + v2 Pos_Prev = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Index_Prev, 1)->Pos[0]; + v2 Pos_Next = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Index_Next, 1)->Pos[0]; + v2 Vector_Prev = Pos - Pos_Prev; + v2 Vector_Next = Pos - Pos_Next; + real32 Length_Prev = sqrtf(LengthSq(Vector_Prev)); + real32 Length_Next = sqrtf(LengthSq(Vector_Next)); + + // real32 RadAngle = acos(Inner(Vector_Prev, VectorR) / (LengthL * LengthR)) * PI / 180; + // real32 AngleKappa = (4.f/3) * tan(RadAngle * 1/4); + + real32 Ratio_Prev = Radius / Length_Prev; + real32 Ratio_Prev_Inv = 1.0f - Ratio_Prev; + + real32 Ratio_Next = Radius / Length_Next; + real32 Ratio_Next_Inv = 1.0f - Ratio_Next; + + v2 Point_1 = Pos_Prev + V2(Vector_Prev.x * Ratio_Prev_Inv, (Vector_Prev.y * Ratio_Prev_Inv)); + v2 Point_2 = Vector_Prev * Ratio_Prev * (1-KAPPA); + v2 Point_3 = Pos_Next + V2(Vector_Next.x * Ratio_Next_Inv, Vector_Next.y * Ratio_Next_Inv); + v2 Point_4 = Vector_Next * Ratio_Next * (1-KAPPA); + + *PointData++ = { 1, { Point_1, Point_2, V2(0, 0) }, interpolation_type_bezier, 0 }; + *PointData++ = { 1, { Point_3, V2(0, 0), Point_4 }, interpolation_type_bezier, 0 }; + } else { + *PointData++ = *Point; + } + } + return PointData - PointStart; +} + static bezier_point * Bezier_LookupAddress(memory *Memory, uint16 *Block_Bezier_Index, uint16 Index, bool32 AssertExists) { diff --git a/src/createcalls.cpp b/src/createcalls.cpp index cd8f3d5..4334dc8 100644 --- a/src/createcalls.cpp +++ b/src/createcalls.cpp @@ -627,6 +627,18 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory) Layer->Frame_End = MainComp->Frame_End; Layer_Select(Memory, State, Memory_Block_LazyIndexAtAddress(Memory, F_Layers, Layer)); + shape_layer *Shape = &File->UI.Shape; + v2 Min = {}, Max = {}; + void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128); + layer_transforms T = {}; + NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, 0, 0, 0, &Min, &Max); + Memory_PopScratch(Memory, sizeof(nvg_point) * 128); + Shape->Width = Max.x - Min.x; + Shape->Height = Max.y - Min.y; + Layer->x.CurrentValue = Min.x + (Shape->Width / 2); + Layer->y.CurrentValue = Min.y + (Shape->Height / 2); + + /* v2 Min = V2(10000, 10000); v2 Max = V2(-10000, -10000); shape_layer *Shape = &File->UI.Shape; @@ -644,6 +656,7 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory) v2 ShapeSize = (Max - Min); Layer->x.CurrentValue = Min.x + (ShapeSize.x / 2); Layer->y.CurrentValue = Min.y + (ShapeSize.y / 2); + */ for (int i = 0; i < Shape->Point_Count; i++) { bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); Point->Pos[0] = Point->Pos[0] - Min; diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp index 50d25a4..0a7f310 100644 --- a/src/imgui_ui.cpp +++ b/src/imgui_ui.cpp @@ -23,6 +23,7 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, ImGui::Begin("Files"); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + if (ImGui::IsKeyPressed(ImGuiKey_Backspace)) { // TODO(fox): Delete sources code! diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index fae7bd4..774b305 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -82,7 +82,7 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io if (Point_1->Type == interpolation_type_bezier) draw_list->AddLine(ScreenPoint_0[1], ScreenPoint_0[2], wcol, 2.0f); - ImU32 PointCol = (Point_1->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f); + ImU32 PointCol = (Point_1->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 0.2f); ImGui::PushID(i); for (int a = 0; a < 3; a++) { ImGui::PushID(a); @@ -100,6 +100,12 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); } if (IsItemActivated) { + if (!io.KeyShift) { + for (int p = 0; p < Shape->Point_Count; p++) { + bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, p, 1); + Point->IsSelected = 0; + } + } Point_1->IsSelected = 1; } if (IsItemActive) { @@ -111,12 +117,12 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io Assert(State->Interact_Active == interact_type_keyframe_move); ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); if (io.MouseDelta.x || io.MouseDelta.y) { + if (State->Interact_Active == interact_type_keyframe_move) { + State->Interact_Offset[0] = DragDelta.x * (MainComp->Width / UI->CompZoom.x); + State->Interact_Offset[1] = DragDelta.y * (MainComp->Height / UI->CompZoom.y); + } State->UpdateFrame = true; } - if (State->Interact_Active == interact_type_keyframe_move) { - State->Interact_Offset[0] = DragDelta.x * (MainComp->Width / UI->CompZoom.x); - State->Interact_Offset[1] = DragDelta.y * (MainComp->Height / UI->CompZoom.y); - } } } if (IsItemDeactivated) { @@ -126,85 +132,23 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io Shape->IsClosed = true; History_Entry_End(Memory); } else if (Layer != NULL) { - layer_transforms T = Layer_GetTransforms(Layer); History_Entry_Commit(Memory, "Move point"); - void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128); - v2 Min_Old = {}, Max_Old = {}; - NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min_Old, &Max_Old); - v2 TestMin = Min_Old, TestMax = Max_Old; + layer_transforms T = Layer_GetTransforms(Layer); for (int p = 0; p < Shape->Point_Count; p++) { bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, p, 1); if (Point->IsSelected) { v2 *Pos = &Point->Pos[Point->IsSelected-1]; History_Action_Swap(Memory, F_Bezier, sizeof(*Pos), Pos); + *Pos = TransformPoint(T, Shape->Width, Shape->Height, *Pos); Pos->x += State->Interact_Offset[0]; Pos->y += State->Interact_Offset[1]; - if (Pos->x < TestMin.x) { - TestMin.x = Pos->x; - } - if (Pos->y < TestMin.y) { - TestMin.y = Pos->y; - } - if (Pos->x > TestMax.x) { - TestMax.x = Pos->x; - } - if (Pos->y > TestMax.y) { - TestMax.y = Pos->y; - } + *Pos = T_CompPosToLayerPos(T, MainComp->Width, MainComp->Height, Shape->Width, Shape->Height, Pos->x, Pos->y); } } - v2 MinDiff = TestMin - Min_Old; - v2 MaxDiff = TestMax - Max_Old; - for (int p = 0; p < Shape->Point_Count; p++) { - bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, p, 1); - v2 *Pos = &Point->Pos[0]; - History_Action_Swap(Memory, F_Bezier, sizeof(*Pos), Pos); - if (MinDiff.x) - Pos->x -= State->Interact_Offset[0]; - if (MinDiff.y) - Pos->y -= State->Interact_Offset[1]; - if (MaxDiff.x) - // Pos->x -= State->Interact_Offset[0]; - if (MaxDiff.y) - // Pos->y += State->Interact_Offset[1]; - int FU = 0; - } - State->Interact_Active = interact_type_none; - v2 Min_New = {}, Max_New = {}; - NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, Shape->Width, Shape->Height, Width, Height, 1, &Min_New, &Max_New); - - Memory_PopScratch(Memory, sizeof(nvg_point) * 128); - - int Width_Old = Max_Old.x - Min_Old.x; - int Width_New = Max_New.x - Min_New.x; - int Height_New = Max_New.y - Min_New.y; - if (MinDiff.x) { - History_Action_Swap(Memory, F_Layers, sizeof(Layer->ax.CurrentValue), &Layer->ax.CurrentValue); - Layer->ax.CurrentValue -= (real32)(State->Interact_Offset[0]) * (1.0f - Layer->ax.CurrentValue) / Width_New; - } if (MinDiff.y) { - History_Action_Swap(Memory, F_Layers, sizeof(Layer->ay.CurrentValue), &Layer->ay.CurrentValue); - Layer->ay.CurrentValue -= (real32)(State->Interact_Offset[1]) * (1.0f - Layer->ay.CurrentValue) / Height_New; - } if (MaxDiff.x) { - History_Action_Swap(Memory, F_Layers, sizeof(Layer->ax.CurrentValue), &Layer->ax.CurrentValue); - Layer->ax.CurrentValue -= (real32)(State->Interact_Offset[0]) * (Layer->ax.CurrentValue) / Width_New; - } if (MaxDiff.y) { - History_Action_Swap(Memory, F_Layers, sizeof(Layer->ay.CurrentValue), &Layer->ay.CurrentValue); - Layer->ay.CurrentValue -= (real32)(State->Interact_Offset[1]) * (Layer->ay.CurrentValue) / Height_New; - } - /* - if (Min_New.y < Min_Old.y) { - Layer->y.CurrentValue += Min_New.y - Min_Old.y; - } - if (Max_New.x > Max_Old.x) { - Layer->x.CurrentValue += Max_New.x - Max_Old.x; - } - if (Max_New.y > Max_Old.y) { - Layer->y.CurrentValue += Max_New.y - Max_Old.y; - } - */ - Shape->Width = Width_New; - Shape->Height = Height_New; History_Entry_End(Memory); + State->Interact_Active = interact_type_none; + State->Interact_Offset[0] = 0; + State->Interact_Offset[1] = 0; } } draw_list->AddNgon(ScreenPoint_1[a], 4, PointCol, 8, 5.0f); @@ -735,7 +679,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, } shape_layer *Shape = &UI->Shape; - if (State->Tool == tool_pen && State->MostRecentlySelectedLayer == -1) + if ((State->Tool == tool_pen || State->Tool == tool_square) && State->MostRecentlySelectedLayer == -1) ImGui_Viewport_ShapeUI(State, Memory, UI, io, NULL, 0, 0, Shape, MainComp, draw_list); // Interactions for dragging and zooming diff --git a/src/include/main.h b/src/include/main.h index db384ce..7d3299e 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -188,9 +188,10 @@ struct shape_options { int Visibility; v4 FillCol = {1, 1, 1, 1}; v4 StrokeCol = {0, 1, 0, 1}; - float StrokeWidth = 10; + float StrokeWidth = 25; nvg_line_cap LineJoinType = NVG_ROUND; nvg_line_cap LineCapType = NVG_ROUND; + real32 Roundness; }; struct shape_layer { @@ -248,7 +249,8 @@ char *ToolName[] { "Move", "Crop", "Brush", - "Pen" + "Pen", + "Square" }; enum tool { @@ -256,6 +258,7 @@ enum tool { tool_crop, tool_brush, tool_pen, + tool_square, tool_count }; diff --git a/src/include/my_math.h b/src/include/my_math.h index 865f11c..72c6b99 100644 --- a/src/include/my_math.h +++ b/src/include/my_math.h @@ -1,4 +1,5 @@ #define PI 3.141592653589793238 +#define KAPPA 0.5522847493f union v2 { diff --git a/src/layer.cpp b/src/layer.cpp index 7d40310..6159467 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -114,8 +114,6 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor v2 Min = {}, Max = {}; if (State->Interact_Active == interact_type_keyframe_move) { NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max); - Shape->Width = Max.x - Min.x; - Shape->Height = Max.y - Min.y; } uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, Shape->Width, Shape->Height, Width, Height, 1, &Min, &Max); -- cgit v1.2.3