From 1d0d8549411e23394059f420f053cc3ee28dacfb Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Fri, 6 Jan 2023 23:11:49 -0500 Subject: more shape code --- src/bezier.cpp | 55 ++++++++++++++---- src/gl_calls.cpp | 136 +++++++++++++++++++++++--------------------- src/imgui_ui_properties.cpp | 27 ++++++++- src/imgui_ui_viewport.cpp | 4 +- src/include/functions.h | 6 ++ src/layer.cpp | 5 +- src/nanovg.cpp | 29 +++------- 7 files changed, 163 insertions(+), 99 deletions(-) diff --git a/src/bezier.cpp b/src/bezier.cpp index 1585495..b90e146 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -34,20 +34,53 @@ Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 Tar return Y; } +// All the extra inputs on the second line are for when we need to take +// interactive mode into account. // TODO(fox): Incorporate sorting for non-continuous shapes. static uint32 -Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData) +Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, + project_state *State, layer_transforms T, int Width, int Height, + int CompWidth, int CompHeight, bool32 Interact) { 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]; + bezier_point Point = *Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1); + if (State->Interact_Active == interact_type_keyframe_move && Interact && Point.IsSelected) { + v2 Pos = Point.Pos[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); + Point.Pos[0] = Pos; + } + // Corner rounder + if ((Radius > 0 && Point.Type == interpolation_type_linear) && + (Shape->IsClosed || (i != 0 && i != (Shape->Point_Count - 1)) )) { + 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]; + bezier_point *Point_Prev = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Index_Prev, 1); + bezier_point *Point_Next = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Index_Next, 1); + v2 Pos_Prev = Point_Prev->Pos[0]; + v2 Pos_Next = Point_Next->Pos[0]; + // TODO(fox): debloat + if (State->Interact_Active == interact_type_keyframe_move && Interact && Point_Prev->IsSelected) { + v2 Pos = Pos_Prev; + 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); + Pos_Prev = Pos; + } + if (State->Interact_Active == interact_type_keyframe_move && Interact && Point_Next->IsSelected) { + v2 Pos = Pos_Next; + 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); + Pos_Next = Pos; + } v2 Vector_Prev = Pos - Pos_Prev; v2 Vector_Next = Pos - Pos_Next; real32 Length_Prev = sqrtf(LengthSq(Vector_Prev)); @@ -56,10 +89,10 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData) // 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 = Min(Radius / Length_Prev, 0.5); real32 Ratio_Prev_Inv = 1.0f - Ratio_Prev; - real32 Ratio_Next = Radius / Length_Next; + real32 Ratio_Next = Min(Radius / Length_Next, 0.5); 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)); @@ -67,10 +100,10 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData) 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 }; + *PointData++ = { 1, { Point_1, Point_2, V2(0, 0) }, interpolation_type_bezier, Point.IsSelected }; + *PointData++ = { 1, { Point_3, V2(0, 0), Point_4 }, interpolation_type_bezier, Point.IsSelected }; } else { - *PointData++ = *Point; + *PointData++ = Point; } } return PointData - PointStart; diff --git a/src/gl_calls.cpp b/src/gl_calls.cpp index a1938be..3db9e6a 100644 --- a/src/gl_calls.cpp +++ b/src/gl_calls.cpp @@ -206,53 +206,59 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa Uniform = glGetUniformLocation(DefaultShaderProgram, "Scale"); glUniform1f(Uniform, T.scale); - Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); - glUniform1i(Uniform, 1); - Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); - glUniform1i(Uniform, 1); - - // 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))); - - // 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_FAN, 0, FillCount); - // - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBindVertexArray(0); + if (RenderMode == 0 || RenderMode == 1) + { - Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); - glUniform1i(Uniform, 0); - Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); - glUniform1i(Uniform, 1); - Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol"); - 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); - // + Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); + glUniform1i(Uniform, 1); + Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); + glUniform1i(Uniform, 1); + + // 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))); + + // 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_FAN, 0, FillCount); + // + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glBindVertexArray(0); + + Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode"); + glUniform1i(Uniform, 0); + Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode"); + glUniform1i(Uniform, 1); + Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol"); + 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); + // + } else { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } // stencil buffer not needed glDisable(GL_STENCIL_TEST); @@ -261,24 +267,26 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa 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); - // + if (RenderMode == 0 || RenderMode == 2) { + 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); diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp index 6f949c8..83adcf1 100644 --- a/src/imgui_ui_properties.cpp +++ b/src/imgui_ui_properties.cpp @@ -434,11 +434,13 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * 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" }; + char *Names[3] = { "Fill and stroke", "Fill only", "Stroke only" }; if (ImGui::BeginListBox("Shape render type")) { for (int i = 0; i < 3; i++) { if (ImGui::Selectable(Names[i], (Opt->Visibility == i))) { Opt->Visibility = i; + Memory->PurgeCache = true; + State->UpdateFrame = true; } } ImGui::EndListBox(); @@ -449,6 +451,8 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * for (int i = 0; i < 2; i++) { if (ImGui::Selectable(Names2[i], (Opt->LineCapType == CapVals[i]))) { Opt->LineCapType = CapVals[i]; + Memory->PurgeCache = true; + State->UpdateFrame = true; } } ImGui::EndListBox(); @@ -460,15 +464,36 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * if (ImGui::Selectable(Names3[i], (Opt->LineJoinType == JoinVals[i]))) { Opt->Visibility = i; Opt->LineJoinType = JoinVals[i]; + Memory->PurgeCache = true; + State->UpdateFrame = true; } } ImGui::EndListBox(); } ImGui::ColorEdit4("Fill color", (real32 *)&Opt->FillCol, ImGuiColorEditFlags_Float); + if (ImGui::IsItemActive()) { + Memory->PurgeCache = true; + State->UpdateFrame = true; + } ImGui::ColorEdit4("Stroke color", (real32 *)&Opt->StrokeCol, ImGuiColorEditFlags_Float); + if (ImGui::IsItemActive()) { + Memory->PurgeCache = true; + State->UpdateFrame = true; + } real32 StrokeWidthMin = 0; real32 StrokeWidthMax = 1024; ImGui::DragScalar("Stroke width", ImGuiDataType_Float, &Opt->StrokeWidth, 1, &StrokeWidthMin, &StrokeWidthMax, "%.3f"); + if (ImGui::IsItemActive()) { + Memory->PurgeCache = true; + State->UpdateFrame = true; + } + real32 RoundnessMin = 0; + real32 RoundnessMax = 1024; + ImGui::DragScalar("Roundness", ImGuiDataType_Float, &Opt->Roundness, 1, &RoundnessMin, &RoundnessMax, "%.3f"); + if (ImGui::IsItemActive()) { + Memory->PurgeCache = true; + State->UpdateFrame = true; + } // State->UpdateFrame = true; } ImGui::End(); diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index 774b305..beb7c8f 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -786,7 +786,9 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x, UI->CompPos.y + CompUV.y * UI->CompZoom.y); shape_layer *Shape = &UI->Shape; - ImGui::OpenPopupOnItemClick("shapecreate", ImGuiPopupFlags_MouseButtonRight); + if (Shape->Point_Count > 1) { + ImGui::OpenPopupOnItemClick("shapecreate", ImGuiPopupFlags_MouseButtonRight); + } if (ImGui::BeginPopup("shapecreate")) { if (ImGui::Selectable("Create shape layer")) { State->HotkeyInput = hotkey_newlayer_shape; diff --git a/src/include/functions.h b/src/include/functions.h index 32737ea..2c18f85 100644 --- a/src/include/functions.h +++ b/src/include/functions.h @@ -18,6 +18,12 @@ 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); + +static uint32 +Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, + project_state *State, layer_transforms T, int Width, int Height, + int CompWidth, int CompHeight, bool32 Interact); + void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size); static layer_transforms Transform_Inverse(layer_transforms T); diff --git a/src/layer.cpp b/src/layer.cpp index 6159467..b27935b 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -112,11 +112,14 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor Arbitrary_Zero((uint8 *)Data, sizeof(nvg_point) * 128); layer_transforms T = Layer_GetTransforms(Layer); v2 Min = {}, Max = {}; + int ShapeWidth = 0, ShapeHeight = 0; if (State->Interact_Active == interact_type_keyframe_move) { NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max); + ShapeWidth = Max.x - Min.x; + ShapeHeight = Max.y - Min.y; } uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, - State, T, Shape->Width, Shape->Height, Width, Height, 1, &Min, &Max); + State, T, ShapeWidth, ShapeHeight, 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->Opt.LineCapType, Shape->Opt.LineJoinType, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke); void *Data_Fill = Memory_PushScratch(Memory, sizeof(real32) * 4 * NumberOfVerts); diff --git a/src/nanovg.cpp b/src/nanovg.cpp index 1fb59ee..22d8621 100644 --- a/src/nanovg.cpp +++ b/src/nanovg.cpp @@ -172,42 +172,28 @@ static real32 * NVG_ButtCap(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). -// 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, project_state *State, layer_transforms T, int Width, int Height, int CompWidth, int CompHeight, bool32 Interact, v2 *Min, v2 *Max) { 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); + bezier_point *BezierPointData = (bezier_point *)Memory_PushScratch(Memory, sizeof(bezier_point) * 128); + uint32 BezierCount = Bezier_Shape_Sort(Memory, Shape, BezierPointData, + State, T, Width, Height, + CompWidth, CompHeight, Interact); + for (int i = 0; i < BezierCount; i++) { + bezier_point *Point = &BezierPointData[i]; if (i == 0 || Point->Type == interpolation_type_linear) { 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++; } else if (Point->Type == interpolation_type_bezier) { - bezier_point *Point_1 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i-1, 1); + bezier_point *Point_1 = &BezierPointData[i-1]; 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. if (i != (Shape->Point_Count - 1)) @@ -216,6 +202,7 @@ NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData, Assert(0); } } + Memory_PopScratch(Memory, sizeof(bezier_point) * 128); int NumberOfVerts = PointPlayhead - PointData; nvg_point *Point = &PointData[NumberOfVerts - 1]; nvg_point *NextPoint = PointData; -- cgit v1.2.3