diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index 8e543ab58c7..85233f09fe2 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -16,8 +16,10 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COBJMACROS +#include + +#define COBJMACROS #include "wine/test.h" #include "d3d.h" @@ -342,6 +344,22 @@ static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, flo return create_material(device, &mat); } +static IDirect3DMaterial2 *create_specular_material(IDirect3DDevice2 *device, + float r, float g, float b, float a, float power) +{ + D3DMATERIAL mat; + + memset(&mat, 0, sizeof(mat)); + mat.dwSize = sizeof(mat); + U1(U2(mat).specular).r = r; + U2(U2(mat).specular).g = g; + U3(U2(mat).specular).b = b; + U4(U2(mat).specular).a = a; + U4(mat).power = power; + + return create_material(device, &mat); +} + static IDirect3DMaterial2 *create_emissive_material(IDirect3DDevice2 *device, float r, float g, float b, float a) { D3DMATERIAL mat; @@ -6656,6 +6674,269 @@ static void test_lighting(void) DestroyWindow(window); } +static void test_specular_lighting(void) +{ + static const unsigned int vertices_side = 5; + const unsigned int indices_count = (vertices_side - 1) * (vertices_side - 1) * 2 * 3; + static D3DRECT clear_rect = {{0}, {0}, {640}, {480}}; + static D3DMATRIX mat = + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + static D3DLIGHT2 directional = + { + sizeof(D3DLIGHT2), + D3DLIGHT_DIRECTIONAL, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {1.0f}}, + }, + point = + { + sizeof(D3DLIGHT2), + D3DLIGHT_POINT, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + 100.0f, + 0.0f, + 0.0f, 0.0f, 1.0f, + }, + spot = + { + sizeof(D3DLIGHT2), + D3DLIGHT_SPOT, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {1.0f}}, + 100.0f, + 1.0f, + 0.0f, 0.0f, 1.0f, + M_PI / 12.0f, M_PI / 3.0f + }, + parallelpoint = + { + sizeof(D3DLIGHT2), + D3DLIGHT_PARALLELPOINT, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.5f}, {0.0f}, {-1.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + }; + static const struct expected_color + { + unsigned int x, y; + D3DCOLOR color; + } + expected_directional_local[] = + { + {160, 120, 0x003c3c3c}, + {320, 120, 0x00717171}, + {480, 120, 0x003c3c3c}, + {160, 240, 0x00717171}, + {320, 240, 0x00ffffff}, + {480, 240, 0x00717171}, + {160, 360, 0x003c3c3c}, + {320, 360, 0x00717171}, + {480, 360, 0x003c3c3c}, + }, + expected_point_local[] = + { + {160, 120, 0x00000000}, + {320, 120, 0x00090909}, + {480, 120, 0x00000000}, + {160, 240, 0x00090909}, + {320, 240, 0x00fafafa}, + {480, 240, 0x00090909}, + {160, 360, 0x00000000}, + {320, 360, 0x00090909}, + {480, 360, 0x00000000}, + }, + expected_spot_local[] = + { + {160, 120, 0x00000000}, + {320, 120, 0x00020202}, + {480, 120, 0x00000000}, + {160, 240, 0x00020202}, + {320, 240, 0x00fafafa}, + {480, 240, 0x00020202}, + {160, 360, 0x00000000}, + {320, 360, 0x00020202}, + {480, 360, 0x00000000}, + }, + expected_parallelpoint[] = + { + {160, 120, 0x00050505}, + {320, 120, 0x002c2c2c}, + {480, 120, 0x006e6e6e}, + {160, 240, 0x00090909}, + {320, 240, 0x00717171}, + {480, 240, 0x00ffffff}, + {160, 360, 0x00050505}, + {320, 360, 0x002c2c2c}, + {480, 360, 0x006e6e6e}, + }; + static const struct + { + D3DLIGHT2 *light; + const struct expected_color *expected; + unsigned int expected_count; + } + tests[] = + { + {&directional, expected_directional_local, + sizeof(expected_directional_local) / sizeof(expected_directional_local[0])}, + {&point, expected_point_local, + sizeof(expected_point_local) / sizeof(expected_point_local[0])}, + {&spot, expected_spot_local, + sizeof(expected_spot_local) / sizeof(expected_spot_local[0])}, + {¶llelpoint, expected_parallelpoint, + sizeof(expected_parallelpoint) / sizeof(expected_parallelpoint[0])}, + }; + IDirect3D2 *d3d; + IDirect3DDevice2 *device; + IDirectDraw2 *ddraw; + IDirectDrawSurface *rt; + IDirect3DViewport2 *viewport; + IDirect3DMaterial2 *material, *background_material; + IDirect3DLight *light; + D3DMATERIALHANDLE mat_handle; + D3DCOLOR color; + ULONG refcount; + HWND window; + HRESULT hr; + unsigned int i, j, x, y; + D3DVERTEX *quad; + WORD *indices; + + quad = HeapAlloc(GetProcessHeap(), 0, vertices_side * vertices_side * sizeof(*quad)); + indices = HeapAlloc(GetProcessHeap(), 0, indices_count * sizeof(*indices)); + for (i = 0, y = 0; y < vertices_side; ++y) + { + for (x = 0; x < vertices_side; ++x) + { + U1(quad[i]).x = x * 2.0f / (vertices_side - 1) - 1.0f; + U2(quad[i]).y = y * 2.0f / (vertices_side - 1) - 1.0f; + U3(quad[i]).z = 1.0f; + U4(quad[i]).nx = 0.0f; + U5(quad[i]).ny = 0.0f; + U6(quad[i]).nz = -1.0f; + U7(quad[i]).tu = 0.0f; + U8(quad[i++]).tv = 0.0f; + } + } + for (i = 0, y = 0; y < (vertices_side - 1); ++y) + { + for (x = 0; x < (vertices_side - 1); ++x) + { + indices[i++] = y * vertices_side + x + 1; + indices[i++] = y * vertices_side + x; + indices[i++] = (y + 1) * vertices_side + x; + indices[i++] = y * vertices_side + x + 1; + indices[i++] = (y + 1) * vertices_side + x; + indices[i++] = (y + 1) * vertices_side + x + 1; + } + } + + 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_GetDirect3D(device, &d3d); + ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#x.\n", hr); + + hr = IDirect3DDevice2_GetRenderTarget(device, &rt); + ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr); + + viewport = create_viewport(device, 0, 0, 640, 480); + hr = IDirect3DDevice2_SetCurrentViewport(device, viewport); + ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr); + + hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &mat); + ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &mat); + ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &mat); + ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_CLIPPING, FALSE); + ok(SUCCEEDED(hr), "Failed to disable clipping, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, FALSE); + ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_FOGENABLE, FALSE); + ok(SUCCEEDED(hr), "Failed to disable fog, hr %#x.\n", hr); + + background_material = create_diffuse_material(device, 1.0f, 1.0f, 1.0f, 1.0f); + viewport_set_background(device, viewport, background_material); + + material = create_specular_material(device, 1.0f, 1.0f, 1.0f, 1.0f, 30.0f); + hr = IDirect3DMaterial2_GetHandle(material, device, &mat_handle); + ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr); + hr = IDirect3DDevice2_SetLightState(device, D3DLIGHTSTATE_MATERIAL, mat_handle); + ok(SUCCEEDED(hr), "Failed to set material state, hr %#x.\n", hr); + + hr = IDirect3D2_CreateLight(d3d, &light, NULL); + ok(SUCCEEDED(hr), "Failed to create a light object, hr %#x.\n", hr); + hr = IDirect3DViewport2_AddLight(viewport, light); + ok(SUCCEEDED(hr), "Failed to add a light to the viewport, hr %#x.\n", hr); + + hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SPECULARENABLE, TRUE); + ok(SUCCEEDED(hr), "Failed to enable specular lighting, hr %#x.\n", hr); + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) + { + tests[i].light->dwFlags = D3DLIGHT_ACTIVE; + hr = IDirect3DLight_SetLight(light, (D3DLIGHT *)tests[i].light); + ok(SUCCEEDED(hr), "Failed to set light, hr %#x.\n", hr); + + hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET); + ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr); + + hr = IDirect3DDevice2_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + + hr = IDirect3DDevice2_DrawIndexedPrimitive(device, D3DPT_TRIANGLELIST, D3DVT_VERTEX, + quad, vertices_side * vertices_side, indices, indices_count, 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); + + for (j = 0; j < tests[i].expected_count; ++j) + { + color = get_surface_color(rt, tests[i].expected[j].x, tests[i].expected[j].y); + ok(compare_color(color, tests[i].expected[j].color, 1), + "Expected color 0x%08x at location (%u, %u), got 0x%08x, case %u.\n", + tests[i].expected[j].color, tests[i].expected[j].x, + tests[i].expected[j].y, color, i); + } + } + + hr = IDirect3DViewport2_DeleteLight(viewport, light); + ok(SUCCEEDED(hr), "Failed to remove a light from the viewport, hr %#x.\n", hr); + IDirect3DLight_Release(light); + destroy_material(material); + destroy_material(background_material); + destroy_viewport(device, viewport); + IDirectDrawSurface2_Release(rt); + refcount = IDirect3DDevice2_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + IDirect3D2_Release(d3d); + refcount = IDirectDraw2_Release(ddraw); + ok(!refcount, "Ddraw object has %u references left.\n", refcount); + DestroyWindow(window); + HeapFree(GetProcessHeap(), 0, indices); + HeapFree(GetProcessHeap(), 0, quad); +} + static void test_palette_gdi(void) { IDirectDrawSurface *surface, *primary; @@ -8221,6 +8502,7 @@ START_TEST(ddraw2) test_p8_rgb_blit(); test_material(); test_lighting(); + test_specular_lighting(); test_palette_gdi(); test_palette_alpha(); test_lost_device();