From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/d2d1_private.h | 13 +++++ dlls/d2d1/mesh.c | 101 ++++++++++++++++++++++++++++++++++++++- dlls/d2d1/tests/d2d1.c | 77 +++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 46999eaa272..e910b19db28 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -410,12 +410,25 @@ struct d2d_layer
HRESULT d2d_layer_create(ID2D1Factory *factory, const D2D1_SIZE_F *size, struct d2d_layer **layer);
+enum d2d_mesh_state +{ + D2D_MESH_STATE_INITIAL = 0, + D2D_MESH_STATE_OPEN, + D2D_MESH_STATE_CLOSED, +}; + struct d2d_mesh { ID2D1Mesh ID2D1Mesh_iface; + ID2D1TessellationSink ID2D1TessellationSink_iface; LONG refcount;
ID2D1Factory *factory; + enum d2d_mesh_state state; + + D2D1_TRIANGLE *triangles; + size_t count; + size_t size; };
HRESULT d2d_mesh_create(ID2D1Factory *factory, struct d2d_mesh **mesh); diff --git a/dlls/d2d1/mesh.c b/dlls/d2d1/mesh.c index cd6a5d13a89..a782e01a551 100644 --- a/dlls/d2d1/mesh.c +++ b/dlls/d2d1/mesh.c @@ -25,6 +25,11 @@ static inline struct d2d_mesh *impl_from_ID2D1Mesh(ID2D1Mesh *iface) return CONTAINING_RECORD(iface, struct d2d_mesh, ID2D1Mesh_iface); }
+static inline struct d2d_mesh *impl_from_ID2D1TessellationSink(ID2D1TessellationSink *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_mesh, ID2D1TessellationSink_iface); +} + static HRESULT STDMETHODCALLTYPE d2d_mesh_QueryInterface(ID2D1Mesh *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -64,6 +69,7 @@ static ULONG STDMETHODCALLTYPE d2d_mesh_Release(ID2D1Mesh *iface) if (!refcount) { ID2D1Factory_Release(mesh->factory); + free(mesh->triangles); free(mesh); }
@@ -81,9 +87,21 @@ static void STDMETHODCALLTYPE d2d_mesh_GetFactory(ID2D1Mesh *iface, ID2D1Factory
static HRESULT STDMETHODCALLTYPE d2d_mesh_Open(ID2D1Mesh *iface, ID2D1TessellationSink **sink) { - FIXME("iface %p, sink %p stub!\n", iface, sink); + struct d2d_mesh *mesh = impl_from_ID2D1Mesh(iface); + + TRACE("iface %p, sink %p.\n", iface, sink); + + *sink = NULL; + + if (mesh->state != D2D_MESH_STATE_INITIAL) + return D2DERR_WRONG_STATE;
- return E_NOTIMPL; + *sink = &mesh->ID2D1TessellationSink_iface; + ID2D1TessellationSink_AddRef(*sink); + + mesh->state = D2D_MESH_STATE_OPEN; + + return S_OK; }
static const struct ID2D1MeshVtbl d2d_mesh_vtbl = @@ -95,12 +113,91 @@ static const struct ID2D1MeshVtbl d2d_mesh_vtbl = d2d_mesh_Open, };
+static HRESULT STDMETHODCALLTYPE d2d_mesh_sink_QueryInterface(ID2D1TessellationSink *iface, + REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1TessellationSink) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1TessellationSink_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d2d_mesh_sink_AddRef(ID2D1TessellationSink *iface) +{ + struct d2d_mesh *mesh = impl_from_ID2D1TessellationSink(iface); + + TRACE("iface %p.\n", iface); + + return ID2D1Mesh_AddRef(&mesh->ID2D1Mesh_iface); +} + +static ULONG STDMETHODCALLTYPE d2d_mesh_sink_Release(ID2D1TessellationSink *iface) +{ + struct d2d_mesh *mesh = impl_from_ID2D1TessellationSink(iface); + + TRACE("iface %p.\n", iface); + + return ID2D1Mesh_Release(&mesh->ID2D1Mesh_iface); +} + +static void STDMETHODCALLTYPE d2d_mesh_sink_AddTriangles(ID2D1TessellationSink *iface, + const D2D1_TRIANGLE *triangles, UINT32 count) +{ + struct d2d_mesh *mesh = impl_from_ID2D1TessellationSink(iface); + + TRACE("iface %p, triangles %p, count %u.\n", iface, triangles, count); + + if (!d2d_array_reserve((void **)&mesh->triangles, &mesh->size, + mesh->count + count, sizeof(*mesh->triangles))) + { + WARN("Failed to grow mesh triangles array.\n"); + return; + } + + memcpy(&mesh->triangles[mesh->count], triangles, count * sizeof(*triangles)); + mesh->count += count; +} + +static HRESULT STDMETHODCALLTYPE d2d_mesh_sink_Close(ID2D1TessellationSink *iface) +{ + struct d2d_mesh *mesh = impl_from_ID2D1TessellationSink(iface); + + TRACE("iface %p.\n", iface); + + if (mesh->state != D2D_MESH_STATE_OPEN) + return D2DERR_WRONG_STATE; + + mesh->state = D2D_MESH_STATE_CLOSED; + + return S_OK; +} + +static const ID2D1TessellationSinkVtbl d2d_mesh_sink_vtbl = +{ + d2d_mesh_sink_QueryInterface, + d2d_mesh_sink_AddRef, + d2d_mesh_sink_Release, + d2d_mesh_sink_AddTriangles, + d2d_mesh_sink_Close, +}; + HRESULT d2d_mesh_create(ID2D1Factory *factory, struct d2d_mesh **mesh) { if (!(*mesh = calloc(1, sizeof(**mesh)))) return E_OUTOFMEMORY;
(*mesh)->ID2D1Mesh_iface.lpVtbl = &d2d_mesh_vtbl; + (*mesh)->ID2D1TessellationSink_iface.lpVtbl = &d2d_mesh_sink_vtbl; (*mesh)->refcount = 1; ID2D1Factory_AddRef((*mesh)->factory = factory);
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 12c199e2377..5e8cbed748e 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15913,6 +15913,82 @@ static void test_no_target(BOOL d3d11) release_test_context(&ctx); }
+static void test_mesh(BOOL d3d11) +{ + ID2D1TessellationSink *sink, *sink2; + struct d2d1_test_context ctx; + D2D1_TRIANGLE triangles[2]; + ID2D1RenderTarget *rt; + ID2D1Factory *factory; + ID2D1Mesh *mesh; + HRESULT hr; + + if (!init_test_context(&ctx, d3d11)) + return; + + rt = ctx.rt; + hr = ID2D1RenderTarget_CreateMesh(rt, &mesh); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_interface(mesh, &IID_IUnknown, TRUE); + check_interface(mesh, &IID_ID2D1Resource, TRUE); + check_interface(mesh, &IID_ID2D1Mesh, TRUE); + check_interface(mesh, &IID_ID2D1TessellationSink, FALSE); + + ID2D1Mesh_GetFactory(mesh, &factory); + ok(ctx.factory == factory, "Unexpected factory.\n"); + ID2D1Factory_Release(factory); + + hr = ID2D1Mesh_Open(mesh, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_interface(sink, &IID_IUnknown, TRUE); + check_interface(sink, &IID_ID2D1TessellationSink, TRUE); + check_interface(sink, &IID_ID2D1Mesh, FALSE); + + sink2 = (void *)0xdeadbeef; + hr = ID2D1Mesh_Open(mesh, &sink2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(!sink2, "Unexpected pointer %p.\n", sink2); + + /* Close empty sink */ + hr = ID2D1TessellationSink_Close(sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1TessellationSink_Close(sink); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + + ID2D1TessellationSink_Release(sink); + + hr = ID2D1Mesh_Open(mesh, &sink); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + + ID2D1Mesh_Release(mesh); + + /* Add some triangles */ + hr = ID2D1RenderTarget_CreateMesh(rt, &mesh); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Mesh_Open(mesh, &sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_point(&triangles[0].point1, 0.0f, 0.0f); + set_point(&triangles[0].point2, 10.0f, 20.0f); + set_point(&triangles[0].point3, 40.0f, -20.0f); + set_point(&triangles[1].point1, -100.0f, 0.0f); + set_point(&triangles[1].point2, 30.0f, 200.0f); + set_point(&triangles[1].point3, 50.0f, -200.0f); + ID2D1TessellationSink_AddTriangles(sink, triangles, 2); + hr = ID2D1TessellationSink_Close(sink); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1TessellationSink_Release(sink); + + ID2D1Mesh_Release(mesh); + + release_test_context(&ctx); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -16012,6 +16088,7 @@ START_TEST(d2d1) queue_test(test_effect_blob_property); queue_test(test_get_dxgi_device); queue_test(test_no_target); + queue_test(test_mesh);
run_queued_tests(); }