d2d1: Add an initial d2d_d3d_render_target_DrawGeometry() implementation.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2017-02-03 13:37:09 +01:00 committed by Alexandre Julliard
parent ac3824fe63
commit f3563f4e62
4 changed files with 529 additions and 1 deletions

View File

@ -40,6 +40,7 @@ enum d2d_brush_type
enum d2d_shape_type
{
D2D_SHAPE_TYPE_OUTLINE,
D2D_SHAPE_TYPE_TRIANGLE,
D2D_SHAPE_TYPE_BEZIER,
D2D_SHAPE_TYPE_COUNT,
@ -299,6 +300,17 @@ struct d2d_face
UINT16 v[3];
};
struct d2d_vec4
{
float x, y, z, w;
};
struct d2d_outline_vertex
{
D2D1_POINT_2F position;
D2D1_POINT_2F direction;
};
struct d2d_geometry
{
ID2D1Geometry ID2D1Geometry_iface;
@ -321,6 +333,17 @@ struct d2d_geometry
size_t bezier_vertex_count;
} fill;
struct
{
struct d2d_outline_vertex *vertices;
size_t vertices_size;
size_t vertex_count;
struct d2d_face *faces;
size_t faces_size;
size_t face_count;
} outline;
union
{
struct

View File

@ -127,6 +127,20 @@ static void d2d_bezier_vertex_set(struct d2d_bezier_vertex *b,
b->texcoord.sign = sign;
}
static void d2d_face_set(struct d2d_face *f, UINT16 v0, UINT16 v1, UINT16 v2)
{
f->v[0] = v0;
f->v[1] = v1;
f->v[2] = v2;
}
static void d2d_outline_vertex_set(struct d2d_outline_vertex *v, float x, float y,
float direction_x, float direction_y)
{
d2d_point_set(&v->position, x, y);
d2d_point_set(&v->direction, direction_x, direction_y);
}
static void d2d_fp_two_sum(float *out, float a, float b)
{
float a_virt, a_round, b_virt, b_round;
@ -341,6 +355,25 @@ static void d2d_point_subtract(D2D1_POINT_2F *out,
out->y = a->y - b->y;
}
static void d2d_point_scale(D2D1_POINT_2F *p, float scale)
{
p->x *= scale;
p->y *= scale;
}
static float d2d_point_dot(const D2D1_POINT_2F *p0, const D2D1_POINT_2F *p1)
{
return p0->x * p1->x + p0->y * p1->y;
}
static void d2d_point_normalise(D2D1_POINT_2F *p)
{
float l;
if ((l = sqrtf(d2d_point_dot(p, p))) != 0.0f)
d2d_point_scale(p, 1.0f / l);
}
/* 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. */
@ -1702,8 +1735,84 @@ static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
return TRUE;
}
static BOOL d2d_geometry_outline_add_line_segment(struct d2d_geometry *geometry,
const D2D1_POINT_2F *p0, const D2D1_POINT_2F *next)
{
struct d2d_outline_vertex *v;
D2D1_POINT_2F q_next;
struct d2d_face *f;
size_t base_idx;
if (!d2d_array_reserve((void **)&geometry->outline.vertices, &geometry->outline.vertices_size,
geometry->outline.vertex_count + 4, sizeof(*geometry->outline.vertices)))
{
ERR("Failed to grow outline vertices array.\n");
return FALSE;
}
base_idx = geometry->outline.vertex_count;
v = &geometry->outline.vertices[base_idx];
if (!d2d_array_reserve((void **)&geometry->outline.faces, &geometry->outline.faces_size,
geometry->outline.face_count + 2, sizeof(*geometry->outline.faces)))
{
ERR("Failed to grow outline faces array.\n");
return FALSE;
}
f = &geometry->outline.faces[geometry->outline.face_count];
d2d_point_subtract(&q_next, next, p0);
d2d_point_normalise(&q_next);
d2d_outline_vertex_set(&v[0], p0->x, p0->y, q_next.x, q_next.y);
d2d_outline_vertex_set(&v[1], p0->x, p0->y, -q_next.x, -q_next.y);
d2d_outline_vertex_set(&v[2], next->x, next->y, q_next.x, q_next.y);
d2d_outline_vertex_set(&v[3], next->x, next->y, -q_next.x, -q_next.y);
geometry->outline.vertex_count += 4;
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);
geometry->outline.face_count += 2;
return TRUE;
}
static BOOL d2d_geometry_add_figure_outline(struct d2d_geometry *geometry,
struct d2d_figure *figure, D2D1_FIGURE_END figure_end)
{
const D2D1_POINT_2F *p0, *next;
enum d2d_vertex_type type;
size_t bezier_idx, i;
for (i = 0, bezier_idx = 0; i < figure->vertex_count; ++i)
{
type = figure->vertex_types[i];
if (type == D2D_VERTEX_TYPE_BEZIER)
++bezier_idx;
if (type != D2D_VERTEX_TYPE_LINE)
continue;
p0 = &figure->vertices[i];
if (i == figure->vertex_count - 1)
next = &figure->vertices[0];
else
next = &figure->vertices[i + 1];
if ((figure_end == D2D1_FIGURE_END_CLOSED || i < figure->vertex_count - 1)
&& !d2d_geometry_outline_add_line_segment(geometry, p0, next))
{
ERR("Failed to add line segment.\n");
return FALSE;
}
}
return TRUE;
}
static void d2d_geometry_cleanup(struct d2d_geometry *geometry)
{
HeapFree(GetProcessHeap(), 0, geometry->outline.faces);
HeapFree(GetProcessHeap(), 0, geometry->outline.vertices);
HeapFree(GetProcessHeap(), 0, geometry->fill.bezier_vertices);
HeapFree(GetProcessHeap(), 0, geometry->fill.faces);
HeapFree(GetProcessHeap(), 0, geometry->fill.vertices);
@ -1900,6 +2009,13 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_EndFigure(ID2D1GeometrySink *ifa
&figure->vertices[figure->vertex_count - 1], sizeof(*figure->vertices)))
--figure->vertex_count;
if (!d2d_geometry_add_figure_outline(geometry, figure, figure_end))
{
ERR("Failed to add figure outline.\n");
geometry->u.path.state = D2D_GEOMETRY_STATE_ERROR;
return;
}
geometry->u.path.state = D2D_GEOMETRY_STATE_OPEN;
}
@ -2705,6 +2821,8 @@ static ULONG STDMETHODCALLTYPE d2d_transformed_geometry_Release(ID2D1Transformed
if (!refcount)
{
geometry->outline.faces = NULL;
geometry->outline.vertices = NULL;
geometry->fill.bezier_vertices = NULL;
geometry->fill.faces = NULL;
geometry->fill.vertices = NULL;
@ -2912,6 +3030,7 @@ void d2d_transformed_geometry_init(struct d2d_geometry *geometry, ID2D1Factory *
ID2D1Geometry_AddRef(geometry->u.transformed.src_geometry = src_geometry);
src_impl = unsafe_impl_from_ID2D1Geometry(src_geometry);
geometry->fill = src_impl->fill;
geometry->outline = src_impl->outline;
}
struct d2d_geometry *unsafe_impl_from_ID2D1Geometry(ID2D1Geometry *iface)

View File

@ -614,11 +614,121 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillEllipse(ID2D1RenderTarge
ID2D1EllipseGeometry_Release(geometry);
}
static void d2d_rt_draw_geometry(struct d2d_d3d_render_target *render_target,
const struct d2d_geometry *geometry, struct d2d_brush *brush, float stroke_width)
{
ID3D10Buffer *ib, *vb, *vs_cb, *ps_cb;
D3D10_SUBRESOURCE_DATA buffer_data;
D3D10_BUFFER_DESC buffer_desc;
const D2D1_MATRIX_3X2_F *w;
float tmp_x, tmp_y;
HRESULT hr;
struct
{
struct
{
float _11, _21, _31, pad0;
float _12, _22, _32, stroke_width;
} transform_geometry;
struct d2d_vec4 transform_rtx;
struct d2d_vec4 transform_rty;
} vs_cb_data;
vs_cb_data.transform_geometry._11 = geometry->transform._11;
vs_cb_data.transform_geometry._21 = geometry->transform._21;
vs_cb_data.transform_geometry._31 = geometry->transform._31;
vs_cb_data.transform_geometry.pad0 = 0.0f;
vs_cb_data.transform_geometry._12 = geometry->transform._12;
vs_cb_data.transform_geometry._22 = geometry->transform._22;
vs_cb_data.transform_geometry._32 = geometry->transform._32;
vs_cb_data.transform_geometry.stroke_width = stroke_width;
w = &render_target->drawing_state.transform;
tmp_x = render_target->desc.dpiX / 96.0f;
vs_cb_data.transform_rtx.x = w->_11 * tmp_x;
vs_cb_data.transform_rtx.y = w->_21 * tmp_x;
vs_cb_data.transform_rtx.z = w->_31 * tmp_x;
vs_cb_data.transform_rtx.w = 2.0f / render_target->pixel_size.width;
tmp_y = render_target->desc.dpiY / 96.0f;
vs_cb_data.transform_rty.x = w->_12 * tmp_y;
vs_cb_data.transform_rty.y = w->_22 * tmp_y;
vs_cb_data.transform_rty.z = w->_32 * tmp_y;
vs_cb_data.transform_rty.w = -2.0f / render_target->pixel_size.height;
buffer_desc.ByteWidth = sizeof(vs_cb_data);
buffer_desc.Usage = D3D10_USAGE_DEFAULT;
buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
buffer_desc.CPUAccessFlags = 0;
buffer_desc.MiscFlags = 0;
buffer_data.pSysMem = &vs_cb_data;
buffer_data.SysMemPitch = 0;
buffer_data.SysMemSlicePitch = 0;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vs_cb)))
{
WARN("Failed to create constant buffer, hr %#x.\n", hr);
return;
}
if (FAILED(hr = d2d_brush_get_ps_cb(brush, NULL, render_target, &ps_cb)))
{
WARN("Failed to get ps constant buffer, hr %#x.\n", hr);
ID3D10Buffer_Release(vs_cb);
return;
}
if (geometry->outline.face_count)
{
buffer_desc.ByteWidth = geometry->outline.face_count * sizeof(*geometry->outline.faces);
buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
buffer_data.pSysMem = geometry->outline.faces;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ib)))
{
WARN("Failed to create index buffer, hr %#x.\n", hr);
goto done;
}
buffer_desc.ByteWidth = geometry->outline.vertex_count * sizeof(*geometry->outline.vertices);
buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
buffer_data.pSysMem = geometry->outline.vertices;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &vb)))
{
ERR("Failed to create vertex buffer, hr %#x.\n", hr);
ID3D10Buffer_Release(ib);
goto done;
}
d2d_rt_draw(render_target, D2D_SHAPE_TYPE_OUTLINE, ib, 3 * geometry->outline.face_count, vb,
sizeof(*geometry->outline.vertices), vs_cb, ps_cb, brush, NULL);
ID3D10Buffer_Release(vb);
ID3D10Buffer_Release(ib);
}
done:
ID3D10Buffer_Release(ps_cb);
ID3D10Buffer_Release(vs_cb);
}
static void STDMETHODCALLTYPE d2d_d3d_render_target_DrawGeometry(ID2D1RenderTarget *iface,
ID2D1Geometry *geometry, ID2D1Brush *brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
{
FIXME("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p stub!\n",
const struct d2d_geometry *geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface);
struct d2d_brush *brush_impl = unsafe_impl_from_ID2D1Brush(brush);
TRACE("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p.\n",
iface, geometry, brush, stroke_width, stroke_style);
if (stroke_style)
FIXME("Ignoring stoke style %p.\n", stroke_style);
d2d_rt_draw_geometry(render_target, geometry_impl, brush_impl, stroke_width);
}
static void d2d_rt_fill_geometry(struct d2d_d3d_render_target *render_target,
@ -1770,6 +1880,11 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
unsigned int i, j, k;
HRESULT hr;
static const D3D10_INPUT_ELEMENT_DESC il_desc_outline[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"DIRECTION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
static const D3D10_INPUT_ELEMENT_DESC il_desc_triangle[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
@ -1779,6 +1894,53 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
static const DWORD vs_code_outline[] =
{
#if 0
float3x2 transform_geometry;
float stroke_width;
float4 transform_rtx;
float4 transform_rty;
float4 main(float2 position : POSITION, float2 direction : DIRECTION) : SV_POSITION
{
float2 v_p;
v_p = normalize(float2(-dot(direction.xy, transform_geometry._12_22),
dot(direction.xy, transform_geometry._11_21)));
position = mul(float3(position, 1.0f), transform_geometry) + stroke_width * 0.5f * v_p;
return float4(mul(float2x3(transform_rtx.xyz * transform_rtx.w, transform_rty.xyz * transform_rty.w),
float3(position.xy, 1.0f)) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
}
#endif
0x43425844, 0xdae1a8d0, 0x71b89c55, 0x19c91fd3, 0x3192cf04, 0x00000001, 0x00000334, 0x00000003,
0x0000002c, 0x00000080, 0x000000b4, 0x4e475349, 0x0000004c, 0x00000002, 0x00000008, 0x00000038,
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000303, 0x00000041, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000303, 0x49534f50, 0x4e4f4954, 0x52494400, 0x49544345, 0xab004e4f,
0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003,
0x00000000, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x52444853, 0x00000278, 0x00010040,
0x0000009e, 0x04000059, 0x00208e46, 0x00000000, 0x00000004, 0x0300005f, 0x00101032, 0x00000000,
0x0300005f, 0x00101032, 0x00000001, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x02000068,
0x00000003, 0x0800000f, 0x00100012, 0x00000000, 0x00101046, 0x00000001, 0x00208046, 0x00000000,
0x00000001, 0x06000036, 0x00100012, 0x00000000, 0x8010000a, 0x00000041, 0x00000000, 0x0800000f,
0x00100022, 0x00000000, 0x00101046, 0x00000001, 0x00208046, 0x00000000, 0x00000000, 0x0700000f,
0x00100042, 0x00000000, 0x00100046, 0x00000000, 0x00100046, 0x00000000, 0x05000044, 0x00100042,
0x00000000, 0x0010002a, 0x00000000, 0x07000038, 0x00100032, 0x00000000, 0x00100aa6, 0x00000000,
0x00100046, 0x00000000, 0x08000038, 0x00100042, 0x00000000, 0x0020803a, 0x00000000, 0x00000001,
0x00004001, 0x3f000000, 0x05000036, 0x00100032, 0x00000001, 0x00101046, 0x00000000, 0x05000036,
0x00100042, 0x00000001, 0x00004001, 0x3f800000, 0x08000010, 0x00100012, 0x00000002, 0x00100246,
0x00000001, 0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00100022, 0x00000002, 0x00100246,
0x00000001, 0x00208246, 0x00000000, 0x00000001, 0x09000032, 0x00100032, 0x00000000, 0x00100aa6,
0x00000000, 0x00100046, 0x00000000, 0x00100046, 0x00000002, 0x09000038, 0x00100072, 0x00000001,
0x00208ff6, 0x00000000, 0x00000002, 0x00208246, 0x00000000, 0x00000002, 0x05000036, 0x00100042,
0x00000000, 0x00004001, 0x3f800000, 0x07000010, 0x00100012, 0x00000001, 0x00100246, 0x00000001,
0x00100246, 0x00000000, 0x09000038, 0x00100072, 0x00000002, 0x00208ff6, 0x00000000, 0x00000003,
0x00208246, 0x00000000, 0x00000003, 0x07000010, 0x00100022, 0x00000001, 0x00100246, 0x00000002,
0x00100246, 0x00000000, 0x0a000000, 0x00102032, 0x00000000, 0x00100046, 0x00000001, 0x00004002,
0xbf800000, 0x3f800000, 0x00000000, 0x00000000, 0x08000036, 0x001020c2, 0x00000000, 0x00004002,
0x00000000, 0x00000000, 0x00000000, 0x3f800000, 0x0100003e,
};
static const DWORD vs_code_triangle[] =
{
/* float3x2 transform;
@ -2154,6 +2316,14 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
goto err;
}
if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc_outline,
sizeof(il_desc_outline) / sizeof(*il_desc_outline), vs_code_outline, sizeof(vs_code_outline),
&render_target->shape_resources[D2D_SHAPE_TYPE_OUTLINE].il)))
{
WARN("Failed to create outline input layout, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreateInputLayout(render_target->device, il_desc_triangle,
sizeof(il_desc_triangle) / sizeof(*il_desc_triangle), vs_code_triangle, sizeof(vs_code_triangle),
&render_target->shape_resources[D2D_SHAPE_TYPE_TRIANGLE].il)))
@ -2170,6 +2340,13 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
goto err;
}
if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device, vs_code_outline,
sizeof(vs_code_outline), &render_target->shape_resources[D2D_SHAPE_TYPE_OUTLINE].vs)))
{
WARN("Failed to create 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)))
{
@ -2196,6 +2373,18 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
}
}
for (j = 0; j < D2D_BRUSH_TYPE_COUNT; ++j)
{
for (k = 0; k < D2D_BRUSH_TYPE_COUNT + 1; ++k)
{
struct d2d_shape_resources *outline = &render_target->shape_resources[D2D_SHAPE_TYPE_OUTLINE];
struct d2d_shape_resources *triangle = &render_target->shape_resources[D2D_SHAPE_TYPE_TRIANGLE];
if (triangle->ps[j][k])
ID3D10PixelShader_AddRef(outline->ps[j][k] = triangle->ps[j][k]);
}
}
buffer_desc.ByteWidth = sizeof(indices);
buffer_desc.Usage = D3D10_USAGE_DEFAULT;
buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;

View File

@ -3567,6 +3567,202 @@ static void test_gradient(void)
DestroyWindow(window);
}
static void test_draw_geometry(void)
{
D2D1_POINT_2F point = {0.0f, 0.0f};
ID2D1SolidColorBrush *brush;
ID2D1PathGeometry *geometry;
IDXGISwapChain *swapchain;
ID2D1GeometrySink *sink;
ID2D1RenderTarget *rt;
ID3D10Device1 *device;
IDXGISurface *surface;
ID2D1Factory *factory;
D2D1_COLOR_F color;
ULONG refcount;
HWND window;
HRESULT hr;
BOOL match;
if (!(device = create_device()))
{
skip("Failed to create device, skipping tests.\n");
return;
}
window = create_window();
swapchain = create_swapchain(device, window, TRUE);
hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface);
ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr);
rt = create_render_target(surface);
ok(!!rt, "Failed to create render target.\n");
ID2D1RenderTarget_GetFactory(rt, &factory);
ID2D1RenderTarget_SetDpi(rt, 192.0f, 48.0f);
ID2D1RenderTarget_SetAntialiasMode(rt, D2D1_ANTIALIAS_MODE_ALIASED);
set_color(&color, 0.890f, 0.851f, 0.600f, 1.0f);
hr = ID2D1RenderTarget_CreateSolidColorBrush(rt, &color, NULL, &brush);
ok(SUCCEEDED(hr), "Failed to create brush, hr %#x.\n", hr);
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, 40.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 120.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 120.0f, 160.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 200.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 280.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 280.0f, 160.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 20.0f, 480.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 60.0f, 480.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 120.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 120.0f, 560.0f);
line_to(sink, 120.0f, 400.0f);
line_to(sink, 120.0f, 560.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 180.0f, 480.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 220.0f, 480.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 280.0f, 400.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 280.0f, 560.0f);
line_to(sink, 280.0f, 400.0f);
line_to(sink, 280.0f, 560.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 20.0f, 880.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 40.0f, 720.0f);
line_to(sink, 60.0f, 880.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 100.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 120.0f, 880.0f);
line_to(sink, 140.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_OPEN);
set_point(&point, 180.0f, 880.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 200.0f, 720.0f);
line_to(sink, 220.0f, 880.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 260.0f, 720.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
line_to(sink, 280.0f, 880.0f);
line_to(sink, 300.0f, 720.0f);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
ID2D1GeometrySink_SetFillMode(sink, D2D1_FILL_MODE_ALTERNATE);
hr = ID2D1GeometrySink_Close(sink);
ID2D1GeometrySink_Release(sink);
ID2D1RenderTarget_BeginDraw(rt);
set_color(&color, 0.396f, 0.180f, 0.537f, 1.0f);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_DrawGeometry(rt, (ID2D1Geometry *)geometry, (ID2D1Brush *)brush, 5.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, "");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 0, 160, 160, 0xff652e89, 0, "");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 0, 160, 160, 0xff652e89, 0, "");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 0, 160, 160, 0xff652e89, 0, "q2MKlgEKq2MA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 0, 160, 160, 160, 0xff652e89, 0, "iGNQUFCIYwAA");
ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 160, 160, 160, 0xff652e89, 0,
"qyIKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEK"
"lgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEK"
"lgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKQQpLCkEKSwqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQrLIwAA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 160, 160, 160, 0xff652e89, 0, "4GLAAuBi");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 160, 160, 160, 0xff652e89, 0,
"qyIKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEK"
"lgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEK"
"lgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKlgEKSwpBCksKQQqWAQqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqW"
"AQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQqWAQrLIwAA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 0, 320, 160, 160, 0xff652e89, 0,
"rycCngECnQEEnAEEmwEGmgEGmQEImAEIlwEKlgEKlQEMlAEMkwEOkgEOkQEQkAEQjwESjgESjQEU"
"jAEUiwEKAgqKAQoCCokBCgQKiAEKBAqHAQoGCoYBCgYKhQEKCAqEAQoICoMBCgoKggEKCgqBAQoM"
"CoABCgwKfwoOCn4KDgp9ChAKfAoQCnsKEgp6ChIKeQoUCngKFAp3ChYKdgoWCnUKGAp0ChgKcwoa"
"CnIKGgpxChwKcAocCm8KHgpuCh4KbQogCmwKIAprCiIKagoiCmkKJApoCiQKZwomCmYKJgplCigK"
"ZAooCmMKKgpiCioKYQosCmAKLApfCi4KXgouCl0KMApcCjAKWwoyCloKMgpZCjQKWAo0ClcKNgpW"
"CjYKVQo4ClQKOApTCjoKUgo6ClEKPApQCjwKTwo+Ck4KPgpNCkAKTApACksKQgpKCkIKSQpECkgK"
"RApHCkYKozIA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 160, 320, 160, 160, 0xff652e89, 0,
"ozIKRgpHCkQKSApECkkKQgpKCkIKSwpACkwKQApNCj4KTgo+Ck8KPApQCjwKUQo6ClIKOgpTCjgK"
"VAo4ClUKNgpWCjYKVwo0ClgKNApZCjIKWgoyClsKMApcCjAKXQouCl4KLgpfCiwKYAosCmEKKgpi"
"CioKYwooCmQKKAplCiYKZgomCmcKJApoCiQKaQoiCmoKIgprCiAKbAogCm0KHgpuCh4KbwocCnAK"
"HApxChoKcgoaCnMKGAp0ChgKdQoWCnYKFgp3ChQKeAoUCnkKEgp6ChIKewoQCnwKEAp9Cg4KfgoO"
"Cn8KDAqAAQoMCoEBCgoKggEKCgqDAQoICoQBCggKhQEKBgqGAQoGCocBCgQKiAEKBAqJAQoCCooB"
"CgIKiwEUjAEUjQESjgESjwEQkAEQkQEOkgEOkwEMlAEMlQEKlgEKlwEImAEImQEGmgEGmwEEnAEE"
"nQECngECrycA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 320, 320, 160, 160, 0xff652e89, 2,
"rycCngECnQEEnAEEmwEGmgEGmQEImAEIlwEKlgEKlQEMlAEMkwEOkgEOkQEQkAEQjwESjgESjQEU"
"jAEUiwEKAgqKAQoCCokBCgQKiAEKBAqHAQoGCoYBCgYKhQEKCAqEAQoICoMBCgoKggEKCgqBAQoM"
"CoABCgwKfwoOCn4KDgp9ChAKfAoQCnsKEgp6ChIKeQoUCngKFAp3ChYKdgoWCnUKGAp0ChgKcwoa"
"CnIKGgpxChwKcAocCm8KHgpuCh4KbQogCmwKIAprCiIKagoiCmkKJApoCiQKZwomCmYKJgplCigK"
"ZAooCmMKKgpiCioKYQosCmAKLApfCi4KXgouCl0KMApcCjAKWwoyCloKMgpZCjQKWAo0ClcKNgpW"
"CjYKVQo4ClQKOApTCjoKUgo6ClEKPApQCjwKTwo+Ck4KPgpNCkAKTApACksKQgpKCkIKSQpECkgK"
"RApHWkZagzEA");
todo_wine ok(match, "Figure does not match.\n");
match = compare_figure(surface, 480, 320, 160, 160, 0xff652e89, 0,
"gzFaRlpHCkQKSApECkkKQgpKCkIKSwpACkwKQApNCj4KTgo+Ck8KPApQCjwKUQo6ClIKOgpTCjgK"
"VAo4ClUKNgpWCjYKVwo0ClgKNApZCjIKWgoyClsKMApcCjAKXQouCl4KLgpfCiwKYAosCmEKKgpi"
"CioKYwooCmQKKAplCiYKZgomCmcKJApoCiQKaQoiCmoKIgprCiAKbAogCm0KHgpuCh4KbwocCnAK"
"HApxChoKcgoaCnMKGAp0ChgKdQoWCnYKFgp3ChQKeAoUCnkKEgp6ChIKewoQCnwKEAp9Cg4KfgoO"
"Cn8KDAqAAQoMCoEBCgoKggEKCgqDAQoICoQBCggKhQEKBgqGAQoGCocBCgQKiAEKBAqJAQoCCooB"
"CgIKiwEUjAEUjQESjgESjwEQkAEQkQEOkgEOkwEMlAEMlQEKlgEKlwEImAEImQEGmgEGmwEEnAEE"
"nQECngECrycA");
todo_wine ok(match, "Figure does not match.\n");
ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);
refcount = ID2D1Factory_Release(factory);
ok(!refcount, "Factory has %u references left.\n", refcount);
IDXGISurface_Release(surface);
IDXGISwapChain_Release(swapchain);
ID3D10Device1_Release(device);
DestroyWindow(window);
}
START_TEST(d2d1)
{
test_clip();
@ -3589,4 +3785,5 @@ START_TEST(d2d1)
test_desktop_dpi();
test_stroke_style();
test_gradient();
test_draw_geometry();
}