d2d1: Implement initial support for drawing bezier curves.

This commit is contained in:
Henri Verbeet 2015-07-20 11:07:28 +02:00 committed by Alexandre Julliard
parent 025c320145
commit b33786ce6d
5 changed files with 643 additions and 111 deletions

View File

@ -796,20 +796,21 @@ HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_d3d_render_targe
return hr;
}
void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target)
void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
enum d2d_shape_type shape_type)
{
static const float blend_factor[] = {1.0f, 1.0f, 1.0f, 1.0f};
ID3D10Device *device = render_target->device;
ID3D10PixelShader *ps;
HRESULT hr;
ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
if (brush->type == D2D_BRUSH_TYPE_SOLID)
if (!(ps = render_target->shape_resources[shape_type].ps[brush->type]))
FIXME("No pixel shader for shape type %#x and brush type %#x.\n", shape_type, brush->type);
ID3D10Device_PSSetShader(device, ps);
if (brush->type == D2D_BRUSH_TYPE_BITMAP)
{
ID3D10Device_PSSetShader(device, render_target->rect_solid_ps);
}
else if (brush->type == D2D_BRUSH_TYPE_BITMAP)
{
ID3D10Device_PSSetShader(device, render_target->rect_bitmap_ps);
ID3D10Device_PSSetShaderResources(device, 0, 1, &brush->u.bitmap.bitmap->view);
if (!brush->u.bitmap.sampler_state)
{
@ -838,7 +839,7 @@ void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_tar
}
ID3D10Device_PSSetSamplers(device, 0, 1, &brush->u.bitmap.sampler_state);
}
else
else if (brush->type != D2D_BRUSH_TYPE_SOLID)
{
FIXME("Unhandled brush type %#x.\n", brush->type);
}

View File

@ -35,6 +35,14 @@ enum d2d_brush_type
D2D_BRUSH_TYPE_SOLID,
D2D_BRUSH_TYPE_LINEAR,
D2D_BRUSH_TYPE_BITMAP,
D2D_BRUSH_TYPE_COUNT,
};
enum d2d_shape_type
{
D2D_SHAPE_TYPE_TRIANGLE,
D2D_SHAPE_TYPE_BEZIER,
D2D_SHAPE_TYPE_COUNT,
};
struct d2d_clip_stack
@ -44,6 +52,13 @@ struct d2d_clip_stack
unsigned int count;
};
struct d2d_shape_resources
{
ID3D10InputLayout *il;
ID3D10VertexShader *vs;
ID3D10PixelShader *ps[D2D_BRUSH_TYPE_COUNT];
};
struct d2d_d3d_render_target
{
ID2D1RenderTarget ID2D1RenderTarget_iface;
@ -54,17 +69,13 @@ struct d2d_d3d_render_target
ID3D10Device *device;
ID3D10RenderTargetView *view;
ID3D10StateBlock *stateblock;
ID3D10InputLayout *il;
struct d2d_shape_resources shape_resources[D2D_SHAPE_TYPE_COUNT];
ID3D10Buffer *ib;
unsigned int vb_stride;
ID3D10Buffer *vb;
ID3D10VertexShader *vs;
ID3D10RasterizerState *rs;
ID3D10BlendState *bs;
ID3D10PixelShader *rect_solid_ps;
ID3D10PixelShader *rect_bitmap_ps;
D2D1_DRAWING_STATE_DESCRIPTION drawing_state;
IDWriteRenderingParams *text_rendering_params;
@ -142,7 +153,8 @@ void d2d_linear_gradient_brush_init(struct d2d_brush *brush, ID2D1RenderTarget *
HRESULT d2d_bitmap_brush_init(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
ID2D1Bitmap *bitmap, const D2D1_BITMAP_BRUSH_PROPERTIES *bitmap_brush_desc,
const D2D1_BRUSH_PROPERTIES *brush_desc) DECLSPEC_HIDDEN;
void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target) DECLSPEC_HIDDEN;
void d2d_brush_bind_resources(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
enum d2d_shape_type shape_type) DECLSPEC_HIDDEN;
HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_d3d_render_target *render_target,
ID3D10Buffer **ps_cb) DECLSPEC_HIDDEN;
struct d2d_brush *unsafe_impl_from_ID2D1Brush(ID2D1Brush *iface) DECLSPEC_HIDDEN;
@ -201,6 +213,18 @@ enum d2d_geometry_state
D2D_GEOMETRY_STATE_FIGURE,
};
struct d2d_bezier
{
struct
{
D2D1_POINT_2F position;
struct
{
float u, v, sign;
} texcoord;
} v[3];
};
struct d2d_face
{
UINT16 v[3];
@ -218,6 +242,9 @@ struct d2d_geometry
size_t faces_size;
size_t face_count;
struct d2d_bezier *beziers;
size_t bezier_count;
union
{
struct

View File

@ -39,6 +39,10 @@ struct d2d_figure
D2D1_POINT_2F *vertices;
size_t vertices_size;
size_t vertex_count;
struct d2d_bezier *beziers;
size_t beziers_size;
size_t bezier_count;
};
struct d2d_cdt_edge_ref
@ -71,6 +75,16 @@ static void d2d_point_subtract(D2D1_POINT_2F *out,
out->y = a->y - b->y;
}
static float d2d_point_ccw(const D2D1_POINT_2F *a, const D2D1_POINT_2F *b, const D2D1_POINT_2F *c)
{
D2D1_POINT_2F ab, ac;
d2d_point_subtract(&ab, b, a);
d2d_point_subtract(&ac, c, a);
return ab.x * ac.y - ab.y * ac.x;
}
static BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t element_count, size_t element_size)
{
size_t new_capacity, max_capacity;
@ -133,6 +147,55 @@ static BOOL d2d_figure_add_vertex(struct d2d_figure *figure, D2D1_POINT_2F verte
return TRUE;
}
/* FIXME: No inside/outside testing is done for beziers. */
static BOOL d2d_figure_add_bezier(struct d2d_figure *figure, D2D1_POINT_2F p0, D2D1_POINT_2F p1, D2D1_POINT_2F p2)
{
struct d2d_bezier *b;
unsigned int idx1, idx2;
float sign;
if (!d2d_array_reserve((void **)&figure->beziers, &figure->beziers_size,
figure->bezier_count + 1, sizeof(*figure->beziers)))
{
ERR("Failed to grow beziers array.\n");
return FALSE;
}
if (d2d_point_ccw(&p0, &p1, &p2) > 0.0f)
{
sign = -1.0f;
idx1 = 1;
idx2 = 2;
}
else
{
sign = 1.0f;
idx1 = 2;
idx2 = 1;
}
b = &figure->beziers[figure->bezier_count];
b->v[0].position = p0;
b->v[0].texcoord.u = 0.0f;
b->v[0].texcoord.v = 0.0f;
b->v[0].texcoord.sign = sign;
b->v[idx1].position = p1;
b->v[idx1].texcoord.u = 0.5f;
b->v[idx1].texcoord.v = 0.0f;
b->v[idx1].texcoord.sign = sign;
b->v[idx2].position = p2;
b->v[idx2].texcoord.u = 1.0f;
b->v[idx2].texcoord.v = 1.0f;
b->v[idx2].texcoord.sign = sign;
++figure->bezier_count;
if (sign > 0.0f && !d2d_figure_add_vertex(figure, p1))
return FALSE;
if (!d2d_figure_add_vertex(figure, p2))
return FALSE;
return TRUE;
}
static void d2d_cdt_edge_rot(struct d2d_cdt_edge_ref *dst, const struct d2d_cdt_edge_ref *src)
{
dst->idx = src->idx;
@ -193,12 +256,7 @@ static void d2d_cdt_edge_set_destination(const struct d2d_cdt *cdt,
static float d2d_cdt_ccw(const struct d2d_cdt *cdt, size_t a, size_t b, size_t c)
{
D2D1_POINT_2F ab, ac;
d2d_point_subtract(&ab, &cdt->vertices[b], &cdt->vertices[a]);
d2d_point_subtract(&ac, &cdt->vertices[c], &cdt->vertices[a]);
return ab.x * ac.y - ab.y * ac.x;
return d2d_point_ccw(&cdt->vertices[a], &cdt->vertices[b], &cdt->vertices[c]);
}
static BOOL d2d_cdt_rightof(const struct d2d_cdt *cdt, size_t p, const struct d2d_cdt_edge_ref *e)
@ -773,6 +831,7 @@ static BOOL d2d_cdt_insert_segments(struct d2d_cdt *cdt, struct d2d_geometry *ge
/* Intersect the geometry's segments with themselves. This uses the
* straightforward approach of testing everything against everything, but
* there certainly exist more scalable algorithms for this. */
/* FIXME: Beziers can't currently self-intersect. */
static BOOL d2d_geometry_intersect_self(struct d2d_geometry *geometry)
{
D2D1_POINT_2F p0, p1, q0, q1, v_p, v_q, v_qp, intersection;
@ -920,6 +979,7 @@ static BOOL d2d_path_geometry_add_figure(struct d2d_geometry *geometry)
static void d2d_geometry_destroy(struct d2d_geometry *geometry)
{
HeapFree(GetProcessHeap(), 0, geometry->beziers);
HeapFree(GetProcessHeap(), 0, geometry->faces);
HeapFree(GetProcessHeap(), 0, geometry->vertices);
HeapFree(GetProcessHeap(), 0, geometry);
@ -1048,9 +1108,11 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if
const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
{
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 p;
unsigned int i;
FIXME("iface %p, beziers %p, count %u stub!\n", iface, beziers, count);
TRACE("iface %p, beziers %p, count %u.\n", iface, beziers, count);
if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
{
@ -1060,9 +1122,14 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddBeziers(ID2D1GeometrySink *if
for (i = 0; i < count; ++i)
{
if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], beziers[i].point3))
/* FIXME: This tries to approximate a cubic bezier with a quadratic one. */
p.x = (beziers[i].point1.x + beziers[i].point2.x) * 0.75f;
p.y = (beziers[i].point1.y + beziers[i].point2.y) * 0.75f;
p.x -= (figure->vertices[figure->vertex_count - 1].x + beziers[i].point3.x) * 0.25f;
p.y -= (figure->vertices[figure->vertex_count - 1].y + beziers[i].point3.y) * 0.25f;
if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1], p, beziers[i].point3))
{
ERR("Failed to add vertex.\n");
ERR("Failed to add bezier.\n");
return;
}
}
@ -1097,6 +1164,7 @@ static void d2d_path_geometry_free_figures(struct d2d_geometry *geometry)
for (i = 0; i < geometry->u.path.figure_count; ++i)
{
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].beziers);
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures[i].vertices);
}
HeapFree(GetProcessHeap(), 0, geometry->u.path.figures);
@ -1108,6 +1176,7 @@ static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *ifac
{
struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
HRESULT hr = E_FAIL;
size_t i, start;
TRACE("iface %p.\n", iface);
@ -1121,7 +1190,33 @@ static HRESULT STDMETHODCALLTYPE d2d_geometry_sink_Close(ID2D1GeometrySink *ifac
if (!d2d_geometry_intersect_self(geometry))
goto done;
hr = d2d_path_geometry_triangulate(geometry);
if (FAILED(hr = d2d_path_geometry_triangulate(geometry)))
goto done;
for (i = 0; i < geometry->u.path.figure_count; ++i)
{
geometry->bezier_count += geometry->u.path.figures[i].bezier_count;
}
if (!(geometry->beziers = HeapAlloc(GetProcessHeap(), 0,
geometry->bezier_count * sizeof(*geometry->beziers))))
{
ERR("Failed to allocate beziers array.\n");
geometry->bezier_count = 0;
hr = E_OUTOFMEMORY;
goto done;
}
for (i = 0, start = 0; i < geometry->u.path.figure_count; ++i)
{
struct d2d_figure *figure = &geometry->u.path.figures[i];
if (figure->bezier_count)
{
memcpy(&geometry->beziers[start], figure->beziers,
figure->bezier_count * sizeof(*figure->beziers));
start += figure->bezier_count;
}
}
done:
d2d_path_geometry_free_figures(geometry);
@ -1156,9 +1251,10 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr
const D2D1_QUADRATIC_BEZIER_SEGMENT *beziers, UINT32 bezier_count)
{
struct d2d_geometry *geometry = impl_from_ID2D1GeometrySink(iface);
struct d2d_figure *figure = &geometry->u.path.figures[geometry->u.path.figure_count - 1];
unsigned int i;
FIXME("iface %p, beziers %p, bezier_count %u stub!\n", iface, beziers, bezier_count);
TRACE("iface %p, beziers %p, bezier_count %u.\n", iface, beziers, bezier_count);
if (geometry->u.path.state != D2D_GEOMETRY_STATE_FIGURE)
{
@ -1168,9 +1264,10 @@ static void STDMETHODCALLTYPE d2d_geometry_sink_AddQuadraticBeziers(ID2D1Geometr
for (i = 0; i < bezier_count; ++i)
{
if (!d2d_figure_add_vertex(&geometry->u.path.figures[geometry->u.path.figure_count - 1], beziers[i].point2))
if (!d2d_figure_add_bezier(figure, figure->vertices[figure->vertex_count - 1],
beziers[i].point1, beziers[i].point2))
{
ERR("Failed to add vertex.\n");
ERR("Failed to add bezier.\n");
return;
}
}

View File

@ -127,10 +127,11 @@ static void d2d_clip_stack_pop(struct d2d_clip_stack *stack)
--stack->count;
}
static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *ib, unsigned int index_count,
ID3D10Buffer *vb, unsigned int vb_stride, ID3D10Buffer *vs_cb, ID3D10Buffer *ps_cb,
struct d2d_brush *brush)
static void d2d_draw(struct d2d_d3d_render_target *render_target, enum d2d_shape_type shape_type,
ID3D10Buffer *ib, unsigned int index_count, ID3D10Buffer *vb, unsigned int vb_stride,
ID3D10Buffer *vs_cb, ID3D10Buffer *ps_cb, struct d2d_brush *brush)
{
struct d2d_shape_resources *shape_resources = &render_target->shape_resources[shape_type];
ID3D10Device *device = render_target->device;
unsigned int offset;
D3D10_VIEWPORT vp;
@ -151,13 +152,13 @@ static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *
ID3D10Device_ClearState(device);
ID3D10Device_IASetInputLayout(device, render_target->il);
ID3D10Device_IASetInputLayout(device, shape_resources->il);
ID3D10Device_IASetPrimitiveTopology(device, D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D10Device_IASetIndexBuffer(device, ib, DXGI_FORMAT_R16_UINT, 0);
offset = 0;
ID3D10Device_IASetVertexBuffers(device, 0, 1, &vb, &vb_stride, &offset);
ID3D10Device_VSSetConstantBuffers(device, 0, 1, &vs_cb);
ID3D10Device_VSSetShader(device, render_target->vs);
ID3D10Device_VSSetShader(device, shape_resources->vs);
ID3D10Device_PSSetConstantBuffers(device, 0, 1, &ps_cb);
ID3D10Device_RSSetViewports(device, 1, &vp);
if (render_target->clip_stack.count)
@ -175,11 +176,14 @@ static void d2d_draw(struct d2d_d3d_render_target *render_target, ID3D10Buffer *
}
ID3D10Device_OMSetRenderTargets(device, 1, &render_target->view, NULL);
if (brush)
d2d_brush_bind_resources(brush, render_target);
d2d_brush_bind_resources(brush, render_target, shape_type);
else
ID3D10Device_PSSetShader(device, render_target->rect_solid_ps);
ID3D10Device_PSSetShader(device, shape_resources->ps[D2D_BRUSH_TYPE_SOLID]);
ID3D10Device_DrawIndexed(device, index_count, 0, 0);
if (ib)
ID3D10Device_DrawIndexed(device, index_count, 0, 0);
else
ID3D10Device_Draw(device, index_count, 0);
if (FAILED(hr = render_target->stateblock->lpVtbl->Apply(render_target->stateblock)))
WARN("Failed to apply stateblock, hr %#x.\n", hr);
@ -228,17 +232,25 @@ static ULONG STDMETHODCALLTYPE d2d_d3d_render_target_Release(ID2D1RenderTarget *
if (!refcount)
{
unsigned int i, j;
d2d_clip_stack_cleanup(&render_target->clip_stack);
if (render_target->text_rendering_params)
IDWriteRenderingParams_Release(render_target->text_rendering_params);
ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
ID3D10PixelShader_Release(render_target->rect_solid_ps);
ID3D10BlendState_Release(render_target->bs);
ID3D10RasterizerState_Release(render_target->rs);
ID3D10VertexShader_Release(render_target->vs);
ID3D10Buffer_Release(render_target->vb);
ID3D10Buffer_Release(render_target->ib);
ID3D10InputLayout_Release(render_target->il);
for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
{
for (j = 0; j < D2D_BRUSH_TYPE_COUNT; ++j)
{
if (render_target->shape_resources[i].ps[j])
ID3D10PixelShader_Release(render_target->shape_resources[i].ps[j]);
}
ID3D10VertexShader_Release(render_target->shape_resources[i].vs);
ID3D10InputLayout_Release(render_target->shape_resources[i].il);
}
render_target->stateblock->lpVtbl->Release(render_target->stateblock);
ID3D10RenderTargetView_Release(render_target->view);
ID3D10Device_Release(render_target->device);
@ -606,33 +618,6 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
geometry_impl = unsafe_impl_from_ID2D1Geometry(geometry);
buffer_desc.ByteWidth = geometry_impl->face_count * sizeof(*geometry_impl->faces);
buffer_desc.Usage = D3D10_USAGE_DEFAULT;
buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
buffer_desc.CPUAccessFlags = 0;
buffer_desc.MiscFlags = 0;
buffer_data.pSysMem = geometry_impl->faces;
buffer_data.SysMemPitch = 0;
buffer_data.SysMemSlicePitch = 0;
if (FAILED(hr = ID3D10Device_CreateBuffer(render_target->device, &buffer_desc, &buffer_data, &ib)))
{
WARN("Failed to create index buffer, hr %#x.\n", hr);
return;
}
buffer_desc.ByteWidth = geometry_impl->vertex_count * sizeof(*geometry_impl->vertices);
buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
buffer_data.pSysMem = geometry_impl->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);
return;
}
tmp_x = (2.0f * render_target->dpi_x) / (96.0f * render_target->pixel_size.width);
tmp_y = -(2.0f * render_target->dpi_y) / (96.0f * render_target->pixel_size.height);
transform._11 = render_target->drawing_state.transform._11 * tmp_x;
@ -645,14 +630,18 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
transform.pad1 = 0.0f;
buffer_desc.ByteWidth = sizeof(transform);
buffer_desc.Usage = D3D10_USAGE_DEFAULT;
buffer_desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
buffer_desc.CPUAccessFlags = 0;
buffer_desc.MiscFlags = 0;
buffer_data.pSysMem = &transform;
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);
ID3D10Buffer_Release(vb);
ID3D10Buffer_Release(ib);
return;
}
@ -660,18 +649,56 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_FillGeometry(ID2D1RenderTarg
{
WARN("Failed to get ps constant buffer, hr %#x.\n", hr);
ID3D10Buffer_Release(vs_cb);
ID3D10Buffer_Release(vb);
ID3D10Buffer_Release(ib);
return;
}
d2d_draw(render_target, ib, 3 * geometry_impl->face_count, vb,
buffer_desc.ByteWidth = geometry_impl->face_count * sizeof(*geometry_impl->faces);
buffer_desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
buffer_data.pSysMem = geometry_impl->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_impl->vertex_count * sizeof(*geometry_impl->vertices);
buffer_desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
buffer_data.pSysMem = geometry_impl->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_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, ib, 3 * geometry_impl->face_count, vb,
sizeof(*geometry_impl->vertices), vs_cb, ps_cb, brush_impl);
ID3D10Buffer_Release(ps_cb);
ID3D10Buffer_Release(vs_cb);
ID3D10Buffer_Release(vb);
ID3D10Buffer_Release(ib);
if (geometry_impl->bezier_count)
{
buffer_desc.ByteWidth = geometry_impl->bezier_count * sizeof(*geometry_impl->beziers);
buffer_data.pSysMem = geometry_impl->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);
goto done;
}
d2d_draw(render_target, D2D_SHAPE_TYPE_BEZIER, NULL, 3 * geometry_impl->bezier_count, vb,
sizeof(*geometry_impl->beziers->v), vs_cb, ps_cb, brush_impl);
ID3D10Buffer_Release(vb);
}
done:
ID3D10Buffer_Release(ps_cb);
ID3D10Buffer_Release(vs_cb);
}
static void STDMETHODCALLTYPE d2d_d3d_render_target_FillMesh(ID2D1RenderTarget *iface,
@ -1095,7 +1122,8 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *ifa
return;
}
d2d_draw(render_target, render_target->ib, 6, render_target->vb, render_target->vb_stride, vs_cb, ps_cb, NULL);
d2d_draw(render_target, D2D_SHAPE_TYPE_TRIANGLE, render_target->ib, 6,
render_target->vb, render_target->vb_stride, vs_cb, ps_cb, NULL);
ID3D10Buffer_Release(ps_cb);
ID3D10Buffer_Release(vs_cb);
@ -1408,13 +1436,19 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
D3D10_BUFFER_DESC buffer_desc;
D3D10_BLEND_DESC blend_desc;
ID3D10Resource *resource;
unsigned int i, j;
HRESULT hr;
static const D3D10_INPUT_ELEMENT_DESC il_desc[] =
static const D3D10_INPUT_ELEMENT_DESC il_desc_triangle[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
static const DWORD vs_code[] =
static const D3D10_INPUT_ELEMENT_DESC il_desc_bezier[] =
{
{"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_triangle[] =
{
/* float3x2 transform;
*
@ -1433,7 +1467,32 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
0x00000000, 0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6,
0x00000000, 0x0100003e,
};
static const DWORD rect_solid_ps_code[] =
static const DWORD vs_code_bezier[] =
{
#if 0
float3x2 transform;
float4 main(float4 position : POSITION,
inout float3 texcoord : TEXCOORD0) : SV_POSITION
{
return float4(mul(position.xyw, transform), position.zw);
}
#endif
0x43425844, 0x5e578adb, 0x093f7e27, 0x50d478af, 0xec3dfa4f, 0x00000001, 0x00000198, 0x00000003,
0x0000002c, 0x00000080, 0x000000d8, 0x4e475349, 0x0000004c, 0x00000002, 0x00000008, 0x00000038,
0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000041, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000707, 0x49534f50, 0x4e4f4954, 0x58455400, 0x524f4f43, 0xabab0044,
0x4e47534f, 0x00000050, 0x00000002, 0x00000008, 0x00000038, 0x00000000, 0x00000001, 0x00000003,
0x00000000, 0x0000000f, 0x00000044, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000807,
0x505f5653, 0x5449534f, 0x004e4f49, 0x43584554, 0x44524f4f, 0xababab00, 0x52444853, 0x000000b8,
0x00010040, 0x0000002e, 0x04000059, 0x00208e46, 0x00000000, 0x00000002, 0x0300005f, 0x001010f2,
0x00000000, 0x0300005f, 0x00101072, 0x00000001, 0x04000067, 0x001020f2, 0x00000000, 0x00000001,
0x03000065, 0x00102072, 0x00000001, 0x08000010, 0x00102012, 0x00000000, 0x00101346, 0x00000000,
0x00208246, 0x00000000, 0x00000000, 0x08000010, 0x00102022, 0x00000000, 0x00101346, 0x00000000,
0x00208246, 0x00000000, 0x00000001, 0x05000036, 0x001020c2, 0x00000000, 0x00101ea6, 0x00000000,
0x05000036, 0x00102072, 0x00000001, 0x00101246, 0x00000001, 0x0100003e,
};
static const DWORD ps_code_triangle_solid[] =
{
/* float4 color;
*
@ -1449,7 +1508,7 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
0x00000010, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03000065, 0x001020f2, 0x00000000,
0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
};
static const DWORD rect_bitmap_ps_code[] =
static const DWORD ps_code_triangle_bitmap[] =
{
#if 0
float3x2 transform;
@ -1487,6 +1546,32 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
0x00000000, 0x0010003a, 0x00000000, 0x0020803a, 0x00000000, 0x00000001, 0x05000036, 0x00102072,
0x00000000, 0x00100246, 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[] =
{
#if 0
float4 color;
float4 main(float4 position : SV_POSITION, float3 t : TEXCOORD0) : SV_Target
{
clip((t.x * t.x - t.y) * t.z);
return color;
}
#endif
0x43425844, 0x66075f9e, 0x2ffe405b, 0xb551ee63, 0xa0d9f457, 0x00000001, 0x00000180, 0x00000003,
0x0000002c, 0x00000084, 0x000000b8, 0x4e475349, 0x00000050, 0x00000002, 0x00000008, 0x00000038,
0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x00000044, 0x00000000, 0x00000000,
0x00000003, 0x00000001, 0x00000707, 0x505f5653, 0x5449534f, 0x004e4f49, 0x43584554, 0x44524f4f,
0xababab00, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000,
0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x52444853, 0x000000c0,
0x00000040, 0x00000030, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x03001062, 0x00101072,
0x00000001, 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x0a000032, 0x00100012,
0x00000000, 0x0010100a, 0x00000001, 0x0010100a, 0x00000001, 0x8010101a, 0x00000041, 0x00000001,
0x07000038, 0x00100012, 0x00000000, 0x0010000a, 0x00000000, 0x0010102a, 0x00000001, 0x07000031,
0x00100012, 0x00000000, 0x0010000a, 0x00000000, 0x00004001, 0x00000000, 0x0304000d, 0x0010000a,
0x00000000, 0x06000036, 0x001020f2, 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x0100003e,
};
static const struct
{
float x, y;
@ -1547,11 +1632,57 @@ 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,
sizeof(il_desc) / sizeof(*il_desc), vs_code, sizeof(vs_code),
&render_target->il)))
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)))
{
WARN("Failed to create clear input layout, hr %#x.\n", hr);
WARN("Failed to create triangle 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)))
{
WARN("Failed to create bezier input layout, 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)))
{
WARN("Failed to create triangle vertex shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreateVertexShader(render_target->device, vs_code_bezier,
sizeof(vs_code_bezier), &render_target->shape_resources[D2D_SHAPE_TYPE_BEZIER].vs)))
{
WARN("Failed to create bezier vertex shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
ps_code_triangle_solid, sizeof(ps_code_triangle_solid),
&render_target->shape_resources[D2D_SHAPE_TYPE_TRIANGLE].ps[D2D_BRUSH_TYPE_SOLID])))
{
WARN("Failed to create triangle/solid pixel shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
ps_code_triangle_bitmap, sizeof(ps_code_triangle_bitmap),
&render_target->shape_resources[D2D_SHAPE_TYPE_TRIANGLE].ps[D2D_BRUSH_TYPE_BITMAP])))
{
WARN("Failed to create triangle/bitmap pixel shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
ps_code_bezier_solid, sizeof(ps_code_bezier_solid),
&render_target->shape_resources[D2D_SHAPE_TYPE_BEZIER].ps[D2D_BRUSH_TYPE_SOLID])))
{
WARN("Failed to create bezier/solid pixel shader, hr %#x.\n", hr);
goto err;
}
@ -1584,13 +1715,6 @@ 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, sizeof(vs_code), &render_target->vs)))
{
WARN("Failed to create clear vertex shader, hr %#x.\n", hr);
goto err;
}
rs_desc.FillMode = D3D10_FILL_SOLID;
rs_desc.CullMode = D3D10_CULL_BACK;
rs_desc.FrontCounterClockwise = FALSE;
@ -1622,20 +1746,6 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
goto err;
}
if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
rect_solid_ps_code, sizeof(rect_solid_ps_code), &render_target->rect_solid_ps)))
{
WARN("Failed to create pixel shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = ID3D10Device_CreatePixelShader(render_target->device,
rect_bitmap_ps_code, sizeof(rect_bitmap_ps_code), &render_target->rect_bitmap_ps)))
{
WARN("Failed to create pixel shader, hr %#x.\n", hr);
goto err;
}
if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
{
WARN("Failed to get surface desc, hr %#x.\n", hr);
@ -1665,22 +1775,26 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target,
return S_OK;
err:
if (render_target->rect_bitmap_ps)
ID3D10PixelShader_Release(render_target->rect_bitmap_ps);
if (render_target->rect_solid_ps)
ID3D10PixelShader_Release(render_target->rect_solid_ps);
if (render_target->bs)
ID3D10BlendState_Release(render_target->bs);
if (render_target->rs)
ID3D10RasterizerState_Release(render_target->rs);
if (render_target->vs)
ID3D10VertexShader_Release(render_target->vs);
if (render_target->vb)
ID3D10Buffer_Release(render_target->vb);
if (render_target->ib)
ID3D10Buffer_Release(render_target->ib);
if (render_target->il)
ID3D10InputLayout_Release(render_target->il);
for (i = 0; i < D2D_SHAPE_TYPE_COUNT; ++i)
{
for (j = 0; j < D2D_BRUSH_TYPE_COUNT; ++j)
{
if (render_target->shape_resources[i].ps[j])
ID3D10PixelShader_Release(render_target->shape_resources[i].ps[j]);
}
if (render_target->shape_resources[i].vs)
ID3D10VertexShader_Release(render_target->shape_resources[i].vs);
if (render_target->shape_resources[i].il)
ID3D10InputLayout_Release(render_target->shape_resources[i].il);
}
if (render_target->stateblock)
render_target->stateblock->lpVtbl->Release(render_target->stateblock);
if (render_target->view)

View File

@ -24,12 +24,27 @@
#include "initguid.h"
#include "dwrite.h"
struct figure
{
unsigned int *spans;
unsigned int spans_size;
unsigned int span_count;
};
static void set_point(D2D1_POINT_2F *point, float x, float y)
{
point->x = x;
point->y = y;
}
static void set_quadratic(D2D1_QUADRATIC_BEZIER_SEGMENT *quadratic, float x1, float y1, float x2, float y2)
{
quadratic->point1.x = x1;
quadratic->point1.y = y1;
quadratic->point2.x = x2;
quadratic->point2.y = y2;
}
static void set_rect(D2D1_RECT_F *rect, float left, float top, float right, float bottom)
{
rect->left = left;
@ -179,6 +194,192 @@ static BOOL compare_surface(IDXGISurface *surface, const char *ref_sha1)
return ret;
}
static void serialize_figure(struct figure *figure)
{
static const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned int i, j, k, span;
char output[76];
char t[3];
char *p;
for (i = 0, j = 0, k = 0, p = output; i < figure->span_count; ++i)
{
span = figure->spans[i];
while (span)
{
t[j] = span & 0x7f;
if (span > 0x7f)
t[j] |= 0x80;
span >>= 7;
if (++j == 3)
{
p[0] = lookup[(t[0] & 0xfc) >> 2];
p[1] = lookup[((t[0] & 0x03) << 4) | ((t[1] & 0xf0) >> 4)];
p[2] = lookup[((t[1] & 0x0f) << 2) | ((t[2] & 0xc0) >> 6)];
p[3] = lookup[t[2] & 0x3f];
p += 4;
if (++k == 19)
{
trace("%.76s\n", output);
p = output;
k = 0;
}
j = 0;
}
}
}
if (j)
{
for (i = j; i < 3; ++i)
t[i] = 0;
p[0] = lookup[(t[0] & 0xfc) >> 2];
p[1] = lookup[((t[0] & 0x03) << 4) | ((t[1] & 0xf0) >> 4)];
p[2] = lookup[((t[1] & 0x0f) << 2) | ((t[2] & 0xc0) >> 6)];
p[3] = lookup[t[2] & 0x3f];
++k;
}
if (k)
trace("%.*s\n", k * 4, output);
}
static void deserialize_span(struct figure *figure, unsigned int *current, unsigned int *shift, unsigned int c)
{
*current |= (c & 0x7f) << *shift;
if (c & 0x80)
{
*shift += 7;
return;
}
if (figure->span_count == figure->spans_size)
{
figure->spans_size *= 2;
figure->spans = HeapReAlloc(GetProcessHeap(), 0, figure->spans,
figure->spans_size * sizeof(*figure->spans));
}
figure->spans[figure->span_count++] = *current;
*current = 0;
*shift = 0;
}
static void deserialize_figure(struct figure *figure, const BYTE *s)
{
static const BYTE lookup[] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
};
unsigned int current = 0, shift = 0;
const BYTE *ptr;
BYTE x, y;
figure->span_count = 0;
figure->spans_size = 64;
figure->spans = HeapAlloc(GetProcessHeap(), 0, figure->spans_size * sizeof(*figure->spans));
for (ptr = s; *ptr; ptr += 4)
{
x = lookup[ptr[0]];
y = lookup[ptr[1]];
deserialize_span(figure, &current, &shift, ((x & 0x3f) << 2) | ((y & 0x3f) >> 4));
x = lookup[ptr[2]];
deserialize_span(figure, &current, &shift, ((y & 0x0f) << 4) | ((x & 0x3f) >> 2));
y = lookup[ptr[3]];
deserialize_span(figure, &current, &shift, ((x & 0x03) << 6) | (y & 0x3f));
}
}
static BOOL compare_figure(IDXGISurface *surface, unsigned int x, unsigned int y,
unsigned int w, unsigned int h, DWORD prev, unsigned int max_diff, const char *ref)
{
D3D10_MAPPED_TEXTURE2D mapped_texture;
D3D10_TEXTURE2D_DESC texture_desc;
struct figure ref_figure, figure;
DXGI_SURFACE_DESC surface_desc;
unsigned int i, j, span, diff;
ID3D10Resource *src_resource;
ID3D10Texture2D *texture;
ID3D10Device *device;
HRESULT hr;
hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&device);
ok(SUCCEEDED(hr), "Failed to get device, hr %#x.\n", hr);
hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&src_resource);
ok(SUCCEEDED(hr), "Failed to query resource interface, hr %#x.\n", hr);
hr = IDXGISurface_GetDesc(surface, &surface_desc);
ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
texture_desc.Width = surface_desc.Width;
texture_desc.Height = surface_desc.Height;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = surface_desc.Format;
texture_desc.SampleDesc = surface_desc.SampleDesc;
texture_desc.Usage = D3D10_USAGE_STAGING;
texture_desc.BindFlags = 0;
texture_desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
texture_desc.MiscFlags = 0;
hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture);
ok(SUCCEEDED(hr), "Failed to create texture, hr %#x.\n", hr);
ID3D10Device_CopyResource(device, (ID3D10Resource *)texture, src_resource);
hr = ID3D10Texture2D_Map(texture, 0, D3D10_MAP_READ, 0, &mapped_texture);
ok(SUCCEEDED(hr), "Failed to map texture, hr %#x.\n", hr);
figure.span_count = 0;
figure.spans_size = 64;
figure.spans = HeapAlloc(GetProcessHeap(), 0, figure.spans_size * sizeof(*figure.spans));
for (i = 0, span = 0; i < h; ++i)
{
const DWORD *row = (DWORD *)((BYTE *)mapped_texture.pData + (y + i) * mapped_texture.RowPitch + x * 4);
for (j = 0; j < w; ++j, ++span)
{
if ((i || j) && prev != row[j])
{
if (figure.span_count == figure.spans_size)
{
figure.spans_size *= 2;
figure.spans = HeapReAlloc(GetProcessHeap(), 0, figure.spans,
figure.spans_size * sizeof(*figure.spans));
}
figure.spans[figure.span_count++] = span;
prev = row[j];
span = 0;
}
}
}
deserialize_figure(&ref_figure, (BYTE *)ref);
j = min(figure.span_count, ref_figure.span_count);
for (i = 0, diff = 0; i < j; ++i)
diff += abs(figure.spans[i] - ref_figure.spans[i]);
for (i = j; j < figure.span_count; ++j)
diff += figure.spans[i];
for (i = j; j < ref_figure.span_count; ++j)
diff += ref_figure.spans[i];
if (diff > max_diff)
serialize_figure(&figure);
HeapFree(GetProcessHeap(), 0, ref_figure.spans);
HeapFree(GetProcessHeap(), 0, figure.spans);
ID3D10Texture2D_Unmap(texture, 0);
ID3D10Texture2D_Release(texture);
ID3D10Resource_Release(src_resource);
ID3D10Device_Release(device);
return diff <= max_diff;
}
static ID3D10Device1 *create_device(void)
{
ID3D10Device1 *device;
@ -982,6 +1183,36 @@ static void fill_geometry_sink(ID2D1GeometrySink *sink)
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
}
static void fill_geometry_sink_bezier(ID2D1GeometrySink *sink)
{
D2D1_QUADRATIC_BEZIER_SEGMENT quadratic;
D2D1_POINT_2F point;
set_point(&point, 5.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
set_quadratic(&quadratic, 40.0f, 160.0f, 40.0f, 20.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 40.0f, 160.0f, 75.0f, 160.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 40.0f, 160.0f, 40.0f, 300.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 40.0f, 160.0f, 5.0f, 160.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
set_point(&point, 20.0f, 160.0f);
ID2D1GeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
set_quadratic(&quadratic, 20.0f, 80.0f, 40.0f, 80.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 60.0f, 80.0f, 60.0f, 160.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 60.0f, 240.0f, 40.0f, 240.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
set_quadratic(&quadratic, 20.0f, 240.0f, 20.0f, 160.0f);
ID2D1GeometrySink_AddQuadraticBezier(sink, &quadratic);
ID2D1GeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
}
static void test_path_geometry(void)
{
ID2D1GeometrySink *sink, *tmp_sink;
@ -1227,6 +1458,68 @@ static void test_path_geometry(void)
ok(match, "Surface does not match.\n");
ID2D1PathGeometry_Release(geometry);
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);
fill_geometry_sink_bezier(sink);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
hr = ID2D1PathGeometry_GetFigureCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get figure count, hr %#x.\n", hr);
ok(count == 2, "Got unexpected figure count %u.\n", count);
hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
ok(count == 10, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
ID2D1RenderTarget_BeginDraw(rt);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_FillGeometry(rt, (ID2D1Geometry *)geometry, (ID2D1Brush *)brush, NULL);
hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr);
match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 64,
"7xoCngECngECngECngECngECngECngECnQEEnAEEnAEEnAEEnAEEmwEGmgEGmgEGmgEGmQEImAEI"
"lAEECASLAQgKCIEBDQoMew8KD3YQDBByEgwSbhMOEmwUDhRpFBAUZxUQFWUVEhVjFhIWYRYUFl8X"
"FBddFxYWXRYYFlsXGBdaFhoWWRYcFlgVHhVXFSAVVhQiFFUUIxRVEyYTVBIoElQRKhFUECwQUxAu"
"EFIOMg5SDTQNUgs4C1IJPAlRCEAIUAZEBlAESARQAU4BTgJQAkgGUAY/C1ALMhNQEyoTUBMyC1AL"
"PwZQBkgCUAJOAU4BUARIBFAGRAZQCEAIUQk8CVILOAtSDTQNUg4yDlIQLhBTECwQVBEqEVQSKBJU"
"EyYTVBQjFFYUIhRWFSAVVxUeFVgWHBZZFhoWWhcYF1sWGBZcFxYWXhcUF18WFBZhFhIWYxUSFWUV"
"EBVnFBAUaRQOFGsTDhJvEgwSchAMEHYPCg96DQoMggEICgiLAQQIBJQBCJgBCJkBBpoBBpoBBpoB"
"BpsBBJwBBJwBBJwBBJwBBJ0BAp4BAp4BAp4BAp4BAp4BAp4BAp4BAgAA");
todo_wine ok(match, "Figure does not match.\n");
ID2D1PathGeometry_Release(geometry);
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);
fill_geometry_sink_bezier(sink);
ID2D1GeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
hr = ID2D1GeometrySink_Close(sink);
ok(SUCCEEDED(hr), "Failed to close geometry sink, hr %#x.\n", hr);
hr = ID2D1PathGeometry_GetFigureCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get figure count, hr %#x.\n", hr);
ok(count == 2, "Got unexpected figure count %u.\n", count);
hr = ID2D1PathGeometry_GetSegmentCount(geometry, &count);
ok(SUCCEEDED(hr), "Failed to get segment count, hr %#x.\n", hr);
ok(count == 10, "Got unexpected segment count %u.\n", count);
ID2D1GeometrySink_Release(sink);
ID2D1RenderTarget_BeginDraw(rt);
ID2D1RenderTarget_Clear(rt, &color);
ID2D1RenderTarget_FillGeometry(rt, (ID2D1Geometry *)geometry, (ID2D1Brush *)brush, NULL);
hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL);
ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr);
match = compare_figure(surface, 0, 0, 160, 160, 0xff652e89, 64,
"7xoCngECngECngECngECngECngECngECnQEEnAEEnAEEnAEEnAEEmwEGmgEGmgEGmgEGmQEImAEI"
"lAEQiwEagQEjeyh2LHIwbjNsNmk4ZzplPGM+YUBfQl1DXURbRlpGWUhYSFdKVkpVS1VMVExUTFRM"
"U05STlJOUk5STlFQUFBQUFBQTlRIXD9mMnYqdjJmP1xIVE5QUFBQUFBQUU5STlJOUk5STlNMVExU"
"TFRMVEtWSlZKV0hYSFlGWkZbRFxDXkJfQGE+YzxlOmc4aTZrM28wcix2KHojggEaiwEQlAEImAEI"
"mQEGmgEGmgEGmgEGmwEEnAEEnAEEnAEEnAEEnQECngECngECngECngECngECngECngEC");
ok(match, "Figure does not match.\n");
ID2D1PathGeometry_Release(geometry);
ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);
refcount = ID2D1Factory_Release(factory);