diff options
author | Fox Caminiti <fox@foxcam.net> | 2023-01-20 10:10:54 -0500 |
---|---|---|
committer | Fox Caminiti <fox@foxcam.net> | 2023-01-20 10:10:54 -0500 |
commit | 2f164ae23bcd8a857081529189b484a1515f2834 (patch) | |
tree | c7f5b163f7e1585a8fbdb3b8fb7fb012761ae239 /src/bezier.cpp | |
parent | 1d0d8549411e23394059f420f053cc3ee28dacfb (diff) |
youarelazy
Diffstat (limited to 'src/bezier.cpp')
-rw-r--r-- | src/bezier.cpp | 121 |
1 files changed, 112 insertions, 9 deletions
diff --git a/src/bezier.cpp b/src/bezier.cpp index b90e146..5916c42 100644 --- a/src/bezier.cpp +++ b/src/bezier.cpp @@ -1,3 +1,7 @@ +#if SPECIAL +#include "main.h" +#endif + static real32 Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 TargetX) { @@ -46,6 +50,11 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, 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 (Width != 0 && Height != 0) { + for (int a = 0; a < 3; a++) { + Point.Pos[a] = Point.Pos[a] * V2(Width, Height); + } + } if (State->Interact_Active == interact_type_keyframe_move && Interact && Point.IsSelected) { v2 Pos = Point.Pos[0]; Pos = TransformPoint(T, Width, Height, Pos); @@ -64,6 +73,10 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData, 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]; + if (Width != 0 && Height != 0) { + Pos_Prev = Pos_Prev * V2(Width, Height); + Pos_Next = Pos_Next * V2(Width, Height); + } // TODO(fox): debloat if (State->Interact_Active == interact_type_keyframe_move && Interact && Point_Prev->IsSelected) { v2 Pos = Pos_Prev; @@ -255,21 +268,38 @@ void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Siz return ((uint8 *)Data + (Increment * Size)); } +v2 Bezier_LineDist(v2 a, v2 b, v2 p) +{ + v2 ap = p - a; + v2 ab_dir = b - a; + real32 dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) { + return a; + } + real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + if (dot > ab_len_sqr) { + return b; + } + return p - (a + ab_dir * dot / ab_len_sqr); +} -#if 0 -// A modified version of the bezier code in ImGui with extra features for bitmap and path interaction. - -// Function to convert a ratio back into a point for the bezier handles. -v2 Line_RatioToPoint(v2 a, v2 b, real32 ratio) +v2 Bezier_LineClosestPoint(v2 a, v2 b, v2 p) { + v2 ap = p - a; v2 ab_dir = b - a; + real32 dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) { + return a; + } real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; - real32 dot = ratio*ab_len_sqr; - return a + ab_dir * dot / V2(ab_len_sqr); + if (dot > ab_len_sqr) { + return b; + } + return a + ab_dir * dot / ab_len_sqr; } // The ratio here is just the dot product divided by the squared length. -v2 Bezier_LineClosestPoint2(v2 a, v2 b, v2 p, real32 *ratio) +v2 Bezier_LineClosestPointR(v2 a, v2 b, v2 p, real32 *ratio) { v2 ap = p - a; v2 ab_dir = b - a; @@ -287,6 +317,54 @@ v2 Bezier_LineClosestPoint2(v2 a, v2 b, v2 p, real32 *ratio) return a + ab_dir * dot / ab_len_sqr; } +static void Bezier_CubicBoxCasteljauStep(v2 Min, v2 Max, v2 *p_closest, v2 *p_last, real32 *p_closest_dist2, + real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level) +{ + real32 dx = x4 - x1; + real32 dy = y4 - y1; + real32 d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + real32 d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + v2 p_current = V2(x4, y4); + v2 p[4] = { Min, Max, V2(Min.x, Max.y), V2(Max.y, Min.x) }; + for (int i = 0; i < 4; i++) { + v2 p_line = Bezier_LineClosestPoint(*p_last, p_current, p[i]); + real32 dist2 = LengthSq(p[i] - p_line); + if (dist2 < p_closest_dist2[i]) + { + p_closest[i] = p_line; + p_closest_dist2[i] = dist2; + } + } + *p_last = p_current; + } + else if (level < 10) + { + real32 x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; + real32 x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; + real32 x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; + real32 x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; + real32 x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; + real32 x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; + Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +static void +Bezier_BoxTest(v2 p1, v2 p2, v2 p3, v2 p4, v2 Min, v2 Max, v2 *p_closest) +{ + real32 tess_tol = TESS_TOL; + v2 p_last = p1; + real32 p_closest_dist2[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }; + Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, &p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); +} + + +#if 0 // Following the algorithm, we take the ratio from the _leftmost_ point in each // subdivision of the cubic spline until we're within tess_tol, and then we // interpolate it with the subdivision's rightmost point in the ClosestPoint call. @@ -307,7 +385,7 @@ static void Bezier_CubicClosestPointCasteljauStep(v2 p, v2 *p_closest, real32 ra { v2 p_current = V2(x4, y4); real32 added_ratio; - v2 p_line = Bezier_LineClosestPoint2(*p_last, p_current, p, &added_ratio); + v2 p_line = Bezier_LineClosestPoint(*p_last, p_current, p, &added_ratio); real32 dist2 = LengthSq(p - p_line); if (dist2 < *p_closest_dist2) { @@ -330,6 +408,31 @@ static void Bezier_CubicClosestPointCasteljauStep(v2 p, v2 *p_closest, real32 ra } } +real32 Bezier_CubicRatioOfPoint(v2 p1, v2 p2, v2 p3, v2 p4, v2 p) +{ + real32 tess_tol = TESS_TOL; + v2 p_last = p1; + v2 p_closest; + real32 p_closest_dist2 = FLT_MAX; + real32 ratio = 0; + Bezier_CubicClosestPointCasteljauStep(p, &p_closest, 0, &ratio, &p_last, &p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + return ratio; +} +#endif + + +#if 0 +// A modified version of the bezier code in ImGui with extra features for bitmap and path interaction. + +// Function to convert a ratio back into a point for the bezier handles. +v2 Line_RatioToPoint(v2 a, v2 b, real32 ratio) +{ + v2 ab_dir = b - a; + real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + real32 dot = ratio*ab_len_sqr; + return a + ab_dir * dot / V2(ab_len_sqr); +} + // finds the min/max bounds of the curve static void Bezier_CubicMinMaxCasteljauStep(v2 *p_min, v2 *p_max, real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level) { |