[PATCH 3/5] d2d1: Implement initial support for drawing bezier curves.
Henri Verbeet
hverbeet at codeweavers.com
Mon Jul 20 04:07:28 CDT 2015
---
dlls/d2d1/brush.c | 17 +--
dlls/d2d1/d2d1_private.h | 39 +++++-
dlls/d2d1/geometry.c | 123 +++++++++++++++++--
dlls/d2d1/render_target.c | 282 +++++++++++++++++++++++++++++++-------------
dlls/d2d1/tests/d2d1.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 643 insertions(+), 111 deletions(-)
diff --git a/dlls/d2d1/brush.c b/dlls/d2d1/brush.c
index 762d201..28b896b 100644
--- a/dlls/d2d1/brush.c
+++ b/dlls/d2d1/brush.c
@@ -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)
- {
- ID3D10Device_PSSetShader(device, render_target->rect_solid_ps);
- }
- else if (brush->type == D2D_BRUSH_TYPE_BITMAP)
+ 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_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);
}
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 44c8bd5..377c72a 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -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
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index a511104..ff53bb8 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -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;
}
}
diff --git a/dlls/d2d1/render_target.c b/dlls/d2d1/render_target.c
index 2da50bc..37a8d57 100644
--- a/dlls/d2d1/render_target.c
+++ b/dlls/d2d1/render_target.c
@@ -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 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 clear input layout, hr %#x.\n", hr);
+ 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)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 8351dbe..f8ebecc 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -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, ¤t, &shift, ((x & 0x3f) << 2) | ((y & 0x3f) >> 4));
+ x = lookup[ptr[2]];
+ deserialize_span(figure, ¤t, &shift, ((y & 0x0f) << 4) | ((x & 0x3f) >> 2));
+ y = lookup[ptr[3]];
+ deserialize_span(figure, ¤t, &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);
--
2.1.4
More information about the wine-patches
mailing list