[PATCH 1/1] ddraw/tests: Add some basic material tests.

Henri Verbeet hverbeet at codeweavers.com
Wed Apr 30 05:36:15 CDT 2014


This supersedes patch 104244.
---
 dlls/ddraw/tests/ddraw1.c |  225 ++++++++++++++++++++++++++++++++++++++++++---
 dlls/ddraw/tests/ddraw2.c |  197 ++++++++++++++++++++++++++++++++++-----
 dlls/ddraw/tests/ddraw4.c |  218 ++++++++++++++++++++++++++++++++++++++++---
 dlls/ddraw/tests/ddraw7.c |   44 +++++++++
 4 files changed, 631 insertions(+), 53 deletions(-)

diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index a48cf55..1b41f6e 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -126,7 +126,7 @@ static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
     return color;
 }
 
-static void emit_process_vertices(void **ptr, WORD base_idx, DWORD vertex_count)
+static void emit_process_vertices(void **ptr, DWORD flags, WORD base_idx, DWORD vertex_count)
 {
     D3DINSTRUCTION *inst = *ptr;
     D3DPROCESSVERTICES *pv = (D3DPROCESSVERTICES *)(inst + 1);
@@ -135,7 +135,7 @@ static void emit_process_vertices(void **ptr, WORD base_idx, DWORD vertex_count)
     inst->bSize = sizeof(*pv);
     inst->wCount = 1;
 
-    pv->dwFlags = D3DPROCESSVERTICES_COPY;
+    pv->dwFlags = flags;
     pv->wStart = base_idx;
     pv->wDest = 0;
     pv->dwCount = vertex_count;
@@ -144,6 +144,21 @@ static void emit_process_vertices(void **ptr, WORD base_idx, DWORD vertex_count)
     *ptr = pv + 1;
 }
 
+static void emit_set_ls(void **ptr, D3DLIGHTSTATETYPE state, DWORD value)
+{
+    D3DINSTRUCTION *inst = *ptr;
+    D3DSTATE *ls = (D3DSTATE *)(inst + 1);
+
+    inst->bOpcode = D3DOP_STATELIGHT;
+    inst->bSize = sizeof(*ls);
+    inst->wCount = 1;
+
+    U1(*ls).dlstLightStateType = state;
+    U2(*ls).dwArg[0] = value;
+
+    *ptr = ls + 1;
+}
+
 static void emit_set_rs(void **ptr, D3DRENDERSTATETYPE state, DWORD value)
 {
     D3DINSTRUCTION *inst = *ptr;
@@ -361,10 +376,9 @@ static void destroy_viewport(IDirect3DDevice *device, IDirect3DViewport *viewpor
     IDirect3DViewport_Release(viewport);
 }
 
-static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float r, float g, float b, float a)
+static IDirect3DMaterial *create_material(IDirect3DDevice *device, D3DMATERIAL *mat)
 {
     IDirect3DMaterial *material;
-    D3DMATERIAL mat;
     IDirect3D *d3d;
     HRESULT hr;
 
@@ -372,17 +386,39 @@ static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float
     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
     hr = IDirect3D_CreateMaterial(d3d, &material, NULL);
     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
+    hr = IDirect3DMaterial_SetMaterial(material, mat);
+    ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
+    IDirect3D_Release(d3d);
+
+    return material;
+}
+
+static IDirect3DMaterial *create_diffuse_material(IDirect3DDevice *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
     memset(&mat, 0, sizeof(mat));
     mat.dwSize = sizeof(mat);
     U1(U(mat).diffuse).r = r;
     U2(U(mat).diffuse).g = g;
     U3(U(mat).diffuse).b = b;
     U4(U(mat).diffuse).a = a;
-    hr = IDirect3DMaterial_SetMaterial(material, &mat);
-    ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
-    IDirect3D_Release(d3d);
 
-    return material;
+    return create_material(device, &mat);
+}
+
+static IDirect3DMaterial *create_emissive_material(IDirect3DDevice *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
+    memset(&mat, 0, sizeof(mat));
+    mat.dwSize = sizeof(mat);
+    U1(U3(mat).emissive).r = r;
+    U2(U3(mat).emissive).g = g;
+    U3(U3(mat).emissive).b = b;
+    U4(U3(mat).emissive).a = a;
+
+    return create_material(device, &mat);
 }
 
 static void destroy_material(IDirect3DMaterial *material)
@@ -1089,7 +1125,7 @@ static void test_zenable(void)
     ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
     memcpy(exec_desc.lpData, tquad, sizeof(tquad));
     ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
-    emit_process_vertices(&ptr, 0, 4);
+    emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
     emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
     emit_tquad(&ptr, 0);
     emit_end(&ptr);
@@ -1241,7 +1277,7 @@ static void test_ck_rgba(void)
         ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
         memcpy(exec_desc.lpData, tquad, sizeof(tquad));
         ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad);
-        emit_process_vertices(&ptr, 0, 4);
+        emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
         emit_set_rs(&ptr, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
         emit_set_rs(&ptr, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
@@ -1250,7 +1286,7 @@ static void test_ck_rgba(void)
         emit_tquad(&ptr, 0);
         emit_end(&ptr);
         draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - sizeof(tquad);
-        emit_process_vertices(&ptr, 4, 4);
+        emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 4, 4);
         emit_tquad(&ptr, 0);
         emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
         emit_end(&ptr);
@@ -1404,24 +1440,24 @@ static void test_ck_default(void)
     ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
     memcpy(exec_desc.lpData, tquad, sizeof(tquad));
     ptr = (BYTE *)exec_desc.lpData + sizeof(tquad);
-    emit_process_vertices(&ptr, 0, 4);
+    emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
     emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
     emit_tquad(&ptr, 0);
     emit_end(&ptr);
     draw1_offset = sizeof(tquad);
     draw1_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw1_offset;
-    emit_process_vertices(&ptr, 0, 4);
+    emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
     emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
     emit_tquad(&ptr, 0);
     emit_end(&ptr);
     draw2_offset = draw1_offset + draw1_len;
     draw2_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw2_offset;
-    emit_process_vertices(&ptr, 0, 4);
+    emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
     emit_tquad(&ptr, 0);
     emit_end(&ptr);
     draw3_offset = draw2_offset + draw2_len;
     draw3_len = (BYTE *)ptr - (BYTE *)exec_desc.lpData - draw3_offset;
-    emit_process_vertices(&ptr, 0, 4);
+    emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4);
     emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
     emit_tquad(&ptr, 0);
     emit_set_rs(&ptr, D3DRENDERSTATE_TEXTUREHANDLE, 0);
@@ -4800,6 +4836,164 @@ static void test_p8_rgb_blit(void)
     DestroyWindow(window);
 }
 
+static void test_material(void)
+{
+    IDirect3DExecuteBuffer *execute_buffer;
+    D3DMATERIALHANDLE mat_handle, tmp;
+    D3DEXECUTEBUFFERDESC exec_desc;
+    IDirect3DMaterial *material;
+    IDirect3DViewport *viewport;
+    IDirect3DDevice *device;
+    IDirectDrawSurface *rt;
+    IDirectDraw *ddraw;
+    UINT inst_length;
+    D3DCOLOR color;
+    ULONG refcount;
+    unsigned int i;
+    HWND window;
+    HRESULT hr;
+    BOOL valid;
+    void *ptr;
+
+    static D3DVERTEX quad[] =
+    {
+        {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+    };
+    static const struct
+    {
+        BOOL material;
+        D3DCOLOR expected_color;
+    }
+    test_data[] =
+    {
+        {TRUE,  0x0000ff00},
+        {FALSE, 0x00ffffff},
+    };
+    static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt);
+    ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+
+    material = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+    viewport = create_viewport(device, 0, 0, 640, 480);
+    viewport_set_background(device, viewport, material);
+
+    destroy_material(material);
+    material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
+    hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    memset(&exec_desc, 0, sizeof(exec_desc));
+    exec_desc.dwSize = sizeof(exec_desc);
+    exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
+    exec_desc.dwBufferSize = 1024;
+    exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
+
+    hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
+    ok(SUCCEEDED(hr), "Failed to create execute buffer, hr %#x.\n", hr);
+
+    for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
+    {
+        hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
+        ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr);
+
+        memcpy(exec_desc.lpData, quad, sizeof(quad));
+        ptr = ((BYTE *)exec_desc.lpData) + sizeof(quad);
+        emit_set_ls(&ptr, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
+        emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, 4);
+        emit_tquad(&ptr, 0);
+        emit_end(&ptr);
+        inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
+        inst_length -= sizeof(quad);
+
+        hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
+        ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr);
+
+        hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
+        ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice_BeginScene(device);
+        ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+        set_execute_data(execute_buffer, 4, sizeof(quad), inst_length);
+        hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
+        ok(SUCCEEDED(hr), "Failed to execute exec buffer, hr %#x.\n", hr);
+        hr = IDirect3DDevice_EndScene(device);
+        ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+        color = get_surface_color(rt, 320, 240);
+        if (test_data[i].material)
+            todo_wine ok(compare_color(color, test_data[i].expected_color, 1)
+                    /* The Windows 8 testbot appears to return undefined results. */
+                    || broken(TRUE),
+                    "Got unexpected color 0x%08x, test %u.\n", color, i);
+        else
+            ok(compare_color(color, test_data[i].expected_color, 1),
+                    "Got unexpected color 0x%08x, test %u.\n", color, i);
+    }
+
+    destroy_material(material);
+    material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
+    hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    hr = IDirect3DViewport_SetBackground(viewport, mat_handle);
+    ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
+    hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    hr = IDirect3DViewport_SetBackground(viewport, 0);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    destroy_viewport(device, viewport);
+    viewport = create_viewport(device, 0, 0, 640, 480);
+
+    hr = IDirect3DViewport_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+    ok(!valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    IDirect3DExecuteBuffer_Release(execute_buffer);
+    destroy_viewport(device, viewport);
+    destroy_material(material);
+    IDirectDrawSurface_Release(rt);
+    refcount = IDirect3DDevice_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    refcount = IDirectDraw_Release(ddraw);
+    ok(!refcount, "Ddraw object has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw1)
 {
     IDirectDraw *ddraw;
@@ -4847,4 +5041,5 @@ START_TEST(ddraw1)
     test_mipmap_lock();
     test_palette_complex();
     test_p8_rgb_blit();
+    test_material();
 }
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index cd038c5..9003a92 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -309,10 +309,9 @@ static void destroy_viewport(IDirect3DDevice2 *device, IDirect3DViewport2 *viewp
     IDirect3DViewport2_Release(viewport);
 }
 
-static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
+static IDirect3DMaterial2 *create_material(IDirect3DDevice2 *device, D3DMATERIAL *mat)
 {
     IDirect3DMaterial2 *material;
-    D3DMATERIAL mat;
     IDirect3D2 *d3d;
     HRESULT hr;
 
@@ -320,17 +319,39 @@ static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, flo
     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
     hr = IDirect3D2_CreateMaterial(d3d, &material, NULL);
     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
+    hr = IDirect3DMaterial2_SetMaterial(material, mat);
+    ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
+    IDirect3D2_Release(d3d);
+
+    return material;
+}
+
+static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
     memset(&mat, 0, sizeof(mat));
     mat.dwSize = sizeof(mat);
     U1(U(mat).diffuse).r = r;
     U2(U(mat).diffuse).g = g;
     U3(U(mat).diffuse).b = b;
     U4(U(mat).diffuse).a = a;
-    hr = IDirect3DMaterial2_SetMaterial(material, &mat);
-    ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
-    IDirect3D2_Release(d3d);
 
-    return material;
+    return create_material(device, &mat);
+}
+
+static IDirect3DMaterial2 *create_emissive_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
+    memset(&mat, 0, sizeof(mat));
+    mat.dwSize = sizeof(mat);
+    U1(U3(mat).emissive).r = r;
+    U2(U3(mat).emissive).g = g;
+    U3(U3(mat).emissive).b = b;
+    U4(U3(mat).emissive).a = a;
+
+    return create_material(device, &mat);
 }
 
 static void destroy_material(IDirect3DMaterial2 *material)
@@ -3299,12 +3320,10 @@ static void test_lighting_interface_versions(void)
     IDirect3DDevice2 *device;
     IDirectDrawSurface *rt;
     IDirectDraw2 *ddraw;
-    IDirect3D2 *d3d;
     D3DCOLOR color;
     HWND window;
     HRESULT hr;
     D3DMATERIALHANDLE mat_handle;
-    D3DMATERIAL mat_desc;
     DWORD rs;
     unsigned int i;
     ULONG ref;
@@ -3381,8 +3400,6 @@ static void test_lighting_interface_versions(void)
         DestroyWindow(window);
         return;
     }
-    hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
-    ok(SUCCEEDED(hr), "Failed to get IDirect3D2 interface, hr %#x.\n", hr);
 
     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
@@ -3391,13 +3408,7 @@ static void test_lighting_interface_versions(void)
     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
 
-    memset(&mat_desc, 0, sizeof(mat_desc));
-    mat_desc.dwSize = sizeof(mat_desc);
-    U2(U3(mat_desc).dcvEmissive).g = 1.0f;
-    hr = IDirect3D2_CreateMaterial(d3d, &emissive, NULL);
-    ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
-    hr = IDirect3DMaterial2_SetMaterial(emissive, &mat_desc);
-    ok(SUCCEEDED(hr), "Failed to set material, hr %#x.\n", hr);
+    emissive = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
     hr = IDirect3DMaterial2_GetHandle(emissive, device, &mat_handle);
     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
     hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
@@ -3406,10 +3417,7 @@ static void test_lighting_interface_versions(void)
     ok(SUCCEEDED(hr), "Failed to disable z test, hr %#x.\n", hr);
 
     background = create_diffuse_material(device, 0.1f, 0.1f, 0.1f, 0.1f);
-    hr = IDirect3DMaterial2_GetHandle(background, device, &mat_handle);
-    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
-    hr = IDirect3DViewport2_SetBackground(viewport, mat_handle);
-    ok(SUCCEEDED(hr), "Failed to set background material, hr %#x.\n", hr);
+    viewport_set_background(device, viewport, background);
 
     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, &rs);
     ok(SUCCEEDED(hr), "Failed to get specularenable render state, hr %#x.\n", hr);
@@ -3439,11 +3447,10 @@ static void test_lighting_interface_versions(void)
                 color, tests[i].color, i);
     }
 
-    IDirect3DMaterial2_Release(background);
-    IDirect3DMaterial2_Release(emissive);
+    destroy_material(background);
+    destroy_material(emissive);
     IDirectDrawSurface_Release(rt);
     IDirect3DDevice2_Release(device);
-    IDirect3D2_Release(d3d);
     ref = IDirectDraw2_Release(ddraw);
     ok(ref == 0, "Ddraw object not properly released, refcount %u.\n", ref);
     DestroyWindow(window);
@@ -5914,6 +5921,147 @@ static void test_p8_rgb_blit(void)
     DestroyWindow(window);
 }
 
+static void test_material(void)
+{
+    D3DMATERIALHANDLE mat_handle, tmp;
+    IDirect3DMaterial2 *material;
+    IDirect3DViewport2 *viewport;
+    IDirect3DDevice2 *device;
+    IDirectDrawSurface *rt;
+    IDirectDraw2 *ddraw;
+    D3DCOLOR color;
+    ULONG refcount;
+    unsigned int i;
+    HWND window;
+    HRESULT hr;
+    BOOL valid;
+
+    static D3DVERTEX quad[] =
+    {
+        {{-1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{-1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{ 1.0f}, {-1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+        {{ 1.0f}, { 1.0f}, {0.0f}, {1.0f}, {0.0f}, {0.0f}},
+    };
+    static const struct
+    {
+        BOOL material;
+        D3DCOLOR expected_color;
+    }
+    test_data[] =
+    {
+        {TRUE,  0x0000ff00},
+        {FALSE, 0x00ffffff},
+    };
+    static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    ddraw = create_ddraw();
+    ok(!!ddraw, "Failed to create a ddraw object.\n");
+    if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
+    ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+
+    material = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+    viewport = create_viewport(device, 0, 0, 640, 480);
+    viewport_set_background(device, viewport, material);
+    hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
+    ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
+
+    destroy_material(material);
+    material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
+    hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+    hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
+    ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+    hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, 0);
+    ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+    hr = IDirect3DDevice2_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+
+    for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
+    {
+        hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
+        ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
+        ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice2_BeginScene(device);
+        ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+        hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_VERTEX, quad, 4, 0);
+        ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+        hr = IDirect3DDevice2_EndScene(device);
+        ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+        color = get_surface_color(rt, 320, 240);
+        ok(compare_color(color, test_data[i].expected_color, 1),
+                "Got unexpected color 0x%08x, test %u.\n", color, i);
+    }
+
+    destroy_material(material);
+    material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
+    hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    hr = IDirect3DViewport2_SetBackground(viewport, mat_handle);
+    ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
+    hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    hr = IDirect3DViewport2_SetBackground(viewport, 0);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    destroy_viewport(device, viewport);
+    viewport = create_viewport(device, 0, 0, 640, 480);
+
+    hr = IDirect3DViewport2_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+    ok(!valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    destroy_viewport(device, viewport);
+    destroy_material(material);
+    IDirectDrawSurface_Release(rt);
+    refcount = IDirect3DDevice2_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    refcount = IDirectDraw2_Release(ddraw);
+    ok(!refcount, "Ddraw object has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw2)
 {
     IDirectDraw2 *ddraw;
@@ -5967,4 +6115,5 @@ START_TEST(ddraw2)
     test_mipmap_lock();
     test_palette_complex();
     test_p8_rgb_blit();
+    test_material();
 }
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 8becc1f..4955d7e 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -339,6 +339,56 @@ static void destroy_viewport(IDirect3DDevice3 *device, IDirect3DViewport3 *viewp
     IDirect3DViewport3_Release(viewport);
 }
 
+static IDirect3DMaterial3 *create_material(IDirect3DDevice3 *device, D3DMATERIAL *mat)
+{
+    IDirect3DMaterial3 *material;
+    IDirect3D3 *d3d;
+    HRESULT hr;
+
+    hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+    ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
+    hr = IDirect3D3_CreateMaterial(d3d, &material, NULL);
+    ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
+    hr = IDirect3DMaterial3_SetMaterial(material, mat);
+    ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
+    IDirect3D3_Release(d3d);
+
+    return material;
+}
+
+static IDirect3DMaterial3 *create_diffuse_material(IDirect3DDevice3 *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
+    memset(&mat, 0, sizeof(mat));
+    mat.dwSize = sizeof(mat);
+    U1(U(mat).diffuse).r = r;
+    U2(U(mat).diffuse).g = g;
+    U3(U(mat).diffuse).b = b;
+    U4(U(mat).diffuse).a = a;
+
+    return create_material(device, &mat);
+}
+
+static IDirect3DMaterial3 *create_emissive_material(IDirect3DDevice3 *device, float r, float g, float b, float a)
+{
+    D3DMATERIAL mat;
+
+    memset(&mat, 0, sizeof(mat));
+    mat.dwSize = sizeof(mat);
+    U1(U3(mat).emissive).r = r;
+    U2(U3(mat).emissive).g = g;
+    U3(U3(mat).emissive).b = b;
+    U4(U3(mat).emissive).a = a;
+
+    return create_material(device, &mat);
+}
+
+static void destroy_material(IDirect3DMaterial3 *material)
+{
+    IDirect3DMaterial3_Release(material);
+}
+
 static const UINT *expect_messages;
 
 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
@@ -3569,12 +3619,10 @@ static void test_lighting_interface_versions(void)
     IDirect3DViewport3 *viewport;
     IDirect3DDevice3 *device;
     IDirectDrawSurface4 *rt;
-    IDirect3D3 *d3d;
     D3DCOLOR color;
     HWND window;
     HRESULT hr;
     D3DMATERIALHANDLE mat_handle;
-    D3DMATERIAL mat_desc;
     DWORD rs;
     unsigned int i;
     ULONG ref;
@@ -3712,8 +3760,6 @@ static void test_lighting_interface_versions(void)
         DestroyWindow(window);
         return;
     }
-    hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
-    ok(SUCCEEDED(hr), "Failed to get IDirect3D3 interface, hr %#x.\n", hr);
 
     hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
@@ -3722,13 +3768,7 @@ static void test_lighting_interface_versions(void)
     hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
 
-    memset(&mat_desc, 0, sizeof(mat_desc));
-    mat_desc.dwSize = sizeof(mat_desc);
-    U2(U3(mat_desc).dcvEmissive).g = 1.0f;
-    hr = IDirect3D3_CreateMaterial(d3d, &emissive, NULL);
-    ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
-    hr = IDirect3DMaterial3_SetMaterial(emissive, &mat_desc);
-    ok(SUCCEEDED(hr), "Failed to set material, hr %#x.\n", hr);
+    emissive = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
     hr = IDirect3DMaterial3_GetHandle(emissive, device, &mat_handle);
     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
     hr = IDirect3DDevice3_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
@@ -3764,12 +3804,10 @@ static void test_lighting_interface_versions(void)
                 color, tests[i].color, i);
     }
 
-    IDirect3DMaterial3_Release(emissive);
+    destroy_material(emissive);
     IDirectDrawSurface4_Release(rt);
     ref = IDirect3DDevice3_Release(device);
     ok(ref == 0, "Device not properly released, refcount %u.\n", ref);
-    ref = IDirect3D3_Release(d3d);
-    ok(ref == 0, "D3d not properly released, refcount %u.\n", ref);
     DestroyWindow(window);
 }
 
@@ -6775,6 +6813,157 @@ static void test_p8_rgb_blit(void)
     DestroyWindow(window);
 }
 
+static void test_material(void)
+{
+    D3DMATERIALHANDLE mat_handle, tmp;
+    IDirect3DMaterial3 *material;
+    IDirect3DViewport3 *viewport;
+    IDirect3DDevice3 *device;
+    IDirectDrawSurface4 *rt;
+    D3DCOLOR color;
+    ULONG refcount;
+    unsigned int i;
+    HWND window;
+    HRESULT hr;
+    BOOL valid;
+
+    static struct
+    {
+        struct vec3 position;
+        struct vec3 normal;
+        D3DCOLOR diffuse;
+    }
+    quad1[] =
+    {
+        {{-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffffffff},
+        {{-1.0f,  1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffffffff},
+        {{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffffffff},
+        {{ 1.0f,  1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffffffff},
+    },
+    quad2[] =
+    {
+        {{-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffff0000},
+        {{-1.0f,  1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffff0000},
+        {{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffff0000},
+        {{ 1.0f,  1.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, 0xffff0000},
+    };
+    static const struct
+    {
+        void *data;
+        BOOL material;
+        D3DCOLOR expected_color;
+    }
+    test_data[] =
+    {
+        {quad1, TRUE,  0x0000ff00},
+        {quad2, TRUE,  0x0000ff00},
+        {quad1, FALSE, 0x00ffffff},
+        {quad2, FALSE, 0x00ff0000},
+    };
+    static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice3_GetRenderTarget(device, &rt);
+    ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
+
+    viewport = create_viewport(device, 0, 0, 640, 480);
+    hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
+    ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
+
+    material = create_emissive_material(device, 0.0f, 1.0f, 0.0f, 0.0f);
+    hr = IDirect3DMaterial3_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice3_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+    hr = IDirect3DDevice3_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle);
+    ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+    hr = IDirect3DDevice3_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    hr = IDirect3DDevice3_SetLightState(device, D3DLIGHTSTATE_MATERIAL, 0);
+    ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+    hr = IDirect3DDevice3_GetLightState(device, D3DLIGHTSTATE_MATERIAL, &tmp);
+    ok(SUCCEEDED(hr), "Failed to get light state, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+
+    for (i = 0; i < sizeof(test_data) / sizeof(*test_data); ++i)
+    {
+        hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect,
+                D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff0000ff, 1.0f, 0);
+        ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice3_SetLightState(device, D3DLIGHTSTATE_MATERIAL, test_data[i].material ? mat_handle : 0);
+        ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr);
+
+        hr = IDirect3DDevice3_BeginScene(device);
+        ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
+        hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP,
+                D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE, test_data[i].data, 4, 0);
+        ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
+        hr = IDirect3DDevice3_EndScene(device);
+        ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
+        color = get_surface_color(rt, 320, 240);
+        ok(compare_color(color, test_data[i].expected_color, 1),
+                "Got unexpected color 0x%08x, test %u.\n", color, i);
+    }
+
+    destroy_material(material);
+    material = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
+    hr = IDirect3DMaterial3_GetHandle(material, device, &mat_handle);
+    ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
+
+    hr = IDirect3DViewport3_SetBackground(viewport, mat_handle);
+    ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
+    hr = IDirect3DViewport3_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport3_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    hr = IDirect3DViewport3_SetBackground(viewport, 0);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+    hr = IDirect3DViewport3_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(tmp == mat_handle, "Got unexpected material handle %#x, expected %#x.\n", tmp, mat_handle);
+    ok(valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport3_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    destroy_viewport(device, viewport);
+    viewport = create_viewport(device, 0, 0, 640, 480);
+
+    hr = IDirect3DViewport3_GetBackground(viewport, &tmp, &valid);
+    ok(SUCCEEDED(hr), "Failed to get viewport background, hr %#x.\n", hr);
+    ok(!tmp, "Got unexpected material handle %#x.\n", tmp);
+    ok(!valid, "Got unexpected valid %#x.\n", valid);
+    hr = IDirect3DViewport3_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+    ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
+    color = get_surface_color(rt, 320, 240);
+    ok(compare_color(color, 0x00000000, 1), "Got unexpected color 0x%08x.\n", color);
+
+    destroy_viewport(device, viewport);
+    destroy_material(material);
+    IDirectDrawSurface4_Release(rt);
+    refcount = IDirect3DDevice3_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw4)
 {
     IDirectDraw4 *ddraw;
@@ -6834,4 +7023,5 @@ START_TEST(ddraw4)
     test_mipmap_lock();
     test_palette_complex();
     test_p8_rgb_blit();
+    test_material();
 }
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 375403c..cc383c2 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -6660,6 +6660,49 @@ static void test_p8_rgb_blit(void)
     DestroyWindow(window);
 }
 
+static void test_material(void)
+{
+    static const D3DCOLORVALUE null_color;
+    IDirect3DDevice7 *device;
+    D3DMATERIAL7 material;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice7_GetMaterial(device, &material);
+    ok(SUCCEEDED(hr), "Failed to get material, hr %#x.\n", hr);
+    ok(!memcmp(&U(material).diffuse, &null_color, sizeof(null_color)),
+            "Got unexpected diffuse color {%.8e, %.8e, %.8e, %.8e}.\n",
+            U1(U(material).diffuse).r, U2(U(material).diffuse).g,
+            U3(U(material).diffuse).b, U3(U(material).diffuse).a);
+    ok(!memcmp(&U1(material).ambient, &null_color, sizeof(null_color)),
+            "Got unexpected ambient color {%.8e, %.8e, %.8e, %.8e}.\n",
+            U1(U1(material).ambient).r, U2(U1(material).ambient).g,
+            U3(U1(material).ambient).b, U3(U1(material).ambient).a);
+    ok(!memcmp(&U2(material).specular, &null_color, sizeof(null_color)),
+            "Got unexpected specular color {%.8e, %.8e, %.8e, %.8e}.\n",
+            U1(U2(material).specular).r, U2(U2(material).specular).g,
+            U3(U2(material).specular).b, U3(U2(material).specular).a);
+    ok(!memcmp(&U3(material).emissive, &null_color, sizeof(null_color)),
+            "Got unexpected emissive color {%.8e, %.8e, %.8e, %.8e}.\n",
+            U1(U3(material).emissive).r, U2(U3(material).emissive).g,
+            U3(U3(material).emissive).b, U3(U3(material).emissive).a);
+    ok(U4(material).power == 0.0f, "Got unexpected power %.8e.\n", U4(material).power);
+
+    refcount = IDirect3DDevice7_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw7)
 {
     HMODULE module = GetModuleHandleA("ddraw.dll");
@@ -6726,4 +6769,5 @@ START_TEST(ddraw7)
     test_mipmap_lock();
     test_palette_complex();
     test_p8_rgb_blit();
+    test_material();
 }
-- 
1.7.10.4




More information about the wine-patches mailing list