diff options
author | Fox Caminiti <fox@foxcam.net> | 2023-01-06 10:26:43 -0500 |
---|---|---|
committer | Fox Caminiti <fox@foxcam.net> | 2023-01-06 10:26:43 -0500 |
commit | 1de48570b220acc1ca7063e2a9cda1e89178c0f9 (patch) | |
tree | 1edd38bd7ad7f95f865793a9d0e54c62aa3bf37e /src/nanovg.cpp | |
parent | eebbdd012b0d156e9e92369585c6ad82ed3de371 (diff) |
bad shape positioning
Diffstat (limited to 'src/nanovg.cpp')
-rw-r--r-- | src/nanovg.cpp | 188 |
1 files changed, 126 insertions, 62 deletions
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); |