Store cubic bezier control points alongside quadratic control points.
Signed-off-by: Connor McAdams conmanx360@gmail.com --- dlls/d2d1/geometry.c | 102 +++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 32 deletions(-)
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c index e7bb809359..a8e6a3f2b7 100644 --- a/dlls/d2d1/geometry.c +++ b/dlls/d2d1/geometry.c @@ -59,6 +59,12 @@ struct d2d_segment_idx size_t control_idx; };
+struct d2d_bezier_controls +{ + D2D1_POINT_2F c0, c1; + D2D1_POINT_2F cq0; +}; + struct d2d_figure { D2D1_POINT_2F *vertices; @@ -67,11 +73,11 @@ struct d2d_figure size_t vertex_types_size; size_t vertex_count;
- D2D1_POINT_2F *bezier_controls; + struct d2d_bezier_controls *bezier_controls; size_t bezier_controls_size; size_t bezier_control_count;
- D2D1_POINT_2F *original_bezier_controls; + struct d2d_bezier_controls *original_bezier_controls; size_t original_bezier_control_count;
D2D1_RECT_F bounds; @@ -409,6 +415,15 @@ static void d2d_point_normalise(D2D1_POINT_2F *p) d2d_point_scale(p, 1.0f / l); }
+static void d2d_bezier_quad_to_cubic(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, + const D2D1_POINT_2F *p2, D2D1_POINT_2F *c0, D2D1_POINT_2F *c1) +{ + c0->x = p0->x * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->x; + c0->y = p0->y * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->y; + c1->x = p2->x * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->x; + c1->y = p2->y * (1.0f / 3.0f) + (2.0f / 3.0f) * p1->y; +} + /* This implementation is based on the paper "Adaptive Precision * Floating-Point Arithmetic and Fast Robust Geometric Predicates" and * associated (Public Domain) code by Jonathan Richard Shewchuk. */ @@ -613,7 +628,8 @@ static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F verte return TRUE; }
-static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *p) +static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t idx, const D2D1_POINT_2F *c0, + const D2D1_POINT_2F *c1, const D2D1_POINT_2F *cq0) { if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size, figure->bezier_control_count + 1, sizeof(*figure->bezier_controls))) @@ -624,13 +640,16 @@ static BOOL d2d_figure_insert_bezier_control(struct d2d_figure *figure, size_t i
memmove(&figure->bezier_controls[idx + 1], &figure->bezier_controls[idx], (figure->bezier_control_count - idx) * sizeof(*figure->bezier_controls)); - figure->bezier_controls[idx] = *p; + figure->bezier_controls[idx].cq0 = *cq0; + figure->bezier_controls[idx].c0 = *c0; + figure->bezier_controls[idx].c1 = *c1; ++figure->bezier_control_count;
return TRUE; }
-static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *p) +static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_POINT_2F *c0, const D2D1_POINT_2F *c1, + const D2D1_POINT_2F *cq0) { if (!d2d_array_reserve((void **)&figure->bezier_controls, &figure->bezier_controls_size, figure->bezier_control_count + 1, sizeof(*figure->bezier_controls))) @@ -639,7 +658,9 @@ static BOOL d2d_figure_add_bezier_control(struct d2d_figure *figure, const D2D1_ return FALSE; }
- figure->bezier_controls[figure->bezier_control_count++] = *p; + figure->bezier_controls[figure->bezier_control_count].cq0 = *cq0; + figure->bezier_controls[figure->bezier_control_count].c0 = *c0; + figure->bezier_controls[figure->bezier_control_count++].c1 = *c1;
return TRUE; } @@ -1727,7 +1748,7 @@ static BOOL d2d_geometry_intersect_bezier_line(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[idx_p->figure_idx]; p[0] = &figure->vertices[idx_p->vertex_idx]; - p[1] = &figure->bezier_controls[idx_p->control_idx]; + p[1] = &figure->bezier_controls[idx_p->control_idx].cq0; next = idx_p->vertex_idx + 1; if (next == figure->vertex_count) next = 0; @@ -1805,7 +1826,7 @@ static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[idx_p->figure_idx]; p[0] = &figure->vertices[idx_p->vertex_idx]; - p[1] = &figure->bezier_controls[idx_p->control_idx]; + p[1] = &figure->bezier_controls[idx_p->control_idx].cq0; next = idx_p->vertex_idx + 1; if (next == figure->vertex_count) next = 0; @@ -1813,7 +1834,7 @@ static BOOL d2d_geometry_intersect_bezier_bezier(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[idx_q->figure_idx]; q[0] = &figure->vertices[idx_q->vertex_idx]; - q[1] = &figure->bezier_controls[idx_q->control_idx]; + q[1] = &figure->bezier_controls[idx_q->control_idx].cq0; next = idx_q->vertex_idx + 1; if (next == figure->vertex_count) next = 0; @@ -1864,7 +1885,7 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry, enum d2d_vertex_type vertex_type; const D2D1_POINT_2F *p[3]; struct d2d_figure *figure; - D2D1_POINT_2F q[2]; + D2D1_POINT_2F q[2], c[2]; float t, t_prev;
for (i = 0; i < intersections->intersection_count; ++i) @@ -1898,7 +1919,7 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry, }
p[0] = &figure->vertices[inter->vertex_idx + vertex_offset]; - p[1] = &figure->bezier_controls[inter->control_idx + control_offset]; + p[1] = &figure->bezier_controls[inter->control_idx + control_offset].cq0; next = inter->vertex_idx + vertex_offset + 1; if (next == figure->vertex_count) next = 0; @@ -1907,8 +1928,13 @@ static BOOL d2d_geometry_apply_intersections(struct d2d_geometry *geometry, d2d_point_lerp(&q[0], p[0], p[1], t); d2d_point_lerp(&q[1], p[1], p[2], t);
- figure->bezier_controls[inter->control_idx + control_offset] = q[0]; - if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &q[1]))) + d2d_bezier_quad_to_cubic(p[0], &q[0], &inter->p, &c[0], &c[1]); + figure->bezier_controls[inter->control_idx + control_offset].cq0 = q[0]; + figure->bezier_controls[inter->control_idx + control_offset].c0 = c[0]; + figure->bezier_controls[inter->control_idx + control_offset].c1 = c[1]; + + d2d_bezier_quad_to_cubic(&inter->p, &q[1], p[2], &c[0], &c[1]); + if (!(d2d_figure_insert_bezier_control(figure, inter->control_idx + control_offset + 1, &c[0], &c[1], &q[1]))) return FALSE; ++control_offset;
@@ -2285,7 +2311,7 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry, { prev_type = figure->vertex_types[figure->vertex_count - 1]; if (prev_type == D2D_VERTEX_TYPE_BEZIER) - prev = &figure->bezier_controls[figure->bezier_control_count - 1]; + prev = &figure->bezier_controls[figure->bezier_control_count - 1].cq0; else prev = &figure->vertices[figure->vertex_count - 1]; } @@ -2293,13 +2319,13 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry, { prev_type = figure->vertex_types[i - 1]; if (prev_type == D2D_VERTEX_TYPE_BEZIER) - prev = &figure->bezier_controls[bezier_idx - 1]; + prev = &figure->bezier_controls[bezier_idx - 1].cq0; else prev = &figure->vertices[i - 1]; }
if (type == D2D_VERTEX_TYPE_BEZIER) - next = &figure->bezier_controls[bezier_idx++]; + next = &figure->bezier_controls[bezier_idx++].cq0; else if (i == figure->vertex_count - 1) next = &figure->vertices[0]; else @@ -2541,7 +2567,7 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1], &p, &beziers[i].point3);
- if (!d2d_figure_add_bezier_control(figure, &p)) + if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1, &beziers[i].point2, &p)) { ERR("Failed to add bezier control.\n"); geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR; @@ -2661,7 +2687,7 @@ static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[idx_p->figure_idx]; a[0] = &figure->vertices[idx_p->vertex_idx]; - a[1] = &figure->bezier_controls[idx_p->control_idx]; + a[1] = &figure->bezier_controls[idx_p->control_idx].cq0; if (idx_p->vertex_idx == figure->vertex_count - 1) a[2] = &figure->vertices[0]; else @@ -2669,7 +2695,7 @@ static BOOL d2d_geometry_check_bezier_overlap(struct d2d_geometry *geometry,
figure = &geometry->u.path.figures[idx_q->figure_idx]; b[0] = &figure->vertices[idx_q->vertex_idx]; - b[1] = &figure->bezier_controls[idx_q->control_idx]; + b[1] = &figure->bezier_controls[idx_q->control_idx].cq0; if (idx_q->vertex_idx == figure->vertex_count - 1) b[2] = &figure->vertices[0]; else @@ -2747,19 +2773,19 @@ static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct next = 0;
return d2d_point_ccw(&figure->vertices[idx->vertex_idx], - &figure->bezier_controls[idx->control_idx], &figure->vertices[next]); + &figure->bezier_controls[idx->control_idx].cq0, &figure->vertices[next]); }
static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx) { const D2D1_POINT_2F *p[3]; struct d2d_figure *figure; - D2D1_POINT_2F q[3]; + D2D1_POINT_2F q[3], c[2]; size_t next;
figure = &geometry->u.path.figures[idx->figure_idx]; p[0] = &figure->vertices[idx->vertex_idx]; - p[1] = &figure->bezier_controls[idx->control_idx]; + p[1] = &figure->bezier_controls[idx->control_idx].cq0; next = idx->vertex_idx + 1; if (next == figure->vertex_count) next = 0; @@ -2769,8 +2795,15 @@ static BOOL d2d_geometry_split_bezier(struct d2d_geometry *geometry, const struc d2d_point_lerp(&q[1], p[1], p[2], 0.5f); d2d_point_lerp(&q[2], &q[0], &q[1], 0.5f);
- figure->bezier_controls[idx->control_idx] = q[0]; - if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &q[1]))) + d2d_bezier_quad_to_cubic(p[0], &q[0], &q[2], &c[0], &c[1]); + + figure->bezier_controls[idx->control_idx].cq0 = q[0]; + figure->bezier_controls[idx->control_idx].c0 = c[0]; + figure->bezier_controls[idx->control_idx].c1 = c[1]; + + d2d_bezier_quad_to_cubic(&q[0], &q[1], p[2], &c[0], &c[1]); + + if (!(d2d_figure_insert_bezier_control(figure, idx->control_idx + 1, &c[0], &c[1], &q[1]))) return FALSE; if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2]))) return FALSE; @@ -2841,7 +2874,7 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
figure = &geometry->u.path.figures[idx_p.figure_idx]; p[0] = &figure->vertices[idx_p.vertex_idx]; - p[1] = &figure->bezier_controls[idx_p.control_idx]; + p[1] = &figure->bezier_controls[idx_p.control_idx].cq0;
i = idx_p.vertex_idx + 1; if (d2d_path_geometry_point_inside(geometry, p[1], FALSE)) @@ -2940,6 +2973,7 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr { struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface); struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1]; + D2D1_POINT_2F p0, p1, p2, c[2]; unsigned int i;
TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count); @@ -2954,11 +2988,15 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr { D2D1_RECT_F bezier_bounds;
- d2d_rect_get_bezier_bounds(&bezier_bounds, &figure->vertices[figure->vertex_count - 1], - &beziers[i].point1, &beziers[i].point2); + p0 = figure->vertices[figure->vertex_count - 1]; + p1 = beziers[i].point1; + p2 = beziers[i].point2; + d2d_bezier_quad_to_cubic(&p0, &p1, &p2, &c[0], &c[1]); + + d2d_rect_get_bezier_bounds(&bezier_bounds, &p0, &p1, &p2);
figure->vertex_types[figure->vertex_count - 1] = D2D_VERTEX_TYPE_BEZIER; - if (!d2d_figure_add_bezier_control(figure, &beziers[i].point1)) + if (!d2d_figure_add_bezier_control(figure, &c[0], &c[1], &p1)) { ERR("Failed to add bezier.\n"); geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR; @@ -3165,7 +3203,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry * break;
case D2D_VERTEX_TYPE_BEZIER: - p1 = figure->original_bezier_controls[bezier_idx++]; + p1 = figure->original_bezier_controls[bezier_idx++].cq0; d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[j]; d2d_point_transform(&p2, transform, p2.x, p2.y); @@ -3187,7 +3225,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_GetBounds(ID2D1PathGeometry *
if (type == D2D_VERTEX_TYPE_BEZIER) { - p1 = figure->original_bezier_controls[bezier_idx++]; + p1 = figure->original_bezier_controls[bezier_idx++].cq0; d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[0]; d2d_point_transform(&p2, transform, p2.x, p2.y); @@ -3369,7 +3407,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i break;
case D2D_VERTEX_TYPE_BEZIER: - p1 = figure->original_bezier_controls[bezier_idx++]; + p1 = figure->original_bezier_controls[bezier_idx++].cq0; if (transform) d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[j]; @@ -3393,7 +3431,7 @@ static HRESULT STDMETHODCALLTYPE d2d_path_geometry_Simplify(ID2D1PathGeometry *i
if (type == D2D_VERTEX_TYPE_BEZIER) { - p1 = figure->original_bezier_controls[bezier_idx++]; + p1 = figure->original_bezier_controls[bezier_idx++].cq0; if (transform) d2d_point_transform(&p1, transform, p1.x, p1.y); p2 = figure->vertices[0];