Add a function for getting figure orientation to find the correct fill side of a cubic bezier.
Signed-off-by: Connor McAdams conmanx360@gmail.com --- dlls/d2d1/geometry.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index c9ea108484..a231bed986 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -2915,11 +2915,19 @@ struct d2d_cubic_triangles D2D1_POINT_2F p[4]; };
+enum figure_orientation +{ + ORIENTATION_CW, /* Clockwise. */ + ORIENTATION_CCW, /* Counter clockwise. */ +}; + struct d2d_cubic_triangulation { struct d2d_cubic_triangles *cubic_tri; size_t cubic_tri_count; size_t cubic_tri_size; + + unsigned int orientation; };
static BOOL d2d_point_approximately_equal(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b) @@ -3151,6 +3159,69 @@ static HRESULT d2d_geometry_triangulate_beziers(struct d2d_geometry *geometry, return S_OK; }
+static float d2d_geometry_point_orientation(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b) +{ + return (b->x - a->x) * (b->y + a->y); +} + +static void d2d_geometry_get_figure_orientation(struct d2d_geometry *geometry, + struct d2d_cubic_triangulation *triangles) +{ + const struct d2d_figure *figure; + struct d2d_segment_idx idx; + struct d2d_cubic_triangulation *fig_tri; + enum d2d_vertex_type type; + const D2D1_POINT_2F *p[4]; + float orientation; + size_t next; + unsigned int i; + + for (idx.figure_idx = 0; idx.figure_idx < geometry->u.path.figure_count; ++idx.figure_idx) + { + figure = &geometry->u.path.figures[idx.figure_idx]; + fig_tri = &triangles[idx.figure_idx]; + orientation = 0.0f; + + for (idx.vertex_idx = 0, idx.control_idx = 0; idx.vertex_idx < figure->vertex_count; ++idx.vertex_idx) + { + type = figure->vertex_types[idx.vertex_idx]; + next = idx.vertex_idx + 1; + if (next == figure->vertex_count) + next = 0; + + switch (type) + { + case D2D_VERTEX_TYPE_LINE: + p[0] = &figure->vertices[idx.vertex_idx]; + p[1] = &figure->vertices[next]; + orientation += d2d_geometry_point_orientation(p[0], p[1]); + break; + + case D2D_VERTEX_TYPE_BEZIER: + case D2D_VERTEX_TYPE_SPLIT_BEZIER: + p[0] = &figure->vertices[idx.vertex_idx]; + p[1] = &figure->bezier_controls[idx.control_idx].c0; + p[2] = &figure->bezier_controls[idx.control_idx++].c1; + p[3] = &figure->vertices[next]; + + for (i = 1; i < 4; i++) + orientation += d2d_geometry_point_orientation(p[i - 1], p[i]); + break; + + default: + break; + } + } + + /* Depending on orientation value, set either clockwise or + * counter-clockwise. */ + if (orientation < 0.0f) + fig_tri->orientation = ORIENTATION_CW; + else + fig_tri->orientation = ORIENTATION_CCW; + } +} + static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx_p, const struct d2d_segment_idx *idx_q) { @@ -3337,6 +3408,8 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry) } }
+ d2d_geometry_get_figure_orientation(geometry, triangles); + for (i = 0; i < geometry->u.path.figure_count; ++i) { if (geometry->u.path.figures[i].flags & D2D_FIGURE_FLAG_HOLLOW)