From eebbdd012b0d156e9e92369585c6ad82ed3de371 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Wed, 4 Jan 2023 18:30:56 -0500 Subject: shapes; remove stencil buffer? --- src/bezier.cpp | 39 ++++++++++ src/createcalls.cpp | 39 ++++++---- src/gl_calls.cpp | 60 +++++++++++++-- src/imgui_ui.cpp | 22 +----- src/imgui_ui_properties.cpp | 21 +++++- src/imgui_ui_timeline.cpp | 2 +- src/imgui_ui_viewport.cpp | 173 +++++++++++++++++++++++++++++++++----------- src/include/debug.h | 2 +- src/include/defines.h | 3 +- src/include/functions.h | 6 +- src/include/main.h | 9 ++- src/include/my_math.h | 10 +-- src/layer.cpp | 20 +++-- src/main.cpp | 19 ++--- src/nanovg.cpp | 65 +++++++++++++---- 15 files changed, 350 insertions(+), 140 deletions(-) diff --git a/src/bezier.cpp b/src/bezier.cpp index ac89ed3..420cae1 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -34,6 +34,19 @@ Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 Tar return Y; } +static bezier_point * +Bezier_LookupAddress(memory *Memory, uint16 *Block_Bezier_Index, uint16 Index, bool32 AssertExists) +{ + Assert(Index < (MAX_KEYFRAMES_PER_BLOCK * MAX_KEYFRAME_BLOCKS)); + int SeekBlock = Index / MAX_KEYFRAMES_PER_BLOCK; + int SeekIndex = Index - (SeekBlock * MAX_KEYFRAMES_PER_BLOCK); + block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Block_Bezier_Index[SeekBlock], 0); + Assert(Bezier->Occupied); + if (AssertExists) + Assert(Bezier->Point[SeekIndex].Occupied); + return &Bezier->Point[SeekIndex]; +} + static bezier_point * Bezier_LookupAddress(memory *Memory, property_channel *Property, uint16 Index, bool32 AssertExists) { @@ -64,6 +77,32 @@ Bezier_Interact_Evaluate(project_state *State, bezier_point *PointAddress, v2 *P } } +static void +Bezier_Add(memory *Memory, memory_table_list TableName, uint16 *Block_Bezier_Index, uint16 *Block_Bezier_Count, + uint16 *PointCount, bezier_point PointData) +{ + int k = 0; + for (;;) { + int SeekBlock = k / MAX_KEYFRAMES_PER_BLOCK; + if ((SeekBlock + 1) > *Block_Bezier_Count) { + Block_Bezier_Index[SeekBlock] = Memory_Block_AllocateNew(Memory, F_Bezier); + block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Block_Bezier_Index[SeekBlock], 0); + Bezier->Occupied = true; + History_Action_Swap(Memory, TableName, sizeof(*Block_Bezier_Count), Block_Bezier_Count); + *Block_Bezier_Count += 1; + } + bezier_point *Point = Bezier_LookupAddress(Memory, Block_Bezier_Index, k, 0); + if (!Point->Occupied) { + History_Action_Swap(Memory, F_Bezier, sizeof(*Point), Point); + *Point = PointData; + History_Action_Swap(Memory, TableName, sizeof(*PointCount), PointCount); + *PointCount += 1; + return; + } + k++; + } +} + static void Bezier_Add(memory *Memory, memory_table_list TableName, property_channel *Property, bezier_point PointData, uint16 *ArrayLocation) { diff --git a/src/createcalls.cpp b/src/createcalls.cpp index 4bdd6d7..cd8f3d5 100644 --- a/src/createcalls.cpp +++ b/src/createcalls.cpp @@ -610,7 +610,7 @@ Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *Arr } static void -Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory, v2 Point, v2 Vector) +Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory) { int TopOffset = Layer_GetTopOffset(File, Memory); block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); @@ -618,8 +618,6 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory, History_Entry_Commit(Memory, "New shape layer"); block_layer *Layer = Layer_Init(File, Memory); Layer->IsShapeLayer = true; - Layer->x.CurrentValue = MainComp->Width / 2; - Layer->y.CurrentValue = MainComp->Height / 2; if (File->Layer_Count == 1) { Layer->Vertical_Offset = 11 - 1; } else { @@ -629,17 +627,32 @@ 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)); - Layer->Shape.Block_Bezier_Index[0] = Memory_Block_AllocateNew(Memory, F_Bezier); - block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0], 0); - Bezier->Occupied = true; - v2 BezierPoint[3] = { Point, V2(000, 000), V2(000, 000) }; - interpolation_type Type = interpolation_type_linear; - if (Vector.x) { - BezierPoint[1] = Vector; - BezierPoint[2] = Vector * -1; - Type = interpolation_type_bezier; + v2 Min = V2(10000, 10000); + v2 Max = V2(-10000, -10000); + shape_layer *Shape = &File->UI.Shape; + for (int i = 0; i < Shape->Point_Count; i++) { + bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); + if (Point->Pos[0].x > Max.x) + Max.x = Point->Pos[0].x; + if (Point->Pos[0].x < Min.x) + Min.x = Point->Pos[0].x; + if (Point->Pos[0].y > Max.y) + Max.y = Point->Pos[0].y; + if (Point->Pos[0].y < Min.y) + Min.y = Point->Pos[0].y; } - Bezier->Point[0] = { 1, { BezierPoint[0], BezierPoint[1], BezierPoint[2] }, Type, 0 }; + 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; + } + + History_Action_Swap(Memory, F_Layers, sizeof(Layer->Shape), &Layer->Shape); + Layer->Shape = File->UI.Shape; + History_Action_Swap(Memory, F_File, sizeof(File->UI.Shape), &File->UI.Shape); + File->UI.Shape = {}; History_Entry_End(Memory); State->UpdateFrame = true; diff --git a/src/gl_calls.cpp b/src/gl_calls.cpp index 5007148..dbc0784 100644 --- a/src/gl_calls.cpp +++ b/src/gl_calls.cpp @@ -30,13 +30,14 @@ const char *DefaultFragmentShaderSource = "#version 330 core\n" "in vec2 TexCoord;\n" "uniform sampler2D Texture;\n" "uniform int FragmentMode;\n" +"uniform vec3 InputCol;\n" "void main()\n" "{\n" "vec4 Col = texture(Texture, TexCoord);\n" " if (FragmentMode == 0) {\n" " FragColor = Col;\n" "} else {\n" -" FragColor = vec4(vec3(1.0f), Col.a);\n" +" FragColor = vec4(InputCol, Col.a);\n" "}\n" "}\0"; @@ -164,9 +165,9 @@ GL_DeleteHWBuffer(gl_effect_layer *Test) Test->Initialized = true; } -void -GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *PointData, uint32 GL_PointCount, - layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height) +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) { glBindTexture(GL_TEXTURE_2D, TestL->Texture); int ByteFlag = (BytesPerPixel == 4) ? GL_RGBA : GL_RGBA16; @@ -208,8 +209,18 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *PointDat 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 * GL_PointCount, PointData, GL_STATIC_DRAW); + 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))); @@ -220,15 +231,50 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *PointDat glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); glDisable(GL_CULL_FACE); - glDrawArrays(GL_TRIANGLE_STRIP, 0, GL_PointCount); + 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); + + 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))); + + 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); + + 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); @@ -256,8 +302,6 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *PointDat glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, EffectBitmapAddress); glBindFramebuffer(GL_FRAMEBUFFER, 0); - // GL_DeleteHWBuffer(TestL); - // GL_DeleteHWBuffer(TestM); } void diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp index 1feb1e5..c545e80 100644 --- a/src/imgui_ui.cpp +++ b/src/imgui_ui.cpp @@ -117,26 +117,6 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, } -static void -ImGui_Opt_Shape(shape_options *Opt) -{ - // TODO(fox): Combine with RGBA function? - char *Names[3] = { "Fill only", "Stroke only", "Fill and stroke" }; - if (ImGui::BeginListBox("Shape render type")) { - for (int i = 0; i < 3; i++) { - if (ImGui::Selectable(Names[i], (Opt->Visibility == i))) { - Opt->Visibility = i; - } - } - ImGui::EndListBox(); - } - ImGui::ColorEdit4("Fill color", (real32 *)&Opt->FillCol, ImGuiColorEditFlags_Float); - ImGui::ColorEdit4("Stroke color", (real32 *)&Opt->StrokeCol, ImGuiColorEditFlags_Float); - real32 StrokeWidthMin = 0; - real32 StrokeWidthMax = 1024; - ImGui::DragScalar("Stroke width", ImGuiDataType_Float, &Opt->StrokeWidth, 1, &StrokeWidthMin, &StrokeWidthMax, "%.3f"); -} - static void ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) { @@ -196,7 +176,7 @@ ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memor State_BindBrushTexture(Memory, &State->Brush, 4); } } else if (State->Tool == tool_pen && State->MostRecentlySelectedLayer == -1) { - ImGui_Opt_Shape(&State->Pen.Opt); + // ImGui_Opt_Shape(&State->Pen.Opt); } ImGui::End(); diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp index c6b710c..d89f2f0 100644 --- a/src/imgui_ui_properties.cpp +++ b/src/imgui_ui_properties.cpp @@ -390,7 +390,7 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * ImGui_Properties_CurvesUI(State, Memory, io, Effect, Property, SortedPointStart); c = EffectHeader->Property_Count; // Causes this loop to only iterate once. } else if (EffectHeader->DisplayType == effect_display_type_levels) { - ImGui::Text("Levels!"); + ImGui::Text("Levels"); uint32 VisibleChannel = *(uint32 *)&Effect->ExtraData[0]; real32 *P_Left = 0, *P_Mid = 0, *P_Right = 0; if (VisibleChannel == 0) { @@ -431,6 +431,25 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * State->UpdateFrame = true; } } + if (Layer->IsShapeLayer) { + shape_options *Opt = &Layer->Shape.Opt; + // TODO(fox): Combine with RGBA function? + char *Names[3] = { "Fill only", "Stroke only", "Fill and stroke" }; + if (ImGui::BeginListBox("Shape render type")) { + for (int i = 0; i < 3; i++) { + if (ImGui::Selectable(Names[i], (Opt->Visibility == i))) { + Opt->Visibility = i; + } + } + ImGui::EndListBox(); + } + ImGui::ColorEdit4("Fill color", (real32 *)&Opt->FillCol, ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("Stroke color", (real32 *)&Opt->StrokeCol, ImGuiColorEditFlags_Float); + real32 StrokeWidthMin = 0; + real32 StrokeWidthMax = 1024; + ImGui::DragScalar("Stroke width", ImGuiDataType_Float, &Opt->StrokeWidth, 1, &StrokeWidthMin, &StrokeWidthMax, "%.3f"); + // State->UpdateFrame = true; + } ImGui::End(); } else { ImGui::Begin("Properties: empty###Properties"); diff --git a/src/imgui_ui_timeline.cpp b/src/imgui_ui_timeline.cpp index 92a08f6..3a5eca0 100644 --- a/src/imgui_ui_timeline.cpp +++ b/src/imgui_ui_timeline.cpp @@ -322,7 +322,7 @@ ImGui_Timeline_DrawGraph(project_data *File, project_state *State, memory *Memor Bezier_Interact_Evaluate(State, PointAddress[Idx], PointPos, GraphZoomHeight, Y_Increment); PointPos[0].x += Frame_Offset; - ImVec2 Keyframe_LocalPos[3] = { V2(PointPos[0]), V2(PointPos[0] + PointPos[1]), V2(PointPos[0] + PointPos[2]) }; + ImVec2 Keyframe_LocalPos[3] = { ImVec2_(PointPos[0]), ImVec2_(PointPos[0] + PointPos[1]), ImVec2_(PointPos[0] + PointPos[2]) }; ImVec2 Keyframe_LocalPos_Ratio[3]; for (int b = 0; b < 3; b++) { diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index e21c1a6..9563d63 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -31,6 +31,66 @@ ImGui_Viewport_Toolbar(project_state *State, ImDrawList *draw_list) ImGui::PopStyleVar(2); } +static void +ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, shape_layer *Shape, block_composition *MainComp, ImDrawList *draw_list) +{ + if (Shape->Point_Count) { + uint32 wcol = IM_COL32(00, 00, 80, 255); + v2 CompUV = State->LastClickedPoint; + ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, + UI->CompPos.y + CompUV.y * UI->CompZoom.y); + bezier_point *Point_0 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Shape->Point_Count - 1, 1); + bezier_point *Point_1 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, 0, 1); + Assert(Shape->Contiguous); + int i = 0; + while (i < Shape->Point_Count) { + ImVec2 CompDimensions = ImVec2(MainComp->Width, MainComp->Height); + ImVec2 ScreenPoint_0[3]; + ImVec2 ScreenPoint_1[3]; + + 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]); + 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]); + 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); + + 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) { + History_Entry_Commit(Memory, "Close shape"); + History_Action_Swap(Memory, F_File, sizeof(Shape->IsClosed), &Shape->IsClosed); + Shape->IsClosed = true; + History_Entry_End(Memory); + } + } + ImGui::PopID(); + } + ImGui::PopID(); + // draw_list->AddBezierCubic(ScreenPoint_0, ScreenPoint_R_0, ScreenPoint_L_1, ScreenPoint_1, IM_COL32(10, 10, 10, 255), 1.0f, 0); + // draw_list->AddLine(ScreenPoint_0, ScreenPoint_1, wcol, 2.0f); + + i++; + if (i < Shape->Point_Count) { + Point_0 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i-1, 1); + Point_1 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); + } + } + } +} + + static void ImGui_Viewport_BrushUI(project_state *State, memory *Memory, ImVec2 ViewportMin, ImVec2 ViewportMax, ImVec2 CompZoom, ImGuiIO io, uint16 Width, uint16 Height) { @@ -386,7 +446,8 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD 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; - NumberOfVerts = NVG_FlattenPath(Memory, Bezier, 3, (nvg_point *)Data, &L_Width, &L_Height); + Assert(Layer->Shape.Contiguous); + NumberOfVerts = NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, &L_Width, &L_Height); Width = L_Width; Height = L_Height; } else { @@ -395,8 +456,6 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD Height = Source->Height; } - v2 Point[5] = { V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue), V2(0, 0), V2(Width, 0), V2(0, Height), V2(Width, Height) }; - layer_transforms T = Layer_GetTransforms(Layer); if (State->Interact_Active == interact_type_viewport_transform && Layer->IsSelected == 1) { @@ -404,34 +463,39 @@ 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++) { - // v2 ThisPoint = Bezier->Point[i].Pos[0]; - // v2 Pos = TransformPoint(T, Width, Height, ThisPoint); - // 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); - // } - - // imgui code - - void *Data2 = Memory_PushScratch(Memory, sizeof(real32) * 3 * 256); - uint32 GL_PointCount = NVG_ExpandStroke(Memory, Bezier, NumberOfVerts, (nvg_point *)Data, (real32 *)Data2); - - v2 L_Pos[4] = { Bezier->Point[0].Pos[0], Bezier->Point[0].Pos[2], Bezier->Point[1].Pos[1], Bezier->Point[1].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]); + 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); - ScreenPoint[i] = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, - UI->CompPos.y + CompUV.y * UI->CompZoom.y); + 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); } - 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); + 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); + + 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 @@ -456,9 +520,10 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD Memory_PopScratch(Memory, sizeof(nvg_point) * 128); } + v2 BoundingPoint[5] = { V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue), V2(0, 0), V2(Width, 0), V2(0, Height), V2(Width, Height) }; v2 NewPos[5]; for (int i = 0; i < 5; i++) { - NewPos[i] = TransformPoint(T, Width, Height, Point[i]); + NewPos[i] = TransformPoint(T, Width, Height, BoundingPoint[i]); } int i = 0; @@ -554,7 +619,9 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, } } - + 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); // Interactions for dragging and zooming ImGui::SetCursorScreenPos(ViewportMin); @@ -573,7 +640,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, if (IsHovered && IsActivated && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) { - State->TempZoomRatio = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos); + State->LastClickedPoint = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos); if (!ImGui::IsKeyDown(ImGuiKey_Z)) { if (State->Tool == tool_brush && State->Interact_Active != interact_type_brush) { @@ -654,21 +721,39 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, RenderQueue_AddBlit(State); } } + if (State->Tool == tool_pen && State->Interact_Active == interact_type_none && State->MostRecentlySelectedLayer == -1) { - v2 CompUV = State->TempZoomRatio; + v2 CompUV = State->LastClickedPoint; ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, UI->CompPos.y + CompUV.y * UI->CompZoom.y); - ImVec2 Vector = io.MousePos - ScreenPoint; - if (IsActive && !OtherActions) { - uint32 wcol = IM_COL32(00, 00, 80, 255); - draw_list->AddLine(ScreenPoint - Vector, io.MousePos, wcol, 2.0f); - draw_list->AddNgon(ScreenPoint, 2, wcol, 8, 2.0f); + shape_layer *Shape = &UI->Shape; + ImGui::OpenPopupOnItemClick("shapecreate", ImGuiPopupFlags_MouseButtonRight); + if (ImGui::BeginPopup("shapecreate")) { + if (ImGui::Selectable("Create shape layer")) { + State->HotkeyInput = hotkey_newlayer_shape; + } + ImGui::EndPopup(); } - if (IsDeactivated) { - State->HotkeyInput = hotkey_newlayer_shape; - if (fabs(Vector.x) > 5 && fabs(Vector.y) > 5) { - State->HotkeyExtra[0] = Vector.x; - State->HotkeyExtra[1] = Vector.y; + if (!Shape->IsClosed) { + if (IsHovered && IsActivated && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) + { + } + ImVec2 Vector = io.MousePos - ScreenPoint; + uint32 wcol = IM_COL32(00, 00, 80, 255); + if (IsActive && !OtherActions) { + draw_list->AddLine(ScreenPoint - Vector, io.MousePos, wcol, 2.0f); + draw_list->AddNgon(ScreenPoint, 2, wcol, 8, 2.0f); + } + if (IsDeactivated && !OtherActions && !ImGui::IsMouseReleased(ImGuiMouseButton_Right)) { + interpolation_type Type = interpolation_type_bezier; + if (fabs(Vector.x) < 5 && fabs(Vector.y) < 5) { + Type = interpolation_type_linear; + Vector = ImVec2(0, 0); + } + bezier_point PointData = { 1, { CompUV * V2(MainComp->Width, MainComp->Height), V2(Vector.x, Vector.y), V2(-Vector.x, -Vector.y) }, Type, 0 }; + History_Entry_Commit(Memory, "Bezier point"); + Bezier_Add(Memory, F_File, Shape->Block_Bezier_Index, &Shape->Block_Bezier_Count, &Shape->Point_Count, PointData); + History_Entry_End(Memory); } } } @@ -693,8 +778,8 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, Distance *= -1; UI->CompZoom.x += (Distance)*(real32)MainComp->Width/MainComp->Height; UI->CompZoom.y += (Distance); - UI->CompPos.x -= ((Distance)*(real32)MainComp->Width/MainComp->Height)*State->TempZoomRatio.x; - UI->CompPos.y -= Distance*State->TempZoomRatio.y; + UI->CompPos.x -= ((Distance)*(real32)MainComp->Width/MainComp->Height)*State->LastClickedPoint.x; + UI->CompPos.y -= Distance*State->LastClickedPoint.y; } ImGui::SetCursorScreenPos(ImVec2(ViewportMin.x, ViewportMin.y + ViewportScale.y - FontSize*1.5)); diff --git a/src/include/debug.h b/src/include/debug.h index 6321679..e1d8ccc 100644 --- a/src/include/debug.h +++ b/src/include/debug.h @@ -37,7 +37,7 @@ struct project_debug // NOTE(fox): Pixel count isn't thread safe; don't use with multithreading! uint64 LayerCycleCount[64]; uint32 UndoState = 0; - uint64 ScratchSize[6]; + uint64 ScratchSize[32]; uint32 ScratchState = 0; }; diff --git a/src/include/defines.h b/src/include/defines.h index 8216f1c..1d4e147 100644 --- a/src/include/defines.h +++ b/src/include/defines.h @@ -36,7 +36,8 @@ typedef uint64 ptrsize; // is there a compiler variable for 32 vs 64 bit like #define MAX_MASKS 8 #define MAX_PROPERTIES_PER_EFFECT 80 // Kinda high since we want to support 8 xy points of Curves data across 5 channels. #define MAX_KEYFRAME_BLOCKS 64 -#define MAX_KEYFRAMES_PER_BLOCK 32 // max keyframes on a single channel is 2048 +// #define MAX_KEYFRAMES_PER_BLOCK 32 // max keyframes on a single channel is 2048 +#define MAX_KEYFRAMES_PER_BLOCK 2 #define MAX_SELECTED_PROPERTIES 16 diff --git a/src/include/functions.h b/src/include/functions.h index 53920cb..e7b5e44 100644 --- a/src/include/functions.h +++ b/src/include/functions.h @@ -12,15 +12,17 @@ static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 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); uint32 Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size); -void GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *PointData, uint32 GL_PointCount, - layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height); +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); 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/main.h b/src/include/main.h index 8590904..a39fe45 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -187,7 +187,7 @@ struct shape_options { int Visibility; v4 FillCol = {1, 1, 1, 1}; v4 StrokeCol = {1, 1, 1, 1}; - float StrokeWidth; + float StrokeWidth = 50; }; struct shape_layer { @@ -195,6 +195,7 @@ struct shape_layer { uint16 Block_Bezier_Count; uint16 Point_Count; bool32 IsClosed; + bool32 Contiguous = 1; // No points have been deleted/added, so sorting isn't needed. int Width; int Height; shape_options Opt; @@ -207,7 +208,6 @@ enum timeline_mode }; struct pen_state { - shape_options Opt; }; struct brush_state @@ -378,7 +378,6 @@ struct project_state int32 PreviewSource = -1; hotkey_input HotkeyInput; - real32 HotkeyExtra[4]; // bloat? void *Dump1; void *Dump2; @@ -443,7 +442,7 @@ struct project_state focused_window FocusedWindow; // Convenience for adding window-specific hotkeys. bool32 SetFocus; - v2 TempZoomRatio = V2(1, 1); + v2 LastClickedPoint = V2(1, 1); }; // UI info that's saved to the file and is not part of the history tree @@ -468,6 +467,8 @@ struct ui bool32 StableEnabled = 0; #endif + shape_layer Shape; + ImU32 LayerColors[16] = { 0xff8b1f1f, 0xffc25909, diff --git a/src/include/my_math.h b/src/include/my_math.h index 92d43b7..865f11c 100644 --- a/src/include/my_math.h +++ b/src/include/my_math.h @@ -66,14 +66,8 @@ inline v2 V2(ImVec2 A) return(Result); } -inline ImVec2 V2(v2 A) -{ - struct ImVec2 Result; - - Result.x = A.x; - Result.y = A.y; - - return(Result); +inline ImVec2 ImVec2_(v2 f) { + return { f.x, f.y }; } inline v2i V2i(int32 x, int32 y) diff --git a/src/layer.cpp b/src/layer.cpp index c3d3d16..93db19d 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -107,16 +107,20 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor GL_UpdateTexture(&TestM, EffectBitmapAddress, Width, Height, BytesPerPixel, 1); if (Layer->IsShapeLayer) { - block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0]); + shape_layer *Shape = &Layer->Shape; void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128); - uint32 NumberOfVerts = NVG_FlattenPath(Memory, Bezier, 3, (nvg_point *)Data, L_Width, L_Height); - void *Data2 = Memory_PushScratch(Memory, sizeof(real32) * 3 * 256); - uint32 GL_PointCount = NVG_ExpandStroke(Memory, Bezier, NumberOfVerts, (nvg_point *)Data, (real32 *)Data2); + uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, L_Width, L_Height); + 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); + 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, Data2, GL_PointCount, T, Width, Height, BytesPerPixel, EffectBitmapAddress, *L_Width, *L_Height); + 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); - Memory_PopScratch(Memory, sizeof(real32) * 3 * 256); + Memory_PopScratch(Memory, sizeof(real32) * 4 * NumberOfVerts); + Memory_PopScratch(Memory, sizeof(real32) * 4 * 256); Memory_PopScratch(Memory, sizeof(nvg_point) * 128); // Bitmap_StencilAlpha(SourceBitmapAddress, EffectBitmapAddress, Source->BytesPerPixel, Size); @@ -350,7 +354,7 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar 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); layer_transforms T = Layer_GetTransforms(Layer); - v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->TempZoomRatio); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->LastClickedPoint); if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected) { SelectionCount++; @@ -364,7 +368,7 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar 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); layer_transforms T = Layer_GetTransforms(Layer); - v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->TempZoomRatio); + v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->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 9856143..27a985e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -783,11 +783,12 @@ int main(int argc, char *argv[]) { #endif #if DEBUG -#if 0 +#if 1 sprintf(State->DummyName, "test"); - File_Open(File, State, &Memory, State->DummyName); - State->UpdateFrame = true; - // State->MostRecentlySelectedLayer = 0; + if (File_Open(File, State, &Memory, State->DummyName)) { + State->UpdateFrame = true; + State->MostRecentlySelectedLayer = 0; + } #else // uint16 SourceIndex = Source_Generate(File, State, &Memory, (void *)"../asset/yu.webm"); // block_source *Source = (block_source *)Memory_Block_AddressAtIndex(&Memory, F_Sources, SourceIndex); @@ -877,15 +878,7 @@ int main(int argc, char *argv[]) { } break; case hotkey_newlayer_shape: { - block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(&Memory, F_Precomps, File->PrincipalCompIndex); - v2 Point = State->TempZoomRatio * V2(MainComp->Width, MainComp->Height); - v2 Vector = V2(0, 0); - if (State->HotkeyExtra[0] != 0) { - Vector = V2(State->HotkeyExtra[0], State->HotkeyExtra[1]); - State->HotkeyExtra[0] = 0; - State->HotkeyExtra[1] = 0; - } - Project_ShapeLayer_New(File, State, &Memory, Point, Vector); + Project_ShapeLayer_New(File, State, &Memory); } break; case hotkey_newlayer_source: { diff --git a/src/nanovg.cpp b/src/nanovg.cpp index 06b2910..5627b5f 100644 --- a/src/nanovg.cpp +++ b/src/nanovg.cpp @@ -128,20 +128,23 @@ static real32 * NVG_RoundCap(nvg_point * Point, real32 *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). static uint32 -NVG_FlattenPath(void *Memory, block_bezier *Bezier, int PointCount, nvg_point *PointData, int *Width, int *Height) +NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData, int *Width, int *Height) { uint32 NumberOfVerts = 0; nvg_point *PointPlayhead = PointData; - for (int i = 0; i < PointCount; i++) { - if (i == 0 || Bezier->Point[i].Type == interpolation_type_linear) { - *(v2 *)PointPlayhead = Bezier->Point[i].Pos[0]; - if (i != 0 && i != (PointCount - 1)) { + 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)) { PointPlayhead->Flags |= NVG_PT_CORNER; } PointPlayhead++; NumberOfVerts++; - } else if (Bezier->Point[i].Type == interpolation_type_bezier) { - v2 Pos[4] = { Bezier->Point[i].Pos[0], Bezier->Point[i].Pos[1], Bezier->Point[i+1].Pos[2], Bezier->Point[i+1].Pos[0] }; + } 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)); @@ -151,6 +154,14 @@ NVG_FlattenPath(void *Memory, block_bezier *Bezier, int PointCount, nvg_point *P } 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 } nvg_point *Point = &PointData[NumberOfVerts - 1]; nvg_point *NextPoint = PointData; @@ -178,17 +189,26 @@ NVG_FlattenPath(void *Memory, block_bezier *Bezier, int PointCount, nvg_point *P real32 MiterLimit = 2.4f; static uint32 -NVG_ExpandStroke(void *Memory, block_bezier *Bezier, int NumberOfVerts, nvg_point *PointData, real32 *StrokeData) +NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsClosed, nvg_point *PointData, real32 *StrokeData) { - real32 Width = 50 * 0.5; - nvg_point *Point = PointData; - nvg_point *NextPoint = &PointData[1]; + real32 Width = StartWidth * 0.5; int ncap = 12; real32 *StartingStrokeData = StrokeData; - StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0); + nvg_point *Point = &PointData[NumberOfVerts - 1]; + nvg_point *NextPoint = PointData; + int Start = 0; + int LoopAmount = NumberOfVerts; + + if (!IsClosed) { + Point = PointData; + NextPoint = &PointData[1]; + Start = 1; + LoopAmount = NumberOfVerts - 1; + StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0); + } - for (int i = 1; i < (NumberOfVerts - 1); i++) { + for (int i = Start; i < LoopAmount; i++) { real32 dlx0, dly0, dlx1, dly1, dmr2, cross, limit; dlx0 = Point->dy; @@ -223,7 +243,7 @@ NVG_ExpandStroke(void *Memory, block_bezier *Bezier, int NumberOfVerts, nvg_poin // 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; + // NextPoint->Flags |= NVG_PT_BEVEL; // } } @@ -239,9 +259,24 @@ NVG_ExpandStroke(void *Memory, block_bezier *Bezier, int NumberOfVerts, nvg_poin Point = NextPoint++; } - StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 1); + if (!IsClosed) { + StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 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); + } int GL_PointCount = (StrokeData - StartingStrokeData) / 4; return GL_PointCount; } + +static void +NVG_ExpandFill(void *Memory, int NumberOfVerts, nvg_point *PointData, real32 *FillData) +{ + nvg_point *Point = PointData; + for (int i = 0; i < NumberOfVerts; i++) { + FillData = NVG_Point(FillData, Point->x, Point->y, 0, 0); + Point++; + } +} -- cgit v1.2.3