d2d1: Split overlapping bezier control triangles.
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3895f07c4b
commit
2187a1edb3
|
@ -2641,9 +2641,138 @@ static BOOL d2d_geometry_get_next_bezier_segment_idx(struct d2d_geometry *geomet
|
|||
return d2d_geometry_get_bezier_segment_idx(geometry, idx, TRUE);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const D2D1_POINT_2F *a[3], *b[3], *p[2], *q;
|
||||
const struct d2d_figure *figure;
|
||||
D2D1_POINT_2F v_q[3], v_p, v_qp;
|
||||
unsigned int i, j, score;
|
||||
float det, t;
|
||||
|
||||
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];
|
||||
if (idx_p->vertex_idx == figure->vertex_count - 1)
|
||||
a[2] = &figure->vertices[0];
|
||||
else
|
||||
a[2] = &figure->vertices[idx_p->vertex_idx + 1];
|
||||
|
||||
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];
|
||||
if (idx_q->vertex_idx == figure->vertex_count - 1)
|
||||
b[2] = &figure->vertices[0];
|
||||
else
|
||||
b[2] = &figure->vertices[idx_q->vertex_idx + 1];
|
||||
|
||||
if (d2d_point_ccw(a[0], a[1], a[2]) == 0.0f || d2d_point_ccw(b[0], b[1], b[2]) == 0.0f)
|
||||
return FALSE;
|
||||
|
||||
d2d_point_subtract(&v_q[0], b[1], b[0]);
|
||||
d2d_point_subtract(&v_q[1], b[2], b[0]);
|
||||
d2d_point_subtract(&v_q[2], b[1], b[2]);
|
||||
|
||||
/* Check for intersections between the edges. Strictly speaking we'd only
|
||||
* need to check 8 of the 9 possible intersections, since if there's any
|
||||
* intersection there has to be a second intersection as well. */
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
d2d_point_subtract(&v_p, a[(i & 1) + 1], a[i & 2]);
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
det = v_p.x * v_q[j].y - v_p.y * v_q[j].x;
|
||||
if (det == 0.0f)
|
||||
continue;
|
||||
|
||||
d2d_point_subtract(&v_qp, a[i & 2], b[j & 2]);
|
||||
t = (v_q[j].x * v_qp.y - v_q[j].y * v_qp.x) / det;
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
continue;
|
||||
|
||||
t = (v_p.x * v_qp.y - v_p.y * v_qp.x) / det;
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
continue;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if one triangle is contained within the other. */
|
||||
for (j = 0, score = 0, q = a[1], p[0] = b[2]; j < 3; ++j)
|
||||
{
|
||||
p[1] = b[j];
|
||||
d2d_point_subtract(&v_p, p[1], p[0]);
|
||||
d2d_point_subtract(&v_qp, q, p[0]);
|
||||
|
||||
if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
|
||||
++score;
|
||||
|
||||
p[0] = p[1];
|
||||
}
|
||||
|
||||
if (score & 1)
|
||||
return TRUE;
|
||||
|
||||
for (j = 0, score = 0, q = b[1], p[0] = a[2]; j < 3; ++j)
|
||||
{
|
||||
p[1] = a[j];
|
||||
d2d_point_subtract(&v_p, p[1], p[0]);
|
||||
d2d_point_subtract(&v_qp, q, p[0]);
|
||||
|
||||
if ((q->y < p[0]->y) != (q->y < p[1]->y) && v_qp.x < v_p.x * (v_qp.y / v_p.y))
|
||||
++score;
|
||||
|
||||
p[0] = p[1];
|
||||
}
|
||||
|
||||
return score & 1;
|
||||
}
|
||||
|
||||
static float d2d_geometry_bezier_ccw(struct d2d_geometry *geometry, const struct d2d_segment_idx *idx)
|
||||
{
|
||||
const struct d2d_figure *figure = &geometry->u.path.figures[idx->figure_idx];
|
||||
size_t next = idx->vertex_idx + 1;
|
||||
|
||||
if (next == figure->vertex_count)
|
||||
next = 0;
|
||||
|
||||
return d2d_point_ccw(&figure->vertices[idx->vertex_idx],
|
||||
&figure->bezier_controls[idx->control_idx], &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];
|
||||
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];
|
||||
next = idx->vertex_idx + 1;
|
||||
if (next == figure->vertex_count)
|
||||
next = 0;
|
||||
p[2] = &figure->vertices[next];
|
||||
|
||||
d2d_point_lerp(&q[0], p[0], p[1], 0.5f);
|
||||
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])))
|
||||
return FALSE;
|
||||
if (!(d2d_figure_insert_vertex(figure, idx->vertex_idx + 1, q[2])))
|
||||
return FALSE;
|
||||
figure->vertex_types[idx->vertex_idx + 1] = D2D_VERTEX_TYPE_SPLIT_BEZIER;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
|
||||
{
|
||||
struct d2d_segment_idx idx_p;
|
||||
struct d2d_segment_idx idx_p, idx_q;
|
||||
struct d2d_bezier_vertex *b;
|
||||
const D2D1_POINT_2F *p[3];
|
||||
struct d2d_figure *figure;
|
||||
|
@ -2652,6 +2781,34 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
|
|||
if (!d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p))
|
||||
return S_OK;
|
||||
|
||||
/* Split overlapping bezier control triangles. */
|
||||
while (d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_p))
|
||||
{
|
||||
d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_q);
|
||||
while (idx_q.figure_idx < idx_p.figure_idx || idx_q.vertex_idx < idx_p.vertex_idx)
|
||||
{
|
||||
while (d2d_geometry_check_bezier_overlap(geometry, &idx_p, &idx_q))
|
||||
{
|
||||
if (fabsf(d2d_geometry_bezier_ccw(geometry, &idx_q)) > fabsf(d2d_geometry_bezier_ccw(geometry, &idx_p)))
|
||||
{
|
||||
if (!d2d_geometry_split_bezier(geometry, &idx_q))
|
||||
return E_OUTOFMEMORY;
|
||||
if (idx_p.figure_idx == idx_q.figure_idx)
|
||||
{
|
||||
++idx_p.vertex_idx;
|
||||
++idx_p.control_idx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!d2d_geometry_split_bezier(geometry, &idx_p))
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
d2d_geometry_get_next_bezier_segment_idx(geometry, &idx_q);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < geometry->u.path.figure_count; ++i)
|
||||
{
|
||||
geometry->fill.bezier_vertex_count += 3 * geometry->u.path.figures[i].bezier_control_count;
|
||||
|
@ -2666,6 +2823,7 @@ static HRESULT d2d_geometry_resolve_beziers(struct d2d_geometry *geometry)
|
|||
}
|
||||
|
||||
bezier_idx = 0;
|
||||
d2d_geometry_get_first_bezier_segment_idx(geometry, &idx_p);
|
||||
for (;;)
|
||||
{
|
||||
float sign = -1.0f;
|
||||
|
|
|
@ -5696,7 +5696,7 @@ static void test_bezier_intersect(void)
|
|||
"sQGRAbEBkAGyAZABsgGPAbMBjwG0AY4BtAGNAbUBjQG2AYwBtgGLAbgBigG4AYoBuQGJAboBhwG7"
|
||||
"AYcBvAGGAb0BhQG+AYQBvwGDAcABggHBAYIBwgGAAcMBf8QBfsYBfMgBe8gBesoBeMwBd80BddAB"
|
||||
"c9EBcdQBb9YBbNkBatsBaN0BZeEBYuQBX+gBW+0BVvEBUvUBTvwBR4QCQIoCOZgCK6oCGQIA");
|
||||
todo_wine ok(match, "Figure does not match.\n");
|
||||
ok(match, "Figure does not match.\n");
|
||||
|
||||
ID2D1SolidColorBrush_Release(brush);
|
||||
ID2D1RenderTarget_Release(rt);
|
||||
|
|
Loading…
Reference in New Issue