d2d1: Implement initial support for quadratic bezier outlines.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2017-05-21 17:53:43 +02:00 committed by Alexandre Julliard
parent 22bdde479f
commit bd2141e521
4 changed files with 725 additions and 2 deletions

View File

@ -41,6 +41,7 @@ enum d2d_brush_type
enum d2d_shape_type
{
D2D_SHAPE_TYPE_OUTLINE,
D2D_SHAPE_TYPE_BEZIER_OUTLINE,
D2D_SHAPE_TYPE_TRIANGLE,
D2D_SHAPE_TYPE_BEZIER,
D2D_SHAPE_TYPE_COUNT,
@ -315,6 +316,13 @@ struct d2d_outline_vertex
D2D1_POINT_2F next;
};
struct d2d_bezier_outline_vertex
{
D2D1_POINT_2F position;
D2D1_POINT_2F p0, p1, p2;
D2D1_POINT_2F prev, next;
};
struct d2d_geometry
{
ID2D1Geometry ID2D1Geometry_iface;
@ -346,6 +354,14 @@ struct d2d_geometry
struct d2d_face *faces;
size_t faces_size;
size_t face_count;
struct d2d_bezier_outline_vertex *beziers;
size_t beziers_size;
size_t bezier_count;
struct d2d_face *bezier_faces;
size_t bezier_faces_size;
size_t bezier_face_count;
} outline;
union

View File

@ -142,6 +142,18 @@ static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float
d2d_point_set(&v->next, next_x, next_y);
}
static void d2d_bezier_outline_vertex_set(struct d2d_bezier_outline_vertex *b, const D2D1_POINT_2F *position,
const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2,
float prev_x, float prev_y, float next_x, float next_y)
{
b->position = *position;
b->p0 = *p0;
b->p1 = *p1;
b->p2 = *p2;
d2d_point_set(&b->prev, prev_x, prev_y);
d2d_point_set(&b->next, next_x, next_y);
}
static void d2d_fp_two_sum(float *out, float a, float b)
{
float a_virt, a_round, b_virt, b_round;
@ -362,6 +374,13 @@ static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
p->y *= scale;
}
static void d2d_point_lerp(D2D1_POINT_2F *out,
const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, float t)
{
out->x = a->x * (1.0f - t) + b->x * t;
out->y = a->y * (1.0f - t) + b->y * t;
}
static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
{
return p0->x * p1->x + p0->y * p1->y;
@ -1842,6 +1861,70 @@ static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
return TRUE;
}
static BOOL d2d_geometry_outline_add_bezier_segment(struct d2d_geometry *geometry,
const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1, const D2D1_POINT_2F *p2)
{
struct d2d_bezier_outline_vertex *b;
D2D1_POINT_2F r0, r1, r2;
D2D1_POINT_2F q0, q1, q2;
struct d2d_face *f;
size_t base_idx;
if (!d2d_array_reserve((void **)&geometry->outline.beziers, &geometry->outline.beziers_size,
geometry->outline.bezier_count + 7, sizeof(*geometry->outline.beziers)))
{
ERR("Failed to grow outline beziers array.\n");
return FALSE;
}
base_idx = geometry->outline.bezier_count;
b = &geometry->outline.beziers[base_idx];
if (!d2d_array_reserve((void **)&geometry->outline.bezier_faces, &geometry->outline.bezier_faces_size,
geometry->outline.bezier_face_count + 5, sizeof(*geometry->outline.bezier_faces)))
{
ERR("Failed to grow outline faces array.\n");
return FALSE;
}
f = &geometry->outline.bezier_faces[geometry->outline.bezier_face_count];
d2d_point_lerp(&q0, p0, p1, 0.5f);
d2d_point_lerp(&q1, p1, p2, 0.5f);
d2d_point_lerp(&q2, &q0, &q1, 0.5f);
d2d_point_subtract(&r0, &q0, p0);
d2d_point_subtract(&r1, &q1, &q0);
d2d_point_subtract(&r2, p2, &q1);
d2d_point_normalise(&r0);
d2d_point_normalise(&r1);
d2d_point_normalise(&r2);
if (d2d_point_ccw(p0, p1, p2) > 0.0f)
{
d2d_point_scale(&r0, -1.0f);
d2d_point_scale(&r1, -1.0f);
d2d_point_scale(&r2, -1.0f);
}
d2d_bezier_outline_vertex_set(&b[0], p0, p0, p1, p2, r0.x, r0.y, r0.x, r0.y);
d2d_bezier_outline_vertex_set(&b[1], p0, p0, p1, p2, -r0.x, -r0.y, -r0.x, -r0.y);
d2d_bezier_outline_vertex_set(&b[2], &q0, p0, p1, p2, r0.x, r0.y, r1.x, r1.y);
d2d_bezier_outline_vertex_set(&b[3], &q2, p0, p1, p2, -r1.x, -r1.y, -r1.x, -r1.y);
d2d_bezier_outline_vertex_set(&b[4], &q1, p0, p1, p2, r1.x, r1.y, r2.x, r2.y);
d2d_bezier_outline_vertex_set(&b[5], p2, p0, p1, p2, -r2.x, -r2.y, -r2.x, -r2.y);
d2d_bezier_outline_vertex_set(&b[6], p2, p0, p1, p2, r2.x, r2.y, r2.x, r2.y);
geometry->outline.bezier_count += 7;
d2d_face_set(&f[0], base_idx + 0, base_idx + 1, base_idx + 2);
d2d_face_set(&f[1], base_idx + 2, base_idx + 1, base_idx + 3);
d2d_face_set(&f[2], base_idx + 3, base_idx + 4, base_idx + 2);
d2d_face_set(&f[3], base_idx + 5, base_idx + 4, base_idx + 3);
d2d_face_set(&f[4], base_idx + 5, base_idx + 6, base_idx + 4);
geometry->outline.bezier_face_count += 5;
return TRUE;
}
static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
{
@ -1894,6 +1977,21 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
ERR("Failed to add line segment.\n");
return FALSE;
}
else if (type == D2D_VERTEX_TYPE_BEZIER)
{
const D2D1_POINT_2F *p2;
if (i == figure->vertex_count - 1)
p2 = &figure->vertices[0];
else
p2 = &figure->vertices[i + 1];
if (!d2d_geometry_outline_add_bezier_segment(geometry, p0, next, p2))
{
ERR("Failed to add bezier segment.\n");
return FALSE;
}
}
}
return TRUE;
@ -1901,6 +1999,8 @@ static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
{
HeapFree(GetProcessHeap(), 0, geometry->outline.bezier_faces);
HeapFree(GetProcessHeap(), 0, geometry->outline.beziers);
HeapFree(GetProcessHeap(), 0, geometry->outline.faces);
HeapFree(GetProcessHeap(), 0, geometry->outline.vertices);
HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
@ -2925,6 +3025,8 @@ static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1Transformed
if (!refcount)
{
geometry->outline.bezier_faces = NULL;
geometry->outline.beziers = NULL;
geometry->outline.faces = NULL;
geometry->outline.vertices = NULL;
geometry->fill.bezier_vertices = NULL;

View File

@ -725,6 +725,36 @@ static void d2d_rt_draw_geometry(struct d2d_d3d_render_target *render_target,
ID3D10Buffer_Release(ib);
}
if (geometry->outline.bezier_face_count)
{
buffer_desc.ByteWidth = geometry->outline.bezier_face_count * sizeof(*geometry->outline.bezier_faces);
buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
buffer_data.pSysMem = geometry->outline.bezier_faces;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ib)))
{
WARN("Failed to create beziers index buffer, hr %#x.\n", hr);
goto done;
}
buffer_desc.ByteWidth = geometry->outline.bezier_count * sizeof(*geometry->outline.beziers);
buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
buffer_data.pSysMem = geometry->outline.beziers;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vb)))
{
ERR("Failed to create beziers vertex buffer, hr %#x.\n", hr);
ID3D10Buffer_Release(ib);
goto done;
}
d2d_rt_draw(render_target, D2D_SHAPE_TYPE_BEZIER_OUTLINE, ib, 3 * geometry->outline.bezier_face_count, vb,
sizeof(*geometry->outline.beziers), vs_cb, ps_cb, brush, NULL);
ID3D10Buffer_Release(vb);
ID3D10Buffer_Release(ib);
}
done:
ID3D10Buffer_Release(ps_cb);
ID3D10Buffer_Release(vs_cb);
@ -2031,6 +2061,15 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
static const D3D10_INPUT_ELEMENT_DESC il_desc_bezier_outline[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"P", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"P", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"P", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"PREV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"NEXT", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 40, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
static const D3D10_INPUT_ELEMENT_DESC il_desc_bezier[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
@ -2131,6 +2170,164 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6,
0x00000000, 0x0100003e,
};
/* ⎡p0.x p0.y 1⎤
* A = p1.x p1.y 1
* p2.x p2.y 1
*
* 0 0
* B = ½ 0
* 1 1
*
* A' = p1.x-p0.x p1.y-p0.y
* p2.x-p0.x p2.y-p0.y
*
* B' = ½ 0
* 1 1
*
* A'T = B'
* T = A'¹B'
*/
static const DWORD vs_code_bezier_outline[] =
{
#if 0
float3x2 transform_geometry;
float stroke_width;
float4 transform_rtx;
float4 transform_rty;
float4 main(float2 position : POSITION, float2 p0 : P0, float2 p1 : P1, float2 p2 : P2,
float2 prev : PREV, float2 next : NEXT, out float4 texcoord : UV,
out float2x2 stroke_transform : STROKE_TRANSFORM) : SV_POSITION
{
float2 q_prev, q_next, v_p, q_i, p;
float2x2 geom, rt;
float l;
geom = float2x2(transform_geometry._11_21, transform_geometry._12_22);
rt = float2x2(transform_rtx.xy, transform_rty.xy);
stroke_transform = rt * stroke_width * 0.5f;
p = mul(geom, position);
p0 = mul(geom, p0);
p1 = mul(geom, p1);
p2 = mul(geom, p2);
p -= p0;
p1 -= p0;
p2 -= p0;
q_prev = normalize(mul(geom, prev));
q_next = normalize(mul(geom, next));
v_p = float2(-q_prev.y, q_prev.x);
l = -dot(v_p, q_next) / (1.0f + dot(q_prev, q_next));
q_i = l * q_prev + v_p;
p += stroke_width * q_i;
v_p = normalize(float2(-p2.y, p2.x));
if (abs(dot(p1, v_p)) < 1.0f)
{
texcoord.xzw = float3(0.0f, 0.0f, 0.0f);
texcoord.y = dot(p, v_p);
}
else
{
texcoord.zw = sign(dot(p1, v_p)) * v_p;
v_p = -float2(-p.y, p.x) / dot(float2(-p1.y, p1.x), p2);
texcoord.x = dot(v_p, p1 - 0.5f * p2);
texcoord.y = dot(v_p, p1);
}
position = mul(geom, position)
+ float2(transform_geometry._31, transform_geometry._32) + stroke_width * q_i;
position = mul(rt, position) + float2(transform_rtx.z, transform_rty.z);
position = position * float2(transform_rtx.w, transform_rty.w) + float2(-1.0f, 1.0f);
return float4(position, 0.0f, 1.0f);
}
#endif
0x43425844, 0x411d8ea2, 0xae9762e9, 0x31a7c2d1, 0x529c1b7e, 0x00000001, 0x00000a04, 0x00000003,
0x0000002c, 0x000000e4, 0x00000174, 0x4e475349, 0x000000b0, 0x00000006, 0x00000008, 0x00000098,
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000303, 0x000000a1, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000303, 0x000000a1, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
0x00000303, 0x000000a1, 0x00000002, 0x00000000, 0x00000003, 0x00000003, 0x00000303, 0x000000a3,
0x00000000, 0x00000000, 0x00000003, 0x00000004, 0x00000303, 0x000000a8, 0x00000000, 0x00000000,
0x00000003, 0x00000005, 0x00000303, 0x49534f50, 0x4e4f4954, 0x50005000, 0x00564552, 0x5458454e,
0xababab00, 0x4e47534f, 0x00000088, 0x00000004, 0x00000008, 0x00000068, 0x00000000, 0x00000001,
0x00000003, 0x00000000, 0x0000000f, 0x00000074, 0x00000000, 0x00000000, 0x00000003, 0x00000001,
0x0000000f, 0x00000077, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000c03, 0x00000077,
0x00000001, 0x00000000, 0x00000003, 0x00000003, 0x00000c03, 0x505f5653, 0x5449534f, 0x004e4f49,
0x53005655, 0x4b4f5254, 0x52545f45, 0x46534e41, 0x004d524f, 0x52444853, 0x00000888, 0x00010040,
0x00000222, 0x04000059, 0x00208e46, 0x00000000, 0x00000004, 0x0300005f, 0x00101032, 0x00000000,
0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x00101032, 0x00000002, 0x0300005f, 0x00101032,
0x00000003, 0x0300005f, 0x00101032, 0x00000004, 0x0300005f, 0x00101032, 0x00000005, 0x04000067,
0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000001, 0x03000065, 0x00102032,
0x00000002, 0x03000065, 0x00102032, 0x00000003, 0x02000068, 0x00000004, 0x0800000f, 0x00100012,
0x00000000, 0x00208046, 0x00000000, 0x00000000, 0x00101046, 0x00000005, 0x0800000f, 0x00100022,
0x00000000, 0x00208046, 0x00000000, 0x00000001, 0x00101046, 0x00000005, 0x0700000f, 0x00100042,
0x00000000, 0x00100046, 0x00000000, 0x00100046, 0x00000000, 0x05000044, 0x00100042, 0x00000000,
0x0010002a, 0x00000000, 0x07000038, 0x00100032, 0x00000000, 0x00100aa6, 0x00000000, 0x00100046,
0x00000000, 0x0800000f, 0x00100012, 0x00000001, 0x00208046, 0x00000000, 0x00000000, 0x00101046,
0x00000004, 0x0800000f, 0x00100022, 0x00000001, 0x00208046, 0x00000000, 0x00000001, 0x00101046,
0x00000004, 0x0700000f, 0x00100042, 0x00000000, 0x00100046, 0x00000001, 0x00100046, 0x00000001,
0x05000044, 0x00100042, 0x00000000, 0x0010002a, 0x00000000, 0x07000038, 0x00100032, 0x00000001,
0x00100aa6, 0x00000000, 0x00100046, 0x00000001, 0x06000036, 0x001000c2, 0x00000001, 0x80100556,
0x00000041, 0x00000001, 0x0700000f, 0x00100042, 0x00000000, 0x00100a26, 0x00000001, 0x00100046,
0x00000000, 0x0700000f, 0x00100012, 0x00000000, 0x00100046, 0x00000001, 0x00100046, 0x00000000,
0x07000000, 0x00100012, 0x00000000, 0x0010000a, 0x00000000, 0x00004001, 0x3f800000, 0x0800000e,
0x00100012, 0x00000000, 0x8010002a, 0x00000041, 0x00000000, 0x0010000a, 0x00000000, 0x09000032,
0x00100032, 0x00000000, 0x00100006, 0x00000000, 0x00100046, 0x00000001, 0x00100f36, 0x00000001,
0x0800000f, 0x00100012, 0x00000001, 0x00208046, 0x00000000, 0x00000000, 0x00101046, 0x00000000,
0x08000000, 0x00100012, 0x00000002, 0x0010000a, 0x00000001, 0x0020802a, 0x00000000, 0x00000000,
0x0800000f, 0x00100022, 0x00000001, 0x00208046, 0x00000000, 0x00000001, 0x00101046, 0x00000000,
0x08000000, 0x00100022, 0x00000002, 0x0010001a, 0x00000001, 0x0020802a, 0x00000000, 0x00000001,
0x0a000032, 0x001000c2, 0x00000000, 0x00208ff6, 0x00000000, 0x00000001, 0x00100406, 0x00000000,
0x00100406, 0x00000002, 0x0800000f, 0x00100042, 0x00000001, 0x00208046, 0x00000000, 0x00000002,
0x00100ae6, 0x00000000, 0x0800000f, 0x00100042, 0x00000000, 0x00208046, 0x00000000, 0x00000003,
0x00100ae6, 0x00000000, 0x08000000, 0x00100042, 0x00000000, 0x0010002a, 0x00000000, 0x0020802a,
0x00000000, 0x00000003, 0x08000038, 0x00100022, 0x00000002, 0x0010002a, 0x00000000, 0x0020803a,
0x00000000, 0x00000003, 0x08000000, 0x00100042, 0x00000000, 0x0010002a, 0x00000001, 0x0020802a,
0x00000000, 0x00000002, 0x08000038, 0x00100012, 0x00000002, 0x0010002a, 0x00000000, 0x0020803a,
0x00000000, 0x00000002, 0x0a000000, 0x00102032, 0x00000000, 0x00100046, 0x00000002, 0x00004002,
0xbf800000, 0x3f800000, 0x00000000, 0x00000000, 0x08000036, 0x001020c2, 0x00000000, 0x00004002,
0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x0800000f, 0x00100012, 0x00000002, 0x00208046,
0x00000000, 0x00000000, 0x00101046, 0x00000001, 0x0800000f, 0x00100022, 0x00000002, 0x00208046,
0x00000000, 0x00000001, 0x00101046, 0x00000001, 0x08000000, 0x001000c2, 0x00000000, 0x00100406,
0x00000001, 0x80100406, 0x00000041, 0x00000002, 0x0a000032, 0x00100032, 0x00000000, 0x00208ff6,
0x00000000, 0x00000001, 0x00100046, 0x00000000, 0x00100ae6, 0x00000000, 0x06000036, 0x00100042,
0x00000000, 0x8010001a, 0x00000041, 0x00000000, 0x0800000f, 0x00100012, 0x00000001, 0x00208046,
0x00000000, 0x00000000, 0x00101046, 0x00000002, 0x0800000f, 0x00100022, 0x00000001, 0x00208046,
0x00000000, 0x00000001, 0x00101046, 0x00000002, 0x08000000, 0x00100032, 0x00000001, 0x80100046,
0x00000041, 0x00000002, 0x00100046, 0x00000001, 0x06000036, 0x00100042, 0x00000001, 0x8010001a,
0x00000041, 0x00000001, 0x0800000f, 0x00100012, 0x00000003, 0x00208046, 0x00000000, 0x00000000,
0x00101046, 0x00000003, 0x0800000f, 0x00100022, 0x00000003, 0x00208046, 0x00000000, 0x00000001,
0x00101046, 0x00000003, 0x08000000, 0x00100032, 0x00000002, 0x80100046, 0x00000041, 0x00000002,
0x00100046, 0x00000003, 0x0700000f, 0x00100082, 0x00000000, 0x00100a26, 0x00000001, 0x00100046,
0x00000002, 0x0800000e, 0x001000c2, 0x00000000, 0x801002a6, 0x00000041, 0x00000000, 0x00100ff6,
0x00000000, 0x0d000032, 0x001000c2, 0x00000001, 0x80100406, 0x00000041, 0x00000002, 0x00004002,
0x00000000, 0x00000000, 0x3f000000, 0x3f000000, 0x00100406, 0x00000001, 0x0700000f, 0x00100012,
0x00000003, 0x00100ae6, 0x00000000, 0x00100ae6, 0x00000001, 0x0700000f, 0x00100022, 0x00000003,
0x00100ae6, 0x00000000, 0x00100046, 0x00000001, 0x06000036, 0x001000c2, 0x00000002, 0x80100556,
0x00000041, 0x00000002, 0x0700000f, 0x00100042, 0x00000000, 0x00100086, 0x00000002, 0x001000c6,
0x00000002, 0x0a000038, 0x001000c2, 0x00000001, 0x00100156, 0x00000002, 0x00004002, 0x00000000,
0x00000000, 0xbf800000, 0x3f800000, 0x05000044, 0x00100042, 0x00000000, 0x0010002a, 0x00000000,
0x07000038, 0x001000c2, 0x00000000, 0x00100aa6, 0x00000000, 0x00100ea6, 0x00000001, 0x0700000f,
0x00100022, 0x00000002, 0x00100046, 0x00000000, 0x00100ae6, 0x00000000, 0x08000036, 0x001000d2,
0x00000002, 0x00004002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0700000f, 0x00100012,
0x00000000, 0x00100046, 0x00000001, 0x00100ae6, 0x00000000, 0x07000031, 0x00100022, 0x00000000,
0x00004001, 0x00000000, 0x0010000a, 0x00000000, 0x07000031, 0x00100012, 0x00000001, 0x0010000a,
0x00000000, 0x00004001, 0x00000000, 0x08000031, 0x00100012, 0x00000000, 0x8010000a, 0x00000081,
0x00000000, 0x00004001, 0x3f800000, 0x0800001e, 0x00100022, 0x00000000, 0x8010001a, 0x00000041,
0x00000000, 0x0010000a, 0x00000001, 0x0500002b, 0x00100022, 0x00000000, 0x0010001a, 0x00000000,
0x07000038, 0x001000c2, 0x00000003, 0x00100ea6, 0x00000000, 0x00100556, 0x00000000, 0x09000037,
0x001020f2, 0x00000001, 0x00100006, 0x00000000, 0x00100e46, 0x00000002, 0x00100e46, 0x00000003,
0x06000036, 0x00100032, 0x00000000, 0x00208046, 0x00000000, 0x00000002, 0x06000036, 0x001000c2,
0x00000000, 0x00208406, 0x00000000, 0x00000003, 0x08000038, 0x001000f2, 0x00000000, 0x00100e46,
0x00000000, 0x00208ff6, 0x00000000, 0x00000001, 0x0a000038, 0x001000f2, 0x00000000, 0x00100e46,
0x00000000, 0x00004002, 0x3f000000, 0x3f000000, 0x3f000000, 0x3f000000, 0x05000036, 0x00102032,
0x00000002, 0x00100086, 0x00000000, 0x05000036, 0x00102032, 0x00000003, 0x001005d6, 0x00000000,
0x0100003e,
};
static const DWORD vs_code_bezier[] =
{
#if 0
@ -2361,6 +2558,59 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
0x00000000, 0x00000001, 0x0010003a, 0x00000001, 0x07000038, 0x001020f2, 0x00000000, 0x00100006,
0x00000000, 0x00100e46, 0x00000001, 0x0100003e,
};
/* Evaluate the implicit form of the curve (u² - v = 0) in texture space,
* using the screen-space partial derivatives to convert the calculated
* distance to object space.
*
* d(x, y) = |f(x, y)| / f(x, y)
* = |f(x, y)| / ((f/x)² + (f/y)²)
* f(x, y) = u(x, y)² - v(x, y)
* f/x = 2u · u/x - v/x
* f/y = 2u · u/y - v/y */
static const DWORD ps_code_bezier_solid_outline[] =
{
#if 0
float4 color;
float4 main(float4 position : SV_POSITION, float4 uv : UV,
nointerpolation float2x2 stroke_transform : STROKE_TRANSFORM) : SV_Target
{
float2 du, dv, df;
du = float2(ddx(uv.x), ddy(uv.x));
dv = float2(ddx(uv.y), ddy(uv.y));
df = 2.0f * uv.x * du - dv;
clip(dot(df, uv.zw));
clip(length(mul(stroke_transform, df)) - abs(uv.x * uv.x - uv.y));
return color;
}
#endif
0x43425844, 0x9da521d4, 0x4c86449e, 0x4f2c1641, 0x6f798508, 0x00000001, 0x000002f4, 0x00000003,
0x0000002c, 0x000000bc, 0x000000f0, 0x4e475349, 0x00000088, 0x00000004, 0x00000008, 0x00000068,
0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x00000074, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000f0f, 0x00000077, 0x00000000, 0x00000000, 0x00000003, 0x00000002,
0x00000303, 0x00000077, 0x00000001, 0x00000000, 0x00000003, 0x00000003, 0x00000303, 0x505f5653,
0x5449534f, 0x004e4f49, 0x53005655, 0x4b4f5254, 0x52545f45, 0x46534e41, 0x004d524f, 0x4e47534f,
0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x000001fc, 0x00000040, 0x0000007f,
0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03001062, 0x001010f2, 0x00000001, 0x03000862,
0x00101032, 0x00000002, 0x03000862, 0x00101032, 0x00000003, 0x03000065, 0x001020f2, 0x00000000,
0x02000068, 0x00000002, 0x0500000b, 0x00100032, 0x00000000, 0x00101046, 0x00000001, 0x0500000c,
0x001000c2, 0x00000000, 0x00101406, 0x00000001, 0x07000000, 0x00100012, 0x00000001, 0x0010100a,
0x00000001, 0x0010100a, 0x00000001, 0x0a000032, 0x00100032, 0x00000000, 0x00100006, 0x00000001,
0x00100086, 0x00000000, 0x801005d6, 0x00000041, 0x00000000, 0x0700000f, 0x00100042, 0x00000000,
0x00100046, 0x00000000, 0x00101ae6, 0x00000001, 0x07000031, 0x00100042, 0x00000000, 0x0010002a,
0x00000000, 0x00004001, 0x00000000, 0x0304000d, 0x0010002a, 0x00000000, 0x07000038, 0x00100062,
0x00000000, 0x00100556, 0x00000000, 0x00101106, 0x00000003, 0x09000032, 0x00100032, 0x00000000,
0x00101046, 0x00000002, 0x00100006, 0x00000000, 0x00100596, 0x00000000, 0x0700000f, 0x00100012,
0x00000000, 0x00100046, 0x00000000, 0x00100046, 0x00000000, 0x0500004b, 0x00100012, 0x00000000,
0x0010000a, 0x00000000, 0x0a000032, 0x00100022, 0x00000000, 0x0010100a, 0x00000001, 0x0010100a,
0x00000001, 0x8010101a, 0x00000041, 0x00000001, 0x08000000, 0x00100012, 0x00000000, 0x8010001a,
0x000000c1, 0x00000000, 0x0010000a, 0x00000000, 0x07000031, 0x00100012, 0x00000000, 0x0010000a,
0x00000000, 0x00004001, 0x00000000, 0x0304000d, 0x0010000a, 0x00000000, 0x06000036, 0x001020f2,
0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
};
/* The basic idea here is to evaluate the implicit form of the curve in
* texture space. "t.z" determines which side of the curve is shaded. */
static const DWORD ps_code_bezier_solid[] =
@ -2400,7 +2650,7 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
{ps_code_triangle_solid, sizeof(ps_code_triangle_solid),
D2D_SHAPE_TYPE_TRIANGLE, D2D_BRUSH_TYPE_SOLID, D2D_BRUSH_TYPE_COUNT},
{ps_code_triangle_solid_bitmap, sizeof(ps_code_triangle_solid_bitmap),
D2D_SHAPE_TYPE_TRIANGLE, D2D_BRUSH_TYPE_SOLID, D2D_BRUSH_TYPE_BITMAP},
D2D_SHAPE_TYPE_TRIANGLE, D2D_BRUSH_TYPE_SOLID, D2D_BRUSH_TYPE_BITMAP},
{ps_code_triangle_bitmap, sizeof(ps_code_triangle_bitmap),
D2D_SHAPE_TYPE_TRIANGLE, D2D_BRUSH_TYPE_BITMAP, D2D_BRUSH_TYPE_COUNT},
{ps_code_triangle_bitmap_solid, sizeof(ps_code_triangle_bitmap_solid),
@ -2409,6 +2659,8 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
D2D_SHAPE_TYPE_TRIANGLE, D2D_BRUSH_TYPE_BITMAP, D2D_BRUSH_TYPE_BITMAP},
{ps_code_bezier_solid, sizeof(ps_code_bezier_solid),
D2D_SHAPE_TYPE_BEZIER, D2D_BRUSH_TYPE_SOLID, D2D_BRUSH_TYPE_COUNT},
{ps_code_bezier_solid_outline, sizeof(ps_code_bezier_solid_outline),
D2D_SHAPE_TYPE_BEZIER_OUTLINE, D2D_BRUSH_TYPE_SOLID, D2D_BRUSH_TYPE_COUNT},
};
static const struct
{
@ -2501,6 +2753,15 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
goto err;
}
if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc_bezier_outline,
sizeof(il_desc_bezier_outline) / sizeof(*il_desc_bezier_outline),
vs_code_bezier_outline, sizeof(vs_code_bezier_outline),
&render_target->shape_resources[D2D_SHAPE_TYPE_BEZIER_OUTLINE].il)))
{
WARN("Failed to create bezier outline input layout, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc_bezier,
sizeof(il_desc_bezier) / sizeof(*il_desc_bezier), vs_code_bezier, sizeof(vs_code_bezier),
&render_target->shape_resources[D2D_SHAPE_TYPE_BEZIER].il)))
@ -2516,6 +2777,13 @@ static HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_t
goto err;
}
if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device, vs_code_bezier_outline,
sizeof(vs_code_bezier_outline), &render_target->shape_resources[D2D_SHAPE_TYPE_BEZIER_OUTLINE].vs)))
{
WARN("Failed to create bezier outline vertex shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device, vs_code_triangle,
sizeof(vs_code_triangle), &render_target->shape_resources[D2D_SHAPE_TYPE_TRIANGLE].vs)))
{

View File

@ -3671,7 +3671,7 @@ static void test_gradient(void)
static void test_draw_geometry(void)
{
ID2D1TransformedGeometry *transformed_geometry[3];
ID2D1TransformedGeometry *transformed_geometry[4];
ID2D1RectangleGeometry *rect_geometry[2];
D2D1_POINT_2F point = {0.0f, 0.0f};
ID2D1SolidColorBrush *brush;
@ -4061,6 +4061,343 @@ static void test_draw_geometry(void)
"tAIKtgIJuAIHugIEvQIC82IA");
ok(match, "Figure does not match.\n");
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
set_point(&point, 20.0f, 80.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 40.0f, 80.0f, 60.0f, 80.0f);
quadratic_to(sink, 60.0f, 160.0f, 60.0f, 240.0f);
quadratic_to(sink, 40.0f, 240.0f, 20.0f, 240.0f);
quadratic_to(sink, 20.0f, 160.0f, 20.0f, 80.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 100.0f, 80.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 105.0f, 80.0f, 140.0f, 80.0f);
quadratic_to(sink, 140.0f, 100.0f, 140.0f, 240.0f);
quadratic_to(sink, 135.0f, 240.0f, 100.0f, 240.0f);
quadratic_to(sink, 100.0f, 220.0f, 100.0f, 80.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 180.0f, 80.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 215.0f, 80.0f, 220.0f, 80.0f);
quadratic_to(sink, 220.0f, 220.0f, 220.0f, 240.0f);
quadratic_to(sink, 185.0f, 240.0f, 180.0f, 240.0f);
quadratic_to(sink, 180.0f, 100.0f, 180.0f, 80.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 260.0f, 80.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 280.0f, 80.0f, 300.0f, 80.0f);
quadratic_to(sink, 300.0f, 160.0f, 300.0f, 240.0f);
quadratic_to(sink, 280.0f, 240.0f, 260.0f, 240.0f);
quadratic_to(sink, 260.0f, 160.0f, 260.0f, 80.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 20.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 40.0f, 420.0f, 60.0f, 400.0f);
quadratic_to(sink, 55.0f, 480.0f, 60.0f, 560.0f);
quadratic_to(sink, 40.0f, 540.0f, 20.0f, 560.0f);
quadratic_to(sink, 25.0f, 480.0f, 20.0f, 400.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 100.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 105.0f, 420.0f, 140.0f, 400.0f);
quadratic_to(sink, 135.0f, 420.0f, 140.0f, 560.0f);
quadratic_to(sink, 135.0f, 540.0f, 100.0f, 560.0f);
quadratic_to(sink, 105.0f, 540.0f, 100.0f, 400.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 180.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 215.0f, 420.0f, 220.0f, 400.0f);
quadratic_to(sink, 215.0f, 540.0f, 220.0f, 560.0f);
quadratic_to(sink, 185.0f, 540.0f, 180.0f, 560.0f);
quadratic_to(sink, 185.0f, 420.0f, 180.0f, 400.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 260.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 280.0f, 420.0f, 300.0f, 400.0f);
quadratic_to(sink, 295.0f, 480.0f, 300.0f, 560.0f);
quadratic_to(sink, 280.0f, 540.0f, 260.0f, 560.0f);
quadratic_to(sink, 265.0f, 480.0f, 260.0f, 400.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 20.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 40.0f, 700.0f, 60.0f, 720.0f);
quadratic_to(sink, 65.0f, 800.0f, 60.0f, 880.0f);
quadratic_to(sink, 40.0f, 900.0f, 20.0f, 880.0f);
quadratic_to(sink, 15.0f, 800.0f, 20.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 100.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 105.0f, 700.0f, 140.0f, 720.0f);
quadratic_to(sink, 145.0f, 740.0f, 140.0f, 880.0f);
quadratic_to(sink, 135.0f, 900.0f, 100.0f, 880.0f);
quadratic_to(sink, 95.0f, 860.0f, 100.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 180.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 215.0f, 700.0f, 220.0f, 720.0f);
quadratic_to(sink, 225.0f, 860.0f, 220.0f, 880.0f);
quadratic_to(sink, 185.0f, 900.0f, 180.0f, 880.0f);
quadratic_to(sink, 175.0f, 740.0f, 180.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 260.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, 280.0f, 700.0f, 300.0f, 720.0f);
quadratic_to(sink, 305.0f, 800.0f, 300.0f, 880.0f);
quadratic_to(sink, 280.0f, 900.0f, 260.0f, 880.0f);
quadratic_to(sink, 255.0f, 800.0f, 260.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
ID2D1RenderTarget_BeginDraw(rt);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)geometry, (ID2D1Brush *)brush, 10.0f, NULL);
hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr);
ID2D1PathGeometry_Release(geometry);
match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 0,
"vi5kPGQ8ZDxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8ZDxkPGQ8ZDxk3i8A");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 0, 160, 160, 0xff652e89, 0,
"vi5kPGQ8ZDxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8ZDxkPGQ8ZDxk3i8A");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 0, 160, 160, 0xff652e89, 0,
"vi5kPGQ8ZDxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8ZDxkPGQ8ZDxk3i8A");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 0, 160, 160, 0xff652e89, 0,
"yC5aRlpGWjxkPGQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8"
"FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwU"
"PBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8FDwUPBQ8ZDxkPGQ8ZDxk3i8A");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 0, 160, 160, 160, 0xff652e89, 64,
"3SoDYAM6B1gHOgtQCzoPSA87EkASPBc2FzwcLBw8IiAiPWI+Yj5iPhQBOAEUPhQKJgoUPxQ4FEAU"
"OBRAFDgUQBQ4FEAUOBRBFDYUQhQ2FEIUNhRCFDYUQhQ2FEIUNhRDFDQURBQ0FEQUNBREFDQURBQ0"
"FEQUNBREFDQURBQ0FEQUNBREFDQURRQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIU"
"RhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRG"
"FDIURRQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEMUNhRCFDYUQhQ2FEIU"
"NhRCFDYUQhQ2FEEUOBRAFDgUQBQ4FEAUOBRAFDgUPxQKJgoUPhQBOAEUPmI+Yj5iPSIgIjwcLBw8"
"FzYXPBJAEjsPSA86C1ALOgdYBzoDYAPdKgAA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 160, 160, 160, 0xff652e89, 1024,
"uxUBnwECngEDnQEEnAEFmwEGmwEGmgEHmQEImAEJlwEKlgELlQEMlQEMlAENkwEOkgEPkQEQkAER"
"VQQ2Ek0KOBJFEDkTPRY6FDUcOxUrJDwYHi09Yj5iP2BAQwkUQDgUFEAUOBRAFDcUQRQ3FEEUNxRC"
"FDYUQhQ2FEIUNhRCFDUUQxQ1FEMUNRRDFDUUQxQ1FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQU"
"NBREFDQURBQ0FEQUNBRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQ0"
"FEQUNBRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQ0FEQUNBREFDQU"
"RBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNRRDFDUUQxQ1FEMUNRRDFDUUQhQ2FEIUNhRC"
"FDYUQhQ3FEEUNxRBFDcUQBQ4FEAUFDhAFAlDQGA/Yj5iPS0eGDwkKxU7HDUUOhY9EzkQRRI4Ck0S"
"NgRVEZABEJEBD5IBDpMBDZQBDJUBDJUBC5YBCpcBCZgBCJkBB5oBBpsBBpsBBZwBBJ0BA54BAp8B"
"AbsV");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 160, 160, 160, 0xff652e89, 1024,
"pBYBngECnQEDnAEEmwEFmgEGmQEGmQEHmAEIlwEJlgEKlQELlAEMkwEMkwENkgEOkQEPkAEQNgRV"
"ETcKTRI4EEUSOhY9EzscNRQ8JCsVPS0eGD5iPmI/YEAUCUNAFBQ4QBQ4FEEUNxRBFDcUQRQ3FEEU"
"NhRCFDYUQhQ2FEMUNRRDFDUUQxQ1FEMUNRRDFDUUQxQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0"
"FEQUNBREFDQURBQ0FEQUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxREFDQU"
"RBQ0FEQUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxREFDQURBQ0FEQUNBRE"
"FDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQUQxQ1FEMUNRRDFDUUQxQ1FEMUNRRDFDYUQhQ2FEIU"
"NhRBFDcUQRQ3FEEUNxRBFDgUQDgUFEBDCRRAYD9iPmI+GB4tPRUrJDwUNRw7Ez0WOhJFEDgSTQo3"
"EVUENhCQAQ+RAQ6SAQ2TAQyTAQyUAQuVAQqWAQmXAQiYAQeZAQaZAQaaAQWbAQScAQOdAQKeAQGk"
"FgAA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 160, 160, 160, 0xff652e89, 64,
"wCsDmQEHlQELkQEPSwJAEkgLNhc8HCwcPCIgIj1iPmI+Yj4UATgBFD4UCiYKFD8UOBRAFDgUQBQ4"
"FEAUOBRAFDgUQRQ2FEIUNhRCFDYUQhQ2FEIUNhRCFDYUQxQ0FEQUNBREFDQURBQ0FEQUNBREFDQU"
"RBQ0FEQUNBREFDQURBQ0FEUUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRG"
"FDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEUU"
"NBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBRDFDYUQhQ2FEIUNhRCFDYUQhQ2"
"FEIUNhRBFDgUQBQ4FEAUOBRAFDgUQBQ4FD8UCiYKFD4UATgBFD5iPmI+Yj0iICI8HCwcPBc2FzwS"
"QBI7D0gPOgtQCzoHWAc6A2AD3SoA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 0, 320, 160, 160, 0xff652e89, 64,
"3SkmcThiRFdOTVhEICAgPhwsHDwXNhc8FDwUOxQ+FDoUPhQ6FD4UOhQ+FDoUPhQ5FEAUOBRAFDgU"
"QBQ4FEAUOBRAFDcUQhQ2FEIUNhRCFDYUQhQ2FEIUNhRCFDUURBQ0FEQUNBREFDQURBQ0FEQUNBRE"
"FDQURBQ0FEQUNBREFDQURBQzFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYU"
"MhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQz"
"FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNRRCFDYUQhQ2FEIUNhRCFDYU"
"QhQ2FEIUNxRAFDgUQBQ4FEAUOBRAFDgUQBQ5FD4UOhQ+FDoUPhQ6FD4UOhQ+FDsUPBQ8FzYXPBws"
"HD4gICBEWE1OV0RiOHEm3SkA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 320, 160, 160, 0xff652e89, 1024,
"zykoczhkRVhQTlpEFx4tPRUrJDwUNRw7FDwVOxQ+FDoUPhQ5FEAUOBRAFDgUQBQ4FEAUOBRBFDcU"
"QRQ3FEEUNhRCFDYUQhQ2FEIUNhRDFDUUQxQ1FEMUNRRDFDUUQxQ0FEQUNBREFDQURBQ0FEQUNBRE"
"FDQURBQ0FEQUNBREFDQURBQ0FEQUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUU"
"MxRFFDMURBQ0FEQUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURBQ0"
"FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEMUNRRDFDUUQxQ1FEMUNRRDFDYU"
"QhQ2FEIUNhRCFDYUQRQ3FEEUNxRBFDgUQBQ4FEAUOBRAFDgUQBQ5FD4UOhQ+FDsVPBQ7HDUUPCQr"
"FT0tHhdEWk5QWEVkOHMozykA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 320, 160, 160, 0xff652e89, 1024,
"6SkobThfRVNQSFpALR4XPSQrFTscNRQ7FTwUOhQ+FDoUPhQ5FEAUOBRAFDgUQBQ4FEAUNxRBFDcU"
"QRQ3FEEUNxRCFDYUQhQ2FEIUNRRDFDUUQxQ1FEMUNRRDFDUUQxQ1FEQUNBREFDQURBQ0FEQUNBRE"
"FDQURBQ0FEQUNBREFDQURBQ0FEQUNBRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUU"
"MxRFFDQURBQ0FEQUNBRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDMURRQzFEUUMxRFFDQURBQ0"
"FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ1FEMUNRRDFDUUQxQ1FEMUNRRDFDUU"
"QhQ2FEIUNhRCFDcUQRQ3FEEUNxRBFDcUQBQ4FEAUOBRAFDgUQBQ5FD4UOhQ+FDoUPBU7FDUcOxUr"
"JD0XHi1AWkhQU0VfOG0o6SkA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 320, 160, 160, 0xff652e89, 64,
"3SkmcThiRFdOTVhGHiAgRhQsHDwXNhc8FDwUOxQ+FDoUPhQ6FD4UOhQ+FDoUPhQ5FEAUOBRAFDgU"
"QBQ4FEAUOBRAFDcUQhQ2FEIUNhRCFDYUQhQ2FEIUNhRCFDUURBQ0FEQUNBREFDQURBQ0FEQUNBRE"
"FDQURBQ0FEQUNBREFDQURBQzFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYU"
"MhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQyFEYUMhRGFDIURhQz"
"FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNBREFDQURBQ0FEQUNRRCFDYUQhQ2FEIUNhRCFDYU"
"QhQ2FEIUNxRAFDgUQBQ4FEAUOBRAFDgUQBQ5FD4UOhQ+FDoUPhQ6FD4UOhQ+FDsUPBQ8FzYXPBws"
"HD4gICBEWE1OV0RiOHEm3SkA");
ok(match, "Figure does not match.\n");
hr = ID2D1Factory_CreatePathGeometry(factory, &geometry);
ok(SUCCEEDED(hr), "Failed to create path geometry, hr %#x.\n", hr);
hr = ID2D1PathGeometry_Open(geometry, &sink);
ok(SUCCEEDED(hr), "Failed to open geometry sink, hr %#x.\n", hr);
set_point(&point, -0.402914f, 0.915514f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_HOLLOW);
quadratic_to(sink, -0.310379f, 0.882571f, -0.116057f, 0.824000f);
quadratic_to(sink, 0.008350f, 0.693614f, -0.052343f, 0.448886f);
quadratic_to(sink, -0.154236f, 0.246072f, -0.279229f, 0.025343f);
quadratic_to(sink, -0.370064f, -0.588586f, -0.383029f, -0.924114f);
quadratic_to(sink, -0.295479f, -0.958764f, -0.017086f, -0.988400f);
quadratic_to(sink, 0.208836f, -0.954157f, 0.272200f, -0.924114f);
quadratic_to(sink, 0.295614f, -0.569071f, 0.230143f, 0.022886f);
quadratic_to(sink, 0.101664f, 0.220643f, 0.012057f, 0.451571f);
quadratic_to(sink, -0.028764f, 0.709014f, 0.104029f, 0.833943f);
quadratic_to(sink, 0.319414f, 0.913057f, 0.403229f, 0.942628f);
quadratic_to(sink, 0.317721f, 1.023450f, -0.017086f, 1.021771f);
quadratic_to(sink, -0.310843f, 1.007472f, -0.402914f, 0.915514f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
ID2D1GeometrySink_Release(sink);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 40.0f, 160.0f);
scale_matrix(&matrix, 20.0f, 80.0f);
hr = ID2D1Factory_CreateTransformedGeometry(factory,
(ID2D1Geometry *)geometry, &matrix, &transformed_geometry[0]);
ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr);
set_matrix_identity(&matrix);
translate_matrix(&matrix, 160.0f, 640.0f);
scale_matrix(&matrix, 40.0f, 160.0f);
rotate_matrix(&matrix, M_PI / -5.0f);
hr = ID2D1Factory_CreateTransformedGeometry(factory,
(ID2D1Geometry *)geometry, &matrix, &transformed_geometry[1]);
ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr);
ID2D1PathGeometry_Release(geometry);
set_matrix_identity(&matrix);
scale_matrix(&matrix, 0.5f, 1.0f);
translate_matrix(&matrix, -80.0f, 0.0f);
hr = ID2D1Factory_CreateTransformedGeometry(factory,
(ID2D1Geometry *)transformed_geometry[1], &matrix, &transformed_geometry[2]);
ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr);
set_matrix_identity(&matrix);
rotate_matrix(&matrix, M_PI / 2.0f);
translate_matrix(&matrix, 80.0f, -320.0f);
scale_matrix(&matrix, 2.0f, 0.25f);
hr = ID2D1Factory_CreateTransformedGeometry(factory,
(ID2D1Geometry *)transformed_geometry[2], &matrix, &transformed_geometry[3]);
ok(SUCCEEDED(hr), "Failed to create geometry, hr %#x.\n", hr);
ID2D1RenderTarget_BeginDraw(rt);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)transformed_geometry[0], (ID2D1Brush *)brush, 2.0f, NULL);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)transformed_geometry[1], (ID2D1Brush *)brush, 10.0f, NULL);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)transformed_geometry[2], (ID2D1Brush *)brush, 5.0f, NULL);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)transformed_geometry[3], (ID2D1Brush *)brush, 15.0f, NULL);
hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr);
ID2D1TransformedGeometry_Release(transformed_geometry[3]);
ID2D1TransformedGeometry_Release(transformed_geometry[2]);
ID2D1TransformedGeometry_Release(transformed_geometry[1]);
ID2D1TransformedGeometry_Release(transformed_geometry[0]);
match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 128,
"yjIJkQEHBwaIAQUSBYMBBBYEggEEFgSCAQQWBIIBBBYEggEEFgSCAQQWBIIBBBYEggEEFgSCAQQW"
"BIIBBBYEggEEFgSDAQQVBIMBBBUEgwEEFQSDAQQVBIMBBBUEgwEEFQSDAQQVBIMBBBUEgwEEFQSD"
"AQQVBIQBBBQEhAEEFASEAQQTBIUBBBMEhQEEEwSFAQQTBIUBBBMEhQEEEwSGAQQSBIYBBBIEhgEE"
"EgSGAQQSBIYBBBIEhgEEEgSGAQQRBIgBBBAEiAEEEASIAQQQBIkBBA4EigEEDgSLAQQMBIwBBAwE"
"jQEECgSOAQQJBJABBAgEkAEFBgSSAQQGBJMBBAQElAEEBASVAQQDBJUBBAIElwEEAQSXAQiZAQeZ"
"AQaaAQaaAQaaAQabAQWbAQWbAQWbAQWaAQeZAQeZAQeZAQiXAQQBBJYBBAMElQEEAwWRAQUGBY0B"
"BQwFhwEFEgSCAQUXBYABBBoFfgUYBIIBBhEFiAEUpTEA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 0, 320, 160, 0xff652e89, 512,
"yJIBArkCDa4CGKMCIZoCK5ECM4gCO4ECQ/gBS/EBUesBLAYl5QEsDiPeASwWIdkBLBwh0wEsISHO"
"ASsgKMsBKR4vyAEnHDPIASUaNMsBIxg1mQEFMCIUN54BCygiDzijAREhIgY9qAEYGWGuAR4RXbMB"
"JAhbuQGAAcABesYBc84Ba9YBTvQBP4MCOIoCNI4CM5ACMZICL5QCLZYCK5kCKJsCJ54CI6MCHq8C"
"EraSAQAA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 0, 160, 160, 320, 0xff652e89, 256,
"xWkCmwEFmAEJlQELlAENkgEOkQEPjwESjQETjAEVigELAQqJAQsCCogBCwQKhwEKBQqGAQoGCoYB"
"CgcKhAEKCAqEAQoIC4IBCgoKggEKCgqBAQoMCoABCgwKfwoNCn8KDgp9Cg8KfQoPCnwKEQp7ChEK"
"egoSCnoKEwp4ChQKeAoUCncLFQp2ChYKdgoWCnYKFwp2ChYKdgoWCncKFgp2ChYKdgoWCncKFQt2"
"ChYKdwoVCncKFQp4ChUKdwoVCncKFQp4ChUKdwoVCngKFAp4ChUKeAoUCngKFAp4CxMKeQoUCngK"
"FAp5ChMKeQoUCnkKEwp5ChMKegoSC3kKEwp6ChIKegoSCnoLEgp6ChIKegoSCnsKEQp7ChEKfAoQ"
"CnwKEAp9Cg8KfQoPCn4KDgp+Cg4KfwoOCn4KDgp/Cg0KfwoNCoABCgwKgAEKDAqBAQoLCoEBCgsK"
"gQELCgqCAQoKCoIBCwkKgwEKCQqDAQoJCoQBCggKhAEKCQqEAQsHCoUBCwYKhgELBQqHAQsECogB"
"CwMKiQELAgqLAQoBCowBFI0BE44BE44BEo8BEZABEJEBD5IBDpMBDpMBDZMBDZQBDJQBDZQBDJQB"
"DBUCfgwSBH4MEQV/DA4GgAEMDAiAAQ0KCYEBDAgLgQENBQ2BAQ0EDoIBDQEPgwEdgwEdgwEdgwEc"
"hAEKAgQCCoUBCgYKhgEKBgqGAQoFC4YBCgUKhwEKBAqIAQoECogBCgMKiQEKAwqIAQoDCokBCgMK"
"iQEKAgqJAQoCCooBCgIKiQEKAgqKAQoBCosBCgEKigEKAQqLARSMARSLARSMAROMARONARKOARGO"
"ARGPARCQAQ6RAQ2YAQTEZAAA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 160, 320, 320, 0xff652e89, 1024,
"ytABA7gCCbICD60CFKkCF6cCGqMCHqACIZ0CJJoCJpgCKZUCFgIUkgIWBBWPAhYHFI4CFQoUjAIV"
"DBSKAhUNFYgCFQ8UhwIVERSFAhUTFIMCFRQVgQIUFxSAAhQZFP4BFBoV/AEUHBT7ARQeFPkBFB8V"
"9wEUIRT2ARQjFPQBFSMV8gEVJRTxARUnFPABFCgV7gEUKhTtARQsFOwBFCwV7AEULBTsARUsFOwB"
"FSsV7AEULBTtARQsFO0BFCsU7QEVKxTtARUqFe0BFSoU7gEUKxTuARQqFe4BFCoU7wEUKhTuARUp"
"FO8BFSkU7wEVKBXvARUoFPABFCkU8AEUKBTxARQoFPEBFCcV8QEUJxTxARUnFPEBFSYU8gEVJhTy"
"ARUlFfIBFSUU8wEUJRXzARQlFPQBFCUU9AEUJBT1ARQkFPUBFCMU9gEUIhT2ARUhFPcBFSAU+AEV"
"HxT5ARUeFPoBFR4U+gEVHRT7ARUcFPwBFRsU/QEVGhT+ARUZFP8BFBkUgAIUGBSBAhQXFIICFBcU"
"ggIUFhSDAhQVFIQCFBQUhQIUExSGAhQSFIcCFBIUhwIUERSIAhUPFIkCFg0UigIXCxSNAhYJFI8C"
"FggUkAIXBRSSAhcDFJQCFwEUlgIrlwIpmgImnAIkngIjnwIhoQIfowIepAIcpgIbpgIaqAIZqAIZ"
"qAIYKwP7ARgnBf0BGCMI/QEZHgz+ARgbD/8BGBcSgAIYEhaAAhoNGIICGggcgwIaBB+DAjyEAjyF"
"AjqGAjmIAjiIAiECFIkCFAIIBBSKAhQNFIsCFAwUjAIUCxSNAhQKFI4CFAkUjwIUBxWQAhQGFZEC"
"FAUVkQIUBRWRAhQFFZECFQMVkwIUAxWTAhQDFZMCFAIVlAIVARWVAiqVAimWAimWAiiYAiaZAiaZ"
"AiWaAiScAiKdAiGeAh+hAhyjAhmuAg3GxgEA");
ok(match, "Figure does not match.\n");
ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);
refcount = ID2D1Factory_Release(factory);