commit 3d75939fef5f032cc68527960b561e61fd13a14f Author: Matteo Bruni Date: Mon Apr 20 15:33:48 2015 +0200 ddraw/tests: Add a ddraw1 specular lighting test. diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 7dda6eba201..b98ea7f9ae0 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -17,6 +17,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + +#include + #define COBJMACROS #include "wine/test.h" @@ -415,6 +418,28 @@ static void emit_tquad_tlist(void **ptr, WORD base_idx) *ptr = tri; } +static void emit_tlist(void **ptr, WORD *indices, unsigned int count) +{ + D3DINSTRUCTION *inst = *ptr; + D3DTRIANGLE *tri = (D3DTRIANGLE *)(inst + 1); + unsigned int i; + + inst->bOpcode = D3DOP_TRIANGLE; + inst->bSize = sizeof(*tri); + inst->wCount = count / 3; + + for (i = 0; i < count / 3; ++i) + { + U1(*tri).v1 = indices[i * 3]; + U2(*tri).v2 = indices[i * 3 + 1]; + U3(*tri).v3 = indices[i * 3 + 2]; + tri->wFlags = D3DTRIFLAG_START; + ++tri; + } + + *ptr = tri; +} + static void emit_texture_load(void **ptr, D3DTEXTUREHANDLE dst_texture, D3DTEXTUREHANDLE src_texture) { @@ -665,6 +690,22 @@ static IDirect3DMaterial *create_diffuse_and_ambient_material(IDirect3DDevice *d return create_material(device, &mat); } +static IDirect3DMaterial *create_specular_material(IDirect3DDevice *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 IDirect3DMaterial *create_emissive_material(IDirect3DDevice *device, float r, float g, float b, float a) { D3DMATERIAL mat; @@ -6294,6 +6335,306 @@ 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; + const unsigned int vertices_data_size = vertices_side * vertices_side * sizeof(D3DVERTEX); + static D3DRECT clear_rect = {{0}, {0}, {640}, {480}}; + static D3DLIGHT directional = + { + sizeof(D3DLIGHT), + D3DLIGHT_DIRECTIONAL, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {1.0f}}, + }, + /* For some reason point and spot lights don't do anything when they have + * position.z >= 0.0f (that's limited to specular, diffuse works just fine). + * My current hypothesis is that, for specular only, the light direction is + * computed as (0 - light position), which is then normalized and used with + * the vertex position to compute the (local viewer) halfvector. This + * doesn't exactly match the test results though. + * + * Actually in the D3D5 and D3D6 docs there is this sentence "Specular + * highlights are calculated as though every vertex in the object being lit + * were at the object's origin. This gives the expected results as long as + * the object is modeled around the origin and the distance from the light + * to the object is relatively large." We know this is false for D3D6 but + * check if this actually matches D3D3 and below... + * + * In other news, attenuation in D3D3 and below works like D3D7+ (higher + * attenuation coefficients = dimmer lights) and unlike D3D5 and 6. There + * might be more weirdness though. */ + point = + { + sizeof(D3DLIGHT), + D3DLIGHT_POINT, + {{1.0f}, {1.0f}, {1.0f}, {1.0f}}, + {{0.1f}, {0.0f}, {-0.1f}}, + {{0.0f}, {0.0f}, {0.0f}}, + 1e10f, + 0.0f, + 0.0f, 0.0f, 0.0f, + }, + spot = + { + sizeof(D3DLIGHT), + D3DLIGHT_SPOT, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {-0.1f}}, + {{0.0f}, {0.0f}, {1.0f}}, + 1000.0f, + 1.0f, + 0.0f, 0.0f, 1.0f, + M_PI / 12.0f, M_PI / 3.0f + }, + parallelpoint = + { + sizeof(D3DLIGHT), + 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[] = + { + {160, 120, 0x00ffffff}, + {320, 120, 0x00ffffff}, + {480, 120, 0x00ffffff}, + {160, 240, 0x00ffffff}, + {320, 240, 0x00ffffff}, + {480, 240, 0x00ffffff}, + {160, 360, 0x00ffffff}, + {320, 360, 0x00ffffff}, + {480, 360, 0x00ffffff}, + }, + expected_point[] = + { + {160, 120, 0x00868686}, + {320, 120, 0x00959595}, + {480, 120, 0x008e8e8e}, + {160, 240, 0x00909090}, + {320, 240, 0x00a3a3a3}, + {480, 240, 0x009a9a9a}, + {160, 360, 0x00868686}, + {320, 360, 0x00959595}, + {480, 360, 0x008e8e8e}, + }, + expected_spot[] = + { + {160, 120, 0x00000000}, + {320, 120, 0x00333333}, + {480, 120, 0x00000000}, + {160, 240, 0x00333333}, + {320, 240, 0x00c0c0c0}, + {480, 240, 0x00333333}, + {160, 360, 0x00000000}, + {320, 360, 0x00333333}, + {480, 360, 0x00000000}, + }, + expected_parallelpoint[] = + { + {160, 120, 0x00e4e4e4}, + {320, 120, 0x00e4e4e4}, + {480, 120, 0x00e4e4e4}, + {160, 240, 0x00e4e4e4}, + {320, 240, 0x00e4e4e4}, + {480, 240, 0x00e4e4e4}, + {160, 360, 0x00e4e4e4}, + {320, 360, 0x00e4e4e4}, + {480, 360, 0x00e4e4e4}, + }; + static const struct + { + D3DLIGHT *light; + const struct expected_color *expected; + unsigned int expected_count; + BOOL todo; + } + tests[] = + { + {&directional, expected_directional, + sizeof(expected_directional) / sizeof(expected_directional[0]), FALSE}, + {&point, expected_point, + sizeof(expected_point) / sizeof(expected_point[0]), TRUE}, + {&spot, expected_spot, + sizeof(expected_spot) / sizeof(expected_spot[0]), TRUE}, + {¶llelpoint, expected_parallelpoint, + sizeof(expected_parallelpoint) / sizeof(expected_parallelpoint[0]), TRUE}, + }; + IDirect3D *d3d; + IDirect3DDevice *device; + IDirectDraw *ddraw; + IDirectDrawSurface *rt; + IDirect3DViewport *viewport; + IDirect3DMaterial *material, *background_material; + IDirect3DLight *light; + IDirect3DExecuteBuffer *execute_buffer; + D3DEXECUTEBUFFERDESC exec_desc; + D3DMATERIALHANDLE mat_handle; + D3DCOLOR color; + D3DDEVICEDESC device_desc, hel_desc; + void *ptr; + UINT inst_length; + 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 /* | WS_VISIBLE */, + 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; + } + + device_desc.dwSize = sizeof(device_desc); + hel_desc.dwSize = sizeof(hel_desc); + hr = IDirect3DDevice_GetCaps(device, &device_desc, &hel_desc); + ok(SUCCEEDED(hr), "Failed to get device caps.\n"); + + ok(!(device_desc.dlcLightingCaps.dwCaps & D3DLIGHTCAPS_GLSPOT), "GLSPOT lights supported.\n"); + + hr = IDirect3DDevice_GetDirect3D(device, &d3d); + ok(SUCCEEDED(hr), "Failed to get D3D interface, hr %#x.\n", hr); + + hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&rt); + ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr); + + viewport = create_viewport(device, 0, 0, 640, 480); + + 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, 1.0f); + hr = IDirect3DMaterial_GetHandle(material, device, &mat_handle); + ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr); + + hr = IDirect3D_CreateLight(d3d, &light, NULL); + ok(SUCCEEDED(hr), "Failed to create a light object, hr %#x.\n", hr); + hr = IDirect3DViewport_AddLight(viewport, light); + ok(SUCCEEDED(hr), "Failed to add a light to the viewport, 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 = 2048; + 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(tests) / sizeof(tests[0]); ++i) + { + hr = IDirect3DLight_SetLight(light, tests[i].light); + ok(SUCCEEDED(hr), "Failed to set light, hr %#x.\n", hr); + + hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET); + ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr); + + hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc); + ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#x.\n", hr); + + memcpy(exec_desc.lpData, quad, vertices_data_size); + ptr = ((BYTE *)exec_desc.lpData) + vertices_data_size; + emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE); + emit_set_rs(&ptr, D3DRENDERSTATE_FOGENABLE, FALSE); + emit_set_rs(&ptr, D3DRENDERSTATE_SPECULARENABLE, TRUE); + emit_set_ls(&ptr, D3DLIGHTSTATE_MATERIAL, mat_handle); + emit_process_vertices(&ptr, D3DPROCESSVERTICES_TRANSFORMLIGHT, 0, vertices_side * vertices_side); + emit_tlist(&ptr, indices, indices_count); + emit_end(&ptr); + inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData; + inst_length -= vertices_data_size; + + hr = IDirect3DExecuteBuffer_Unlock(execute_buffer); + ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#x.\n", hr); + + hr = IDirect3DDevice_BeginScene(device); + ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr); + + set_execute_data(execute_buffer, vertices_side * vertices_side, vertices_data_size, 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); + + for (j = 0; j < tests[i].expected_count; ++j) + { + color = get_surface_color(rt, tests[i].expected[j].x, tests[i].expected[j].y); + if (tests[i].todo) + todo_wine 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); + else + 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); + } + } + + IDirect3DExecuteBuffer_Release(execute_buffer); + hr = IDirect3DViewport_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); + IDirectDrawSurface_Release(rt); + refcount = IDirect3DDevice_Release(device); + ok(!refcount, "Device has %u references left.\n", refcount); + IDirect3D_Release(d3d); + refcount = IDirectDraw_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; @@ -12552,6 +12893,7 @@ START_TEST(ddraw1) test_p8_blit(); test_material(); test_lighting(); + test_specular_lighting(); test_palette_gdi(); test_palette_alpha(); test_lost_device();