From 1de48570b220acc1ca7063e2a9cda1e89178c0f9 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Fri, 6 Jan 2023 10:26:43 -0500 Subject: bad shape positioning --- src/bezier.cpp | 4 +- src/gl_calls.cpp | 139 +++++++++++++---------------- src/imgui_ui.cpp | 1 - src/imgui_ui_properties.cpp | 21 +++++ src/imgui_ui_viewport.cpp | 211 ++++++++++++++++++++++++++++++++++---------- src/include/debug.h | 2 +- src/include/functions.h | 8 +- src/include/layer.h | 2 +- src/include/main.h | 9 +- src/include/nanovg.h | 29 ++++++ src/layer.cpp | 46 ++++++++-- src/main.cpp | 5 +- src/nanovg.cpp | 188 ++++++++++++++++++++++++++------------- src/prenderer.cpp | 46 +++++++--- 14 files changed, 492 insertions(+), 219 deletions(-) create mode 100644 src/include/nanovg.h diff --git a/src/bezier.cpp b/src/bezier.cpp index 420cae1..6bb1541 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -171,13 +171,13 @@ static void Bezier_CubicCalcPointsCasteljauStep(void *Data, uint32 Size, uint32 } } -uint32 Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size) +void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size) { uint32 Increment = 0; real32 tess_tol = TESS_TOL; void *Pointer = Data; Bezier_CubicCalcPointsCasteljauStep(Pointer, Size, &Increment, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); - return Increment; + return ((uint8 *)Data + (Increment * Size)); } diff --git a/src/gl_calls.cpp b/src/gl_calls.cpp index dbc0784..a1938be 100644 --- a/src/gl_calls.cpp +++ b/src/gl_calls.cpp @@ -20,8 +20,8 @@ const char *DefaultVertexShaderSource = "#version 330 core\n" " vec2 YRotation = vec2(sin(Rad), -cos(Rad));\n" " vec2 XAxis = (Point.x - (Anchor.x * LayerDimensions.x)) * Scale * XRotation;\n" " vec2 YAxis = (Point.y - (Anchor.y * LayerDimensions.y)) * -Scale * YRotation;\n" -" vec2 LocalPoint = Pos + vec2(XAxis + YAxis);\n" -" gl_Position = vec4(vec2(LocalPoint.x / CompDimensions.x, LocalPoint.y / CompDimensions.y) * 2 - 1.0f, 0.0f, 1.0);\n" +" vec2 CompPoint = Pos + vec2(XAxis + YAxis);\n" +" gl_Position = vec4(vec2(CompPoint.x / CompDimensions.x, CompPoint.y / CompDimensions.y) * 2 - 1.0f, 0.0f, 1.0);\n" "}\n" " TexCoord = aTexCoord;\n" "}\0"; @@ -167,8 +167,9 @@ GL_DeleteHWBuffer(gl_effect_layer *Test) static void GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeData, void *FillData, uint32 StrokeCount, uint32 FillCount, - layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 Col, int RenderMode) + layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 StrokeCol, v4 FillCol, int RenderMode) { + int Uniform = 0; glBindTexture(GL_TEXTURE_2D, TestL->Texture); int ByteFlag = (BytesPerPixel == 4) ? GL_RGBA : GL_RGBA16; int ByteFlag2 = (BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; @@ -191,10 +192,6 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa glUseProgram(DefaultShaderProgram); - int Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); - glUniform1i(Uniform, 1); - Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); - glUniform1i(Uniform, 1); Uniform = glGetUniformLocation(DefaultShaderProgram, "CompDimensions"); glUniform3f(Uniform, Width, Height, 0); Uniform = glGetUniformLocation(DefaultShaderProgram, "LayerDimensions"); @@ -209,90 +206,80 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa Uniform = glGetUniformLocation(DefaultShaderProgram, "Scale"); glUniform1f(Uniform, T.scale); -#if 0 - void *PointData = NULL; - int PointCount = 0; - if (RenderMode == 0) { - PointData = FillData; - PointCount = FillCount; - } else { - PointData = StrokeData; - PointCount = StrokeCount; - } - glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * PointCount, PointData, GL_STATIC_DRAW); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); - glEnableVertexAttribArray(1); - - // stencil buffer - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); - - if (RenderMode == 0) { - glDrawArrays(GL_TRIANGLE_FAN, 0, PointCount); - } else { - glDrawArrays(GL_TRIANGLE_STRIP, 0, PointCount); - } - - // stencil buffer - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -#else - glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * FillCount, FillData, GL_STATIC_DRAW); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); - - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); - - glDrawArrays(GL_TRIANGLE_FAN, 0, FillCount); + Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); + glUniform1i(Uniform, 1); + Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); + glUniform1i(Uniform, 1); - glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * StrokeCount, StrokeData, GL_STATIC_DRAW); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); + // fill + // vertices + glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * FillCount, FillData, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); + // stencil buffer + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + glDisable(GL_CULL_FACE); - glDrawArrays(GL_TRIANGLE_STRIP, 0, StrokeCount); + glDrawArrays(GL_TRIANGLE_FAN, 0, FillCount); + // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -#endif - - // default verts glBindVertexArray(0); + Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); glUniform1i(Uniform, 0); Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); glUniform1i(Uniform, 1); Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol"); - glUniform3f(Uniform, Col.r, Col.g, Col.b); - glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, sizeof(GL_DefaultVertices), GL_DefaultVertices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); - glEnableVertexAttribArray(1); - - // stencil buffer - glStencilFunc(GL_NOTEQUAL, 0, 0xFF); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - - glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0); - - // stencil buffer + glUniform3f(Uniform, FillCol.r, FillCol.g, FillCol.b); + + // stencil for fill + // + // vertices + glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sizeof(GL_DefaultVertices), GL_DefaultVertices, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + // stencil buffer + glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0); + // + + // stencil buffer not needed glDisable(GL_STENCIL_TEST); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 0, 0xFF); + glBindVertexArray(0); + + Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); + glUniform1i(Uniform, 1); + Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); + glUniform1i(Uniform, 1); + Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol"); + glUniform3f(Uniform, StrokeCol.r, StrokeCol.g, StrokeCol.b); + + // stroke + // + glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * StrokeCount, StrokeData, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); + glEnableVertexAttribArray(1); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, StrokeCount); + // + glBindFramebuffer(GL_READ_FRAMEBUFFER, TestM->FramebufferObject); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, TestL->FramebufferObject); glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height, diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp index c545e80..50d25a4 100644 --- a/src/imgui_ui.cpp +++ b/src/imgui_ui.cpp @@ -116,7 +116,6 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, ImGui::End(); } - static void ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) { diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp index d89f2f0..6f949c8 100644 --- a/src/imgui_ui_properties.cpp +++ b/src/imgui_ui_properties.cpp @@ -443,6 +443,27 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * } ImGui::EndListBox(); } + char *Names2[3] = { "Butt", "Round", "Square" }; + nvg_line_cap CapVals[3] = { NVG_BUTT, NVG_ROUND, NVG_SQUARE }; + if (ImGui::BeginListBox("Path cap type")) { + for (int i = 0; i < 2; i++) { + if (ImGui::Selectable(Names2[i], (Opt->LineCapType == CapVals[i]))) { + Opt->LineCapType = CapVals[i]; + } + } + ImGui::EndListBox(); + } + char *Names3[3] = { "Miter", "Round", "Bevel" }; + nvg_line_cap JoinVals[3] = { NVG_MITER, NVG_ROUND, NVG_BEVEL }; + if (ImGui::BeginListBox("Path join type")) { + for (int i = 0; i < 2; i++) { + if (ImGui::Selectable(Names3[i], (Opt->LineJoinType == JoinVals[i]))) { + Opt->Visibility = i; + Opt->LineJoinType = JoinVals[i]; + } + } + ImGui::EndListBox(); + } ImGui::ColorEdit4("Fill color", (real32 *)&Opt->FillCol, ImGuiColorEditFlags_Float); ImGui::ColorEdit4("Stroke color", (real32 *)&Opt->StrokeCol, ImGuiColorEditFlags_Float); real32 StrokeWidthMin = 0; diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index 9563d63..fae7bd4 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -32,7 +32,7 @@ ImGui_Viewport_Toolbar(project_state *State, ImDrawList *draw_list) } static void -ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, shape_layer *Shape, block_composition *MainComp, ImDrawList *draw_list) +ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io, block_layer *Layer, int Width, int Height, shape_layer *Shape, block_composition *MainComp, ImDrawList *draw_list) { if (Shape->Point_Count) { uint32 wcol = IM_COL32(00, 00, 80, 255); @@ -48,33 +48,166 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, shape_layer ImVec2 ScreenPoint_0[3]; ImVec2 ScreenPoint_1[3]; + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { + Point_1->IsSelected = false; + } + for (int i = 0; i < 3; i++) { ImVec2 Point = (i == 0) ? ImVec2_(Point_0->Pos[0]) : ImVec2_(Point_0->Pos[0] + Point_0->Pos[i]); + if (Layer != NULL) { + layer_transforms T = Layer_GetTransforms(Layer); + Point = ImVec2_(TransformPoint(T, Width, Height, *(v2 *)&Point)); + } + if (State->Interact_Active == interact_type_keyframe_move && Point_0->IsSelected) { + Point.x += State->Interact_Offset[0]; + Point.y += State->Interact_Offset[1]; + } ImVec2 Point_Ratio = Point / CompDimensions; ScreenPoint_0[i] = UI->CompPos + Point_Ratio * UI->CompZoom; } for (int i = 0; i < 3; i++) { ImVec2 Point = (i == 0) ? ImVec2_(Point_1->Pos[0]) : ImVec2_(Point_1->Pos[0] + Point_1->Pos[i]); + if (Layer != NULL) { + layer_transforms T = Layer_GetTransforms(Layer); + Point = ImVec2_(TransformPoint(T, Width, Height, *(v2 *)&Point)); + } + if (State->Interact_Active == interact_type_keyframe_move && Point_1->IsSelected) { + Point.x += State->Interact_Offset[0]; + Point.y += State->Interact_Offset[1]; + } ImVec2 Point_Ratio = Point / CompDimensions; ScreenPoint_1[i] = UI->CompPos + Point_Ratio * UI->CompZoom; } if (Point_1->Type == interpolation_type_bezier) draw_list->AddLine(ScreenPoint_0[1], ScreenPoint_0[2], wcol, 2.0f); - draw_list->AddNgon(ScreenPoint_0[0], 2, wcol, 8, 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); ImGui::PushID(i); for (int a = 0; a < 3; a++) { ImGui::PushID(a); - ImGui::SetCursorScreenPos(ScreenPoint_1[a]); - if (ImGui::Button("##bezhandle")) { - if (a == 0 && i == 0) { + real32 FontSize = ImGui::GetFontSize(); + ImGui::SetCursorScreenPos(ScreenPoint_1[a] - ImVec2(FontSize / 2, FontSize / 2)); + ImGui::InvisibleButton("##bezhandle", ImVec2(FontSize, FontSize), ImGuiMouseButton_Left); + bool32 IsHovered = ImGui::IsItemHovered(); + bool32 IsItemActive = ImGui::IsItemActive(); + bool32 IsItemActivated = ImGui::IsItemActivated(); + bool32 IsItemDeactivated = ImGui::IsItemDeactivated(); + bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left); + bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right); + if (IsHovered) { + PointCol = ImColor(1.0f, 0.8f, 0.8f, 1.0f); + ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); + } + if (IsItemActivated) { + Point_1->IsSelected = 1; + } + if (IsItemActive) { + if (State->Interact_Active == interact_type_none) { + State->Interact_Offset[2] = io.MousePos.x; + State->Interact_Offset[3] = io.MousePos.y; + State->Interact_Active = interact_type_keyframe_move; + } else { + Assert(State->Interact_Active == interact_type_keyframe_move); + ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]); + if (io.MouseDelta.x || io.MouseDelta.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) { + if (Layer == NULL && a == 0 && i == 0 && Shape->IsClosed == false) { History_Entry_Commit(Memory, "Close shape"); History_Action_Swap(Memory, F_File, sizeof(Shape->IsClosed), &Shape->IsClosed); 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; + 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->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; + } + } + } + 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); } } + draw_list->AddNgon(ScreenPoint_1[a], 4, PointCol, 8, 5.0f); ImGui::PopID(); } ImGui::PopID(); @@ -141,7 +274,7 @@ ImGui_Viewport_BrushUI(project_state *State, memory *Memory, ImVec2 ViewportMin, } static void -ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, ImGuiIO &io, +ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO &io, ImDrawList *draw_list, interact_transform *Interact, ImVec2 ViewportMin, uint32 CompWidth, uint32 CompHeight, uint16 *SortedKeyframeArray) { v2 InteractMin = Interact->Min + Interact->Position; @@ -419,7 +552,7 @@ ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Mem } static void -ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, block_composition *MainComp, uint32 CompIndex, block_layer *ParentLayer[4], uint32 Recursions, +ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io, ImDrawList *draw_list, block_composition *MainComp, uint32 CompIndex, block_layer *ParentLayer[4], uint32 Recursions, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray) { sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex]; @@ -432,7 +565,7 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical); if (Layer->IsPrecomp) { ParentLayer[Recursions] = Layer; - ImGui_Viewport_SelectedLayerUI(State, Memory, UI, draw_list, MainComp, Layer->Block_Source_Index, ParentLayer, Recursions + 1, SortedCompArray, SortedLayerArray); + ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, Layer->Block_Source_Index, ParentLayer, Recursions + 1, SortedCompArray, SortedLayerArray); } if (Layer->IsSelected) { uint32 Width = 0, Height = 0; @@ -443,13 +576,22 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD Width = Comp->Width; Height = Comp->Height; } else if (Layer->IsShapeLayer) { +#if DEBUG block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0]); Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128); int L_Width = 0, L_Height = 0; Assert(Layer->Shape.Contiguous); - NumberOfVerts = NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, &L_Width, &L_Height); - Width = L_Width; - Height = L_Height; + + v2 Min = {}, Max = {}; + layer_transforms T = Layer_GetTransforms(Layer); + if (State->Interact_Active == interact_type_keyframe_move) { + NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max); + } + NumberOfVerts = NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, + State, T, Layer->Shape.Width, Layer->Shape.Height, Width, Height, 1, &Min, &Max); +#endif + Width = Layer->Shape.Width; + Height = Layer->Shape.Height; } else { block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); Width = Source->Width; @@ -463,41 +605,12 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD } if (Layer->IsShapeLayer) { - /* - block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0]); - for (int i = 0; i < Layer->Shape.Point_Count; i++) { - bezier_point Point = Bezier->Point[i]; - v2 Pos = TransformPoint(T, Width, Height, Point.Pos[0]); - v2 CompUV = Pos / V2(MainComp->Width, MainComp->Height); - ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, - UI->CompPos.y + CompUV.y * UI->CompZoom.y); - draw_list->AddNgon(ScreenPoint, 10, IM_COL32(10, 10, 10, 255), 8, 9.0f); - } - for (int i = 1; i < Layer->Shape.Point_Count; i++) { - if (Bezier->Point[i].Type == interpolation_type_bezier) { - v2 L_Pos[4] = { Bezier->Point[i-1].Pos[0], Bezier->Point[i-1].Pos[2], Bezier->Point[i].Pos[1], Bezier->Point[i].Pos[0] }; - L_Pos[1] = L_Pos[1] + L_Pos[0]; - L_Pos[2] = L_Pos[2] + L_Pos[3]; - ImVec2 ScreenPoint[4]; - for (int i = 0; i < 4; i++) { - v2 Pos = TransformPoint(T, Width, Height, L_Pos[i]); - v2 CompUV = Pos / V2(MainComp->Width, MainComp->Height); - ScreenPoint[i] = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, - UI->CompPos.y + CompUV.y * UI->CompZoom.y); - } - draw_list->AddNgon(ScreenPoint[0], 10, IM_COL32(10, 10, 10, 255), 8, 2.0f); - draw_list->AddNgon(ScreenPoint[3], 10, IM_COL32(10, 10, 10, 255), 8, 2.0f); - draw_list->AddBezierCubic(ScreenPoint[0],ScreenPoint[1],ScreenPoint[2],ScreenPoint[3], IM_COL32(10, 10, 10, 255), 1.0f, 0); - } else { - } - } - */ - ImGui_Viewport_ShapeUI(State, Memory, UI, &Layer->Shape, MainComp, draw_list); + ImGui_Viewport_ShapeUI(State, Memory, UI, io, Layer, Width, Height, &Layer->Shape, MainComp, draw_list); + // point visualization +#if DEBUG void *Data2 = Memory_PushScratch(Memory, sizeof(real32) * 3 * 256); - uint32 GL_PointCount = NVG_ExpandStroke(Memory, NumberOfVerts, Layer->Shape.Opt.StrokeWidth, Layer->Shape.IsClosed, (nvg_point *)Data, (real32 *)Data2); - - // test code + uint32 GL_PointCount = NVG_ExpandStroke(Memory, NumberOfVerts, Layer->Shape.Opt.StrokeWidth, Layer->Shape.Opt.LineCapType, Layer->Shape.Opt.LineJoinType, Layer->Shape.IsClosed, (nvg_point *)Data, (real32 *)Data2); for (int i = 0; i < NumberOfVerts; i++) { nvg_point Point = *((nvg_point *)Data + i); @@ -516,8 +629,10 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD UI->CompPos.y + CompUV.y * UI->CompZoom.y); draw_list->AddNgon(ScreenPoint, 2, IM_COL32(80, 80, 10, 255), 8, 2.0f); } + Memory_PopScratch(Memory, sizeof(real32) * 3 * 256); Memory_PopScratch(Memory, sizeof(nvg_point) * 128); +#endif } v2 BoundingPoint[5] = { V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue), V2(0, 0), V2(Width, 0), V2(0, Height), V2(Width, Height) }; @@ -613,15 +728,15 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, if (State->MostRecentlySelectedLayer > -1) { block_layer *ParentLayer[4]; - ImGui_Viewport_SelectedLayerUI(State, Memory, UI, draw_list, MainComp, File->PrincipalCompIndex, ParentLayer, 0, SortedCompArray, SortedLayerArray); + ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, File->PrincipalCompIndex, ParentLayer, 0, SortedCompArray, SortedLayerArray); if (State->Interact_Active == interact_type_viewport_transform) { - ImGui_Viewport_TransformUI(File, State, Memory, UI, draw_list, io, (interact_transform *)&State->Interact_Offset[0], ViewportMin, MainComp->Width, MainComp->Height, SortedKeyframeArray); + ImGui_Viewport_TransformUI(File, State, Memory, UI, io, draw_list, (interact_transform *)&State->Interact_Offset[0], ViewportMin, MainComp->Width, MainComp->Height, SortedKeyframeArray); } } shape_layer *Shape = &UI->Shape; - if (State->Tool == tool_pen && State->Interact_Active == interact_type_none && State->MostRecentlySelectedLayer == -1) - ImGui_Viewport_ShapeUI(State, Memory, UI, Shape, MainComp, draw_list); + if (State->Tool == tool_pen && State->MostRecentlySelectedLayer == -1) + ImGui_Viewport_ShapeUI(State, Memory, UI, io, NULL, 0, 0, Shape, MainComp, draw_list); // Interactions for dragging and zooming ImGui::SetCursorScreenPos(ViewportMin); diff --git a/src/include/debug.h b/src/include/debug.h index e1d8ccc..3ddbdc8 100644 --- a/src/include/debug.h +++ b/src/include/debug.h @@ -27,7 +27,7 @@ struct debug_temp struct project_debug { debug_temp Temp; - bool32 ToggleWindow = 1; + bool32 ToggleWindow = 0; bool32 ReloadUI = true; bool32 NoThreading = 0; bool32 DisableAlpha = 0; diff --git a/src/include/functions.h b/src/include/functions.h index e7b5e44..32737ea 100644 --- a/src/include/functions.h +++ b/src/include/functions.h @@ -18,11 +18,15 @@ static void Bezier_Interact_Evaluate(project_state *State, bezier_poin 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); -uint32 Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size); +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 void GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeData, void *FillData, uint32 StrokeCount, uint32 FillCount, - layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 Col, int RenderMode); + layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 FillCol, v4 StrokeCol, int RenderMode); 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); diff --git a/src/include/layer.h b/src/include/layer.h index 85d980d..bf32aca 100644 --- a/src/include/layer.h +++ b/src/include/layer.h @@ -12,7 +12,7 @@ Layer_GetTopOffset(project_data *File, memory *Memory); static void Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memory, void *EffectBitmapAddress, - int Width, int Height, int BytesPerPixel); + int Width, int Height, int BytesPerPixel, int CompWidth, int CompHeight); static void Layer_ToggleChannel(project_data *File, memory *Memory, int32 a); diff --git a/src/include/main.h b/src/include/main.h index a39fe45..db384ce 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -183,11 +183,14 @@ struct sorted_file uint64 Source_SortSize; }; + struct shape_options { int Visibility; v4 FillCol = {1, 1, 1, 1}; - v4 StrokeCol = {1, 1, 1, 1}; - float StrokeWidth = 50; + v4 StrokeCol = {0, 1, 0, 1}; + float StrokeWidth = 10; + nvg_line_cap LineJoinType = NVG_ROUND; + nvg_line_cap LineCapType = NVG_ROUND; }; struct shape_layer { @@ -196,6 +199,8 @@ struct shape_layer { uint16 Point_Count; bool32 IsClosed; bool32 Contiguous = 1; // No points have been deleted/added, so sorting isn't needed. + // NOTE(fox): This is kinda lazily done atm, there may be situations where + // this isn't the correct value. int Width; int Height; shape_options Opt; diff --git a/src/include/nanovg.h b/src/include/nanovg.h new file mode 100644 index 0000000..c6df6b4 --- /dev/null +++ b/src/include/nanovg.h @@ -0,0 +1,29 @@ + +enum nvg_line_cap { + NVG_BUTT, + NVG_ROUND, // join and line type + NVG_SQUARE, + NVG_BEVEL, // join type + NVG_MITER, // join type +}; + +enum nvg_point_flags +{ + NVG_PT_CORNER = 0x01, + NVG_PT_LEFT = 0x02, + NVG_PT_BEVEL = 0x04, + NVG_PR_INNERBEVEL = 0x08, +}; + +struct nvg_point +{ + real32 x; + real32 y; + real32 dx; + real32 dy; + real32 Length; + real32 dmx; + real32 dmy; + uint8 Flags; +}; + diff --git a/src/layer.cpp b/src/layer.cpp index 93db19d..7d40310 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -94,7 +94,7 @@ Layer_GetTopOffset(project_data *File, memory *Memory) static void Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memory, void *EffectBitmapAddress, - int Width, int Height, int BytesPerPixel, int *L_Width, int *L_Height) + int Width, int Height, int BytesPerPixel) { uint64 Size = Width*Height*BytesPerPixel; @@ -109,15 +109,24 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor if (Layer->IsShapeLayer) { shape_layer *Shape = &Layer->Shape; void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128); - uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, L_Width, L_Height); + Arbitrary_Zero((uint8 *)Data, sizeof(nvg_point) * 128); + layer_transforms T = Layer_GetTransforms(Layer); + 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); void *Data_Stroke = Memory_PushScratch(Memory, sizeof(real32) * 4 * 256); - uint32 StrokeCount = NVG_ExpandStroke(Memory, NumberOfVerts, Shape->Opt.StrokeWidth, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke); + uint32 StrokeCount = NVG_ExpandStroke(Memory, NumberOfVerts, Shape->Opt.StrokeWidth, Shape->Opt.LineCapType, Shape->Opt.LineJoinType, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke); void *Data_Fill = Memory_PushScratch(Memory, sizeof(real32) * 4 * NumberOfVerts); NVG_ExpandFill(Memory, NumberOfVerts, (nvg_point *)Data, (real32 *)Data_Fill); - layer_transforms T = Layer_GetTransforms(Layer); GL_RasterizeShape(&TestL, &TestM, Data_Stroke, Data_Fill, StrokeCount, NumberOfVerts, T, - Width, Height, BytesPerPixel, EffectBitmapAddress, *L_Width, *L_Height, Layer->Shape.Opt.StrokeCol, Shape->Opt.Visibility); + Width, Height, BytesPerPixel, EffectBitmapAddress, Shape->Width, Shape->Height, + Shape->Opt.StrokeCol, Shape->Opt.FillCol, Shape->Opt.Visibility); Memory_PopScratch(Memory, sizeof(real32) * 4 * NumberOfVerts); Memory_PopScratch(Memory, sizeof(real32) * 4 * 256); @@ -309,6 +318,23 @@ Layer_Select_Traverse(uint16 PrincipalCompIndex, memory *Memory, project_state * } } +static void +Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height) +{ + if (Layer->IsPrecomp) { + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index); + *Width = Comp->Width; + *Height = Comp->Height; + } else if (Layer->IsShapeLayer) { + *Width = Layer->Shape.Width; + *Height = Layer->Shape.Height; + } else { + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + *Width = Source->Width; + *Height = Source->Height; + } +} + static v2 Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray) { @@ -352,9 +378,10 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar 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); - block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + int Width, Height; + Layer_GetDimensions(Memory, Layer, &Width, &Height); layer_transforms T = Layer_GetTransforms(Layer); - v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->LastClickedPoint); + 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) { SelectionCount++; @@ -366,9 +393,10 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar 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); - block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + int Width, Height; + Layer_GetDimensions(Memory, Layer, &Width, &Height); layer_transforms T = Layer_GetTransforms(Layer); - v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->LastClickedPoint); + 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) { if (SelectionCount == 1) { diff --git a/src/main.cpp b/src/main.cpp index 27a985e..e9cbf32 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,6 +54,7 @@ extern "C" { #include "stable_diffusion.h" #endif #include "memory.h" +#include "nanovg.h" #include "main.h" #include "ffmpeg_backend.h" @@ -441,7 +442,9 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_fil } if (Layer->IsShapeLayer) { - Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Comp->Width, Comp->Height, Comp->BytesPerPixel, &Width, &Height); + Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Comp->Width, Comp->Height, Comp->BytesPerPixel); + Width = Layer->Shape.Width; + Height = Layer->Shape.Height; rectangle RenderRegion = { 0, 0, Comp->Width, Comp->Height }; direct_info Info = { (real32)Comp->Width, (real32)Comp->Height, (real32)Comp->BytesPerPixel, (real32)Comp->Width * Comp->BytesPerPixel, Bitmap_ByteInfo(Comp->BytesPerPixel), UI->Color.a, blend_normal, diff --git a/src/nanovg.cpp b/src/nanovg.cpp index 5627b5f..1fb59ee 100644 --- a/src/nanovg.cpp +++ b/src/nanovg.cpp @@ -1,23 +1,23 @@ -enum nvg_point_flags -{ - NVG_PT_CORNER = 0x01, - NVG_PT_LEFT = 0x02, - NVG_PT_BEVEL = 0x04, - NVG_PR_INNERBEVEL = 0x08, -}; +// nanovg code adapted by me for my data structures, I'm primarily using the +// functions related to shape/path triangulation. -struct nvg_point -{ - real32 x; - real32 y; - real32 dx; - real32 dy; - real32 Length; - real32 dmx; - real32 dmy; - uint8 Flags; -}; +// Copyright (c) 2013 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// static real32 NVG_Normalize(real32 *x, float* y) @@ -87,7 +87,30 @@ static real32 * NVG_RoundJoin(nvg_point *Point, nvg_point *NextPoint, real32 *St StrokeData = NVG_Point(StrokeData, lx1, ly1, 0, 0); StrokeData = NVG_Point(StrokeData, NextPoint->x - dlx1*rw, NextPoint->y - dly1*rw, 0, 0); - } + } else { + float rx0,ry0,rx1,ry1,a0,a1; + NVG_ChooseBevel(NextPoint->Flags & NVG_PR_INNERBEVEL, Point, NextPoint, -rw, &rx0,&ry0, &rx1,&ry1); + a0 = atan2f(dly0, dlx0); + a1 = atan2f(dly1, dlx1); + if (a1 < a0) a1 += PI*2; + + StrokeData = NVG_Point(StrokeData, NextPoint->x + dlx0*rw, NextPoint->y + dly0*rw, 0, 0); + StrokeData = NVG_Point(StrokeData, rx0, ry0, 0, 0); + + n = NVG_Clampi((int)ceilf(((a1 - a0) / PI) * ncap), 2, ncap); + for (i = 0; i < n; i++) { + float u = i/(float)(n-1); + float a = a0 + u*(a1-a0); + float lx = NextPoint->x + cosf(a) * lw; + float ly = NextPoint->y + sinf(a) * lw; + StrokeData = NVG_Point(StrokeData, lx, ly, 0, 0); + StrokeData = NVG_Point(StrokeData, NextPoint->x, NextPoint->y, 0, 0); + } + + StrokeData = NVG_Point(StrokeData, NextPoint->x + dlx1*rw, NextPoint->y + dly1*rw, 0, 0); + StrokeData = NVG_Point(StrokeData, rx1, ry1, 0, 0); + } + return StrokeData; } @@ -125,71 +148,100 @@ static real32 * NVG_RoundCap(nvg_point * Point, real32 *StrokeData, return StrokeData; } +static real32 * NVG_ButtCap(nvg_point *Point, real32 *StrokeData, + float dx, float dy, float w, float d, + float u0, float u1, int Mode) +{ + float px = (Mode == 0) ? Point->x - dx*d : Point->x + dx*d; + float py = (Mode == 0) ? Point->y - dy*d : Point->y + dy*d; + float dlx = dy; + float dly = -dx; + if (Mode == 0) { + StrokeData = NVG_Point(StrokeData, px + dlx*w - dx, py + dly*w - dy, 0, 0); + StrokeData = NVG_Point(StrokeData, px - dlx*w - dx, py - dly*w - dy, 0, 0); + StrokeData = NVG_Point(StrokeData, px + dlx*w, py + dly*w, 0, 0); + StrokeData = NVG_Point(StrokeData, px - dlx*w, py - dly*w, 0, 0); + } else { + StrokeData = NVG_Point(StrokeData, px + dlx*w, py + dly*w, 0, 0); + StrokeData = NVG_Point(StrokeData, px - dlx*w, py - dly*w, 0, 0); + StrokeData = NVG_Point(StrokeData, px + dlx*w + dx, py + dly*w + dy, 0, 0); + StrokeData = NVG_Point(StrokeData, px - dlx*w + dx, py - dly*w + dy, 0, 0); + } + return StrokeData; +} + // NOTE(fox): We only have to care about winding if we want to do HW accelerated // shape subtraction with the stencil buffer (I think). +// All the extra inputs on the second line are for when we need to take +// interactive mode into account. Since undoing a transform requires knowledge +// of the shape's size (does it?), the code needs to be ran twice, controlled +// with the Interact bool. static uint32 -NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData, int *Width, int *Height) +NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData, + project_state *State, layer_transforms T, int Width, int Height, + int CompWidth, int CompHeight, bool32 Interact, v2 *Min, v2 *Max) { - uint32 NumberOfVerts = 0; nvg_point *PointPlayhead = PointData; for (int i = 0; i < Shape->Point_Count; i++) { bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); -#if 0 if (i == 0 || Point->Type == interpolation_type_linear) { - *(v2 *)PointPlayhead = Point->Pos[0]; - if (i != 0 && i != (Shape->Point_Count - 1)) { + v2 Pos = Point->Pos[0]; + if (State->Interact_Active == interact_type_keyframe_move && Point->IsSelected && Interact != 0) { + Pos = TransformPoint(T, Width, Height, Pos); + Pos.x += State->Interact_Offset[0]; + Pos.y += State->Interact_Offset[1]; + Pos = T_CompPosToLayerPos(T, CompWidth, CompHeight, Width, Height, Pos.x, Pos.y); + } + *(v2 *)PointPlayhead = Pos; + if (Shape->IsClosed || (i != 0 && i != (Shape->Point_Count - 1))) { PointPlayhead->Flags |= NVG_PT_CORNER; } PointPlayhead++; - NumberOfVerts++; } else if (Point->Type == interpolation_type_bezier) { bezier_point *Point_1 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i-1, 1); - v2 Pos[4] = { Point->Pos[0], Point->Pos[1], Point_1->Pos[2], Point_1->Pos[0] }; - Pos[1] = Pos[1] + Pos[0]; - Pos[2] = Pos[2] + Pos[3]; - NumberOfVerts += Bezier_CubicCalcPoints(Pos[3], Pos[2], Pos[1], Pos[0], PointPlayhead, sizeof(nvg_point)); + v2 Pos[2] = { Point_1->Pos[0], Point->Pos[0] }; + if (State->Interact_Active == interact_type_keyframe_move && Point->IsSelected && Width != 0) { + for (int i = 0; i < 2; i++) { + Pos[i] = TransformPoint(T, Width, Height, Pos[i]); + Pos[i].x += State->Interact_Offset[0]; + Pos[i].y += State->Interact_Offset[1]; + Pos[i] = T_CompPosToLayerPos(T, CompWidth, CompHeight, Width, Height, Pos[i].x, Pos[i].y); + } + } + PointPlayhead = (nvg_point *)Bezier_CubicCalcPoints(Pos[0], Pos[0] + Point_1->Pos[1], Pos[1] + Point->Pos[2], Pos[1], PointPlayhead, sizeof(nvg_point)); // The point at the end is also returned, so we remove it. - NumberOfVerts--; - PointPlayhead--; + if (i != (Shape->Point_Count - 1)) + PointPlayhead--; } else { Assert(0); } -#else - *(v2 *)PointPlayhead = Point->Pos[0]; - if (i != 0 && i != (Shape->Point_Count - 1)) { - PointPlayhead->Flags |= NVG_PT_CORNER; - } - PointPlayhead++; - NumberOfVerts++; -#endif } + int NumberOfVerts = PointPlayhead - PointData; nvg_point *Point = &PointData[NumberOfVerts - 1]; nvg_point *NextPoint = PointData; - v2 Min = V2(10000, 10000); - v2 Max = V2(-10000, -10000); + *Min = V2(10000, 10000); + *Max = V2(-10000, -10000); for (int i = 0; i < NumberOfVerts; i++) { Point->dx = NextPoint->x - Point->x; Point->dy = NextPoint->y - Point->y; Point->Length = NVG_Normalize(&Point->dx, &Point->dy); - if (Point->x > Max.x) - Max.x = Point->x; - if (Point->x < Min.x) - Min.x = Point->x; - if (Point->y > Max.y) - Max.y = Point->y; - if (Point->y < Min.y) - Min.y = Point->y; + if (Point->x > Max->x) + Max->x = Point->x; + if (Point->x < Min->x) + Min->x = Point->x; + if (Point->y > Max->y) + Max->y = Point->y; + if (Point->y < Min->y) + Min->y = Point->y; Point = NextPoint++; } - *Width = Max.x - Min.x; - *Height = Max.y - Min.y; return NumberOfVerts; } real32 MiterLimit = 2.4f; static uint32 -NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsClosed, nvg_point *PointData, real32 *StrokeData) +NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, nvg_line_cap LineCap, nvg_line_cap LineJoin, bool32 IsClosed, nvg_point *PointData, real32 *StrokeData) { real32 Width = StartWidth * 0.5; int ncap = 12; @@ -205,7 +257,11 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl NextPoint = &PointData[1]; Start = 1; LoopAmount = NumberOfVerts - 1; - StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0); + if (LineCap == NVG_ROUND) { + StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0); + } else { + StrokeData = NVG_ButtCap(Point, StrokeData, Point->dx, Point->dy, Width, Width-1, 0.5, 0.5, 0); + } } for (int i = Start; i < LoopAmount; i++) { @@ -229,6 +285,9 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl NextPoint->dmy *= scale; } + // Clear flags, but keep the corner. + NextPoint->Flags = (NextPoint->Flags & NVG_PT_CORNER) ? NVG_PT_CORNER : 0; + // Keep track of left turns. cross = NextPoint->dx * Point->dy - Point->dx * NextPoint->dy; if (cross > 0.0f) { @@ -236,21 +295,22 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl } // Calculate if we should use bevel or miter for inner join. - // limit = nvg__maxf(1.01f, nvg__minf(p0->len, p1->len) * iw); - // if ((dmr2 * limit*limit) < 1.0f) - // p1->flags |= NVG_PR_INNERBEVEL; + float iw = (Width > 0.0f) ? 1.0f / Width : 0.0f; + limit = Max(1.01f, Min(Point->Length, NextPoint->Length) * iw); + if ((dmr2 * limit*limit) < 1.0f) + NextPoint->Flags |= NVG_PR_INNERBEVEL; // Check to see if the corner needs to be beveled. if (NextPoint->Flags & NVG_PT_CORNER) { - // if ((dmr2 * MiterLimit*MiterLimit) < 1.0f) r // || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) { - // NextPoint->Flags |= NVG_PT_BEVEL; - // } + if (((dmr2 * MiterLimit*MiterLimit) < 1.0f) || LineJoin == NVG_BEVEL || LineJoin == NVG_ROUND) { + NextPoint->Flags |= NVG_PT_BEVEL; + } } if ((NextPoint->Flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) { - // if (lineJoin == NVG_ROUND) { + if (LineJoin == NVG_ROUND) { StrokeData = NVG_RoundJoin(Point, NextPoint, StrokeData, Width, Width, 0.5, 0.5, ncap); - // } + } } else { StrokeData = NVG_Point(StrokeData, NextPoint->x + (NextPoint->dmx * Width), NextPoint->y + (NextPoint->dmy * Width), 0, 0); StrokeData = NVG_Point(StrokeData, NextPoint->x - (NextPoint->dmx * Width), NextPoint->y - (NextPoint->dmy * Width), 0, 0); @@ -260,7 +320,11 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl } if (!IsClosed) { - StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 1); + if (LineCap == NVG_ROUND) { + StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 1); + } else { + StrokeData = NVG_ButtCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, Width-1, 0.5, 0.5, 1); + } } else { StrokeData = NVG_Point(StrokeData, StartingStrokeData[0], StartingStrokeData[1], 0, 0); StrokeData = NVG_Point(StrokeData, StartingStrokeData[4], StartingStrokeData[5], 0, 0); diff --git a/src/prenderer.cpp b/src/prenderer.cpp index 54b19cf..fc6edd4 100644 --- a/src/prenderer.cpp +++ b/src/prenderer.cpp @@ -1,3 +1,23 @@ +static v2 +T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y) +{ + real32 Rad = (T.rotation* (PI / 180)); + v2 XAxis = (SourceWidth * T.scale)*V2(cos(Rad), sin(Rad)); + v2 YAxis = (SourceHeight * -T.scale)*V2(sin(Rad), -cos(Rad)); + + v2 Pos = {T.x, T.y}; + v2 Origin = Pos - (XAxis * T.ax) - (YAxis * T.ay); + + v2 XAxisPerp = (1.0f / LengthSq(XAxis))*XAxis; + v2 YAxisPerp = (1.0f / LengthSq(YAxis))*YAxis; + + real32 StartVectorX = X - Origin.x; + real32 StartVectorY = Y - Origin.y; + real32 LayerU = (StartVectorX * XAxisPerp.x) + (StartVectorY * XAxisPerp.y); + real32 LayerV = (StartVectorX * YAxisPerp.x) + (StartVectorY * YAxisPerp.y); + return V2(LayerU * SourceWidth, LayerV * SourceHeight); +} + static v2 T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV) { @@ -37,20 +57,6 @@ Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHe return V2(LayerUV.x * SourceWidth, LayerUV.y * SourceHeight); } -static void -Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height) -{ - if (!Layer->IsPrecomp) { - block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); - *Width = Source->Width; - *Height = Source->Height; - } else { - block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index); - *Width = Comp->Width; - *Height = Comp->Height; - } -} - // Transform given data based on state's Interact data. static void Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale) @@ -220,6 +226,7 @@ Interact_Transform_Begin(project_data *File, memory *Memory, project_state *Stat */ } + static v2 TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point) { @@ -230,6 +237,17 @@ TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point) return V2(T.x + LocalPoint.x, T.y + LocalPoint.y); } +static layer_transforms +Transform_Inverse(layer_transforms T) +{ + T.x = -T.x; + T.y = -T.y; + T.ax = -T.ax; + T.ay = -T.ay; + T.rotation = T.rotation; + T.scale = 1.0f; + return T; +} static ImVec2 Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point) -- cgit v1.2.3