From: Octavian Voicu Subject: [10/11] ddraw/tests: Add assorted D3D3 DrawPrimitive/visual tests. Message-Id: <1320704834-17156-11-git-send-email-octavian.voicu@gmail.com> Date: Tue, 8 Nov 2011 00:27:13 +0200 Similar to the D3D2 tests, except for D3D3 specific features: - Switch to IDirectDrawSurface4, IDirect3DDevice3, IDirect3DMaterial3, IDirect3DViewport3 interfaces. - Use D3DLIGHT2 when setting light properties. - Switch to D3DFVF_ vertex types, but also test D3DVT_ ones. - Add an extra FVF vertex type with coords, normals, and colors. - Also test D3DDP_DONOTLIGHT flag (introduced in D3D3). --- dlls/ddraw/tests/visual.c | 249 ++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 248 insertions(+), 1 deletions(-) diff --git a/dlls/ddraw/tests/visual.c b/dlls/ddraw/tests/visual.c index 8c919b2..49cd23d 100644 --- a/dlls/ddraw/tests/visual.c +++ b/dlls/ddraw/tests/visual.c @@ -2724,6 +2724,253 @@ out: return ret; } +static void D3D3_DrawPrimitiveTests(void) +{ + enum { + BLACK = 0x000000, + BLUE = 0x0000ff, + GREEN = 0x00ff00, + GRAY = 0x808080, + YELLOW2 = 0x808000, + RED = 0xff0000, + YELLOW = 0xffff00, + WHITE = 0xffffff, + }; + D3DVERTEX vertices[] = { /* bottom-left corner of screen */ + /* x y z nx ny nz tu tv */ + { {-1.f}, {-1.f}, {0.f}, {0.f}, {0.f}, {1.f}, {0.f}, {0.f} }, + { { 0.f}, {-1.f}, {0.f}, {0.f}, {0.f}, {1.f}, {0.f}, {0.f} }, + { {-1.f}, { 0.f}, {0.f}, {0.f}, {0.f}, {1.f}, {0.f}, {0.f} }, + { { 0.f}, { 0.f}, {0.f}, {0.f}, {0.f}, {1.f}, {0.f}, {0.f} } + }; + DWORD fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_SPECULAR; + struct { + D3DVALUE x; + D3DVALUE y; + D3DVALUE z; + D3DVALUE nx; + D3DVALUE ny; + D3DVALUE nz; + D3DCOLOR diffuse; + D3DCOLOR specular; + } fvfvertices[] = { /* bottom-right corner of screen */ + /* x y z nx ny nz diff spec */ + { 0.f, -1.f, 0.f, 0.f, 0.f, 1.f, YELLOW, YELLOW }, + { 1.f, -1.f, 0.f, 0.f, 0.f, 1.f, YELLOW, YELLOW }, + { 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, YELLOW, YELLOW }, + { 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, YELLOW, YELLOW } + }; + D3DLVERTEX lvertices[] = { /* top-left corner of screen */ + /* x y z ? diff spec tu tv */ + { {-1.f}, { 0.f}, {0.f}, 0, {GREEN}, {GREEN}, {0.f}, {0.f} }, + { { 0.f}, { 0.f}, {0.f}, 0, {GREEN}, {GREEN}, {0.f}, {0.f} }, + { {-1.f}, { 1.f}, {0.f}, 0, {GREEN}, {GREEN}, {0.f}, {0.f} }, + { { 0.f}, { 1.f}, {0.f}, 0, {GREEN}, {GREEN}, {0.f}, {0.f} } + }; + D3DTLVERTEX tlvertices[] = { /* top-right corner of screen */ + /* sx sy sz rhw diff spec tu tv */ + { {320.f}, { 0.f}, {0.f}, {1.f}, {BLUE}, {BLUE}, {0.f}, {0.f} }, + { {640.f}, { 0.f}, {0.f}, {1.f}, {BLUE}, {BLUE}, {0.f}, {0.f} }, + { {320.f}, {240.f}, {0.f}, {1.f}, {BLUE}, {BLUE}, {0.f}, {0.f} }, + { {640.f}, {240.f}, {0.f}, {1.f}, {BLUE}, {BLUE}, {0.f}, {0.f} } + }; + /* Triangles are drawn on the screen as shown below. Number shown in each + triangle is the index for the expected[] and is_todo[] arrays bellow. + ----------- + | \ 5| \ 7| + |4 \ |6 \ | + ----------- + | \ 1| \ 3| + |0 \ |2 \ | + ----------- */ + DWORD expected[] = { GRAY, WHITE, YELLOW2, YELLOW, GREEN, GREEN, BLUE, BLUE }; + BOOL is_todo[] = { TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE }; + UINT i, x, y, xgrid[] = {1,2,4,5,1,2,4,5}, ygrid[] = {5,4,5,4,2,1,2,1}; + IDirect3DLight *Direct3DLight; + IDirect3DMaterial3 *Direct3DMaterial3; + D3DLIGHT2 light; + D3DMATERIAL mat; + D3DMATERIALHANDLE hMat; + DDBLTFX ddbltfx; + RECT rc = { 0, 0 }; + HRESULT hr; + DWORD oldcull, oldlighting, val, color; + + /* Fill entire surface with red. */ + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + U5(ddbltfx).dwFillColor = RED; + hr = IDirectDrawSurface4_Blt(Surface4, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + ok(hr == DD_OK, "Blt returned: %08x\n", hr); + + /* Make sure getPixelColor works correctly. */ + color = D3D3_getPixelColor(DirectDraw4, Surface4, 320, 240); + ok(color == RED, "getPixelColor returned: %08x\n", color); + + /* Setup a diffuse directional gray light, perpendicular on the triangles. */ + hr = IDirect3D3_CreateLight(Direct3D3, &Direct3DLight, NULL); + ok(hr == D3D_OK, "CreateLight returned: %08x\n", hr); + memset(&light, 0, sizeof(light)); + light.dwSize = sizeof(light); + light.dltType = D3DLIGHT_DIRECTIONAL; + light.dcvColor.r = .5f; + light.dcvColor.g = .5f; + light.dcvColor.b = .5f; + light.dcvColor.a = 1.f; + light.dvDirection.x = 0.f; + light.dvDirection.y = 0.f; + light.dvDirection.z = -1.f; + light.dwFlags = D3DLIGHT_ACTIVE; + hr = IDirect3DLight_SetLight(Direct3DLight, (D3DLIGHT *)&light); + ok(hr == D3D_OK, "SetLight returned: %08x\n", hr); + hr = IDirect3DViewport3_AddLight(Viewport3, Direct3DLight); + ok(hr == D3D_OK, "AddLight returned: %08x\n", hr); + + /* Use a material that reflects only diffuse light. */ + hr = IDirect3D3_CreateMaterial(Direct3D3, &Direct3DMaterial3, NULL); + ok(hr == D3D_OK, "CreateMaterial returned: %08x\n", hr); + memset(&mat, 0, sizeof(mat)); + mat.dwSize = sizeof(mat); + mat.dcvDiffuse.r = 1.f; + mat.dcvDiffuse.g = 1.f; + mat.dcvDiffuse.b = 1.f; + mat.dcvDiffuse.a = 1.f; + hr = IDirect3DMaterial3_SetMaterial(Direct3DMaterial3, &mat); + ok(hr == D3D_OK, "SetMaterial returned: %08x\n", hr); + hr = IDirect3DMaterial3_GetHandle(Direct3DMaterial3, Direct3DDevice3, &hMat); + ok(hr == D3D_OK, "GetHandle returned: %08x\n", hr); + hr = IDirect3DDevice3_SetLightState(Direct3DDevice3, D3DLIGHTSTATE_MATERIAL, hMat); + ok(hr == D3D_OK, "SetLightState returned: %08x\n", hr); + hr = IDirect3DDevice3_SetLightState(Direct3DDevice3, D3DLIGHTSTATE_COLORVERTEX, TRUE); + ok(hr == D3D_OK, "SetLightState returned: %08x\n", hr); + + hr = IDirect3DDevice3_BeginScene(Direct3DDevice3); + ok(hr == D3D_OK, "BeginScene returned: %08x\n", hr); + + if (SUCCEEDED(hr)) { + /* Don't cull back faces to reduce number of vertices we need to declare. */ + hr = IDirect3DDevice3_GetRenderState(Direct3DDevice3, D3DRENDERSTATE_CULLMODE, &oldcull); + ok(hr == D3D_OK, "GetRenderState returned: %08x\n", hr); + hr = IDirect3DDevice3_SetRenderState(Direct3DDevice3, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); + ok(hr == D3D_OK, "SetRenderState returned: %08x\n", hr); + + /* IDirect3DDevice3 doesn't have D3DRENDERSTATE_LIGHTING, but get/set seem to work w/o any side effects. */ + hr = IDirect3DDevice3_GetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, &oldlighting); + ok(hr == D3D_OK, "GetRenderState returned: %08x\n", hr); + todo_wine ok(oldlighting == 0xffffffff, "D3DRENDERSTATE_LIGHTING is: %08x\n", oldlighting); + + /* Try to disable lighting -- shouldn't have any effect. */ + hr = IDirect3DDevice3_SetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, FALSE); + ok(hr == D3D_OK, "SetRenderState returned: %08x\n", hr); + hr = IDirect3DDevice3_GetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, &val); + ok(hr == D3D_OK, "GetRenderState returned: %08x\n", hr); + ok(val == FALSE, "D3DRENDERSTATE_LIGHTING is: %08x\n", val); + + /* Note: IDirect3DDevice3::DrawPrimitive calls with D3DVT_ vertex types should fail. */ + + /* Triangle 0 -- D3DFVF_VERTEX (vertices with normals, but without colors). */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DVT_VERTEX, + vertices, 3, D3DDP_WAIT); + ok(hr != DDERR_INVALIDPARAMS, "DrawPrimitive returned: %08x\n", hr); + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_VERTEX, + vertices, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 2 -- custom fvf (vertices with normals and colors). */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, fvf, + fvfvertices, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 4 -- D3DFVF_LVERTEX. */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DVT_LVERTEX, + lvertices, 3, D3DDP_WAIT); + ok(hr != DDERR_INVALIDPARAMS, "DrawPrimitive returned: %08x\n", hr); + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, + lvertices, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 6 -- D3DFVF_TLVERTEX. */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DVT_TLVERTEX, + tlvertices, 3, D3DDP_WAIT); + ok(hr != DDERR_INVALIDPARAMS, "DrawPrimitive returned: %08x\n", hr); + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, + tlvertices, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Try to enable lighting -- shouldn't have any effect. */ + hr = IDirect3DDevice3_SetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, TRUE); + ok(hr == D3D_OK, "SetRenderState returned: %08x\n", hr); + hr = IDirect3DDevice3_GetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, &val); + ok(hr == D3D_OK, "GetRenderState returned: %08x\n", hr); + ok(val == TRUE, "D3DRENDERSTATE_LIGHTING is: %08x\n", val); + + /* Triangle 1 -- D3DFVF_VERTEX with D3DDP_DONOTLIGHT. + From DirectX SDK docs: if flag D3DDP_DONOTLIGHT is set and a diffuse or specular + component is not specified, the system uses the default color for the missing + component (0xFFFFFFFF for diffuse and 0x00000000 for specular). */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_VERTEX, + vertices + 1, 3, D3DDP_DONOTLIGHT | D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 3 -- custom fvf (vertices with normals and colors) with D3DDP_DONOTLIGHT. */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, fvf, + fvfvertices + 1, 3, D3DDP_DONOTLIGHT | D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 5 -- D3DFVF_LVERTEX. */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_LVERTEX, + lvertices + 1, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Triangle 7 -- D3DFVF_TLVERTEX. */ + hr = IDirect3DDevice3_DrawPrimitive(Direct3DDevice3, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, + tlvertices + 1, 3, D3DDP_WAIT); + ok(hr == D3D_OK, "DrawPrimitive returned: %08x\n", hr); + + /* Restore state. */ + hr = IDirect3DDevice3_SetRenderState(Direct3DDevice3, D3DRENDERSTATE_CULLMODE, oldcull); + ok(hr == D3D_OK, "SetRenderState returned: %08x\n", hr); + hr = IDirect3DDevice3_SetRenderState(Direct3DDevice3, D3DRENDERSTATE_LIGHTING, oldlighting); + ok(hr == D3D_OK, "SetRenderState returned: %08x\n", hr); + + hr = IDirect3DDevice3_EndScene(Direct3DDevice3); + ok(hr == D3D_OK, "EndScene returned: %08x\n", hr); + } + + /* Blit to window (for debugging, tests read directly from surface). */ + MapWindowPoints(window, NULL, (POINT *)&rc, 1); + rc.right = rc.left + 640; + rc.bottom = rc.top + 480; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + hr = IDirectDrawSurface4_Blt(Primary4, &rc, Surface4, NULL, DDBLT_WAIT, &ddbltfx); + ok(hr == DD_OK, "Blt returned: %08x\n", hr); + + for (i = 0; i < 8; i++) { + /* Split screen using 5x5 grid points and use those points to sample the triangles. */ + x = xgrid[i] * 640 / 6; + y = ygrid[i] * 480 / 6; + color = D3D3_getPixelColor(DirectDraw4, Surface4, x, y); + if (is_todo[i]) + todo_wine + ok(color_match(color, expected[i], 1), "%d: getPixelColor(%d,%d) returned %08x, expected %08x.\n", + i, x, y, color, expected[i]); + else + ok(color_match(color, expected[i], 1), "%d: getPixelColor(%d,%d) returned %08x, expected %08x.\n", + i, x, y, color, expected[i]); + } + + /* Cleanup lights and material. */ + hr = IDirect3DViewport3_DeleteLight(Viewport3, Direct3DLight); + ok(hr == D3D_OK, "DeleteLight returned: %08x\n", hr); + IDirect3DLight_Release(Direct3DLight); + hr = IDirect3DDevice3_SetLightState(Direct3DDevice3, D3DLIGHTSTATE_MATERIAL, 0); + todo_wine + ok(hr == D3D_OK, "SetLightState returned: %08x\n", hr); + IDirect3DMaterial3_Release(Direct3DMaterial3); +} + static void D3D3_ViewportClearTest(void) { HRESULT hr; @@ -3808,7 +4055,7 @@ cleanup: skip("Cannot initialize D3D3, skipping\n"); } else { - /* todo */ + D3D3_DrawPrimitiveTests(); } D3D3_releaseObjects(); -- 1.7.4.1