d3d9/tests: Warn that tests were skipped if we could not load d3d9.dll.
[wine] / dlls / d3d9 / tests / vertexdeclaration.c
1 /*
2  * Copyright (C) 2005 Henri Verbeet
3  * Copyright (C) 2006 Ivan Gyurdiev
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #define COBJMACROS
21 #include <d3d9.h>
22 #include "wine/test.h"
23
24 static HMODULE d3d9_handle = 0;
25
26 #define VDECL_CHECK(fcall) \
27     if(fcall != S_OK) \
28         trace(" Test failed on line #%d\n", __LINE__);
29
30 static HWND create_window(void)
31 {
32     WNDCLASS wc = {0};
33     wc.lpfnWndProc = &DefWindowProc;
34     wc.lpszClassName = "d3d9_test_wc";
35     RegisterClass(&wc);
36
37     return CreateWindow("d3d9_test_wc", "d3d9_test",
38             0, 0, 0, 0, 0, 0, 0, 0, 0);
39 }
40
41 static IDirect3DDevice9 *init_d3d9(void)
42 {
43     IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion) = 0;
44     IDirect3D9 *d3d9_ptr = 0;
45     IDirect3DDevice9 *device_ptr = 0;
46     D3DPRESENT_PARAMETERS present_parameters;
47     HRESULT hres;
48
49     d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
50     ok(d3d9_create != NULL, "Failed to get address of Direct3DCreate9\n");
51     if (!d3d9_create) return NULL;
52     
53     d3d9_ptr = d3d9_create(D3D_SDK_VERSION);
54     ok(d3d9_ptr != NULL, "Failed to create IDirect3D9 object\n");
55     if (!d3d9_ptr) return NULL;
56
57     ZeroMemory(&present_parameters, sizeof(present_parameters));
58     present_parameters.Windowed = TRUE;
59     present_parameters.hDeviceWindow = create_window();
60     present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
61
62     hres = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
63
64     if(FAILED(hres))
65     {
66         trace("could not create device, IDirect3D9_CreateDevice returned %#x\n", hres);
67         return NULL;
68     }
69
70     return device_ptr;
71 }
72
73 static int get_refcount(IUnknown *object)
74 {
75     IUnknown_AddRef(object);
76     return IUnknown_Release(object);
77 }
78
79 static IDirect3DVertexDeclaration9 *test_create_vertex_declaration(IDirect3DDevice9 *device_ptr, D3DVERTEXELEMENT9 *vertex_decl)
80 {
81     IDirect3DVertexDeclaration9 *decl_ptr = 0;
82     HRESULT hret = 0;
83
84     hret = IDirect3DDevice9_CreateVertexDeclaration(device_ptr, vertex_decl, &decl_ptr);
85     ok(hret == D3D_OK && decl_ptr != NULL, "CreateVertexDeclaration returned: hret 0x%x, decl_ptr %p. "
86         "Expected hret 0x%x, decl_ptr != %p. Aborting.\n", hret, decl_ptr, D3D_OK, NULL);
87
88     return decl_ptr;
89 }
90
91 static void test_get_set_vertex_declaration(IDirect3DDevice9 *device_ptr, IDirect3DVertexDeclaration9 *decl_ptr)
92 {
93     IDirect3DVertexDeclaration9 *current_decl_ptr = 0;
94     HRESULT hret = 0;
95     int decl_refcount = 0;
96     int i = 0;
97     
98     /* SetVertexDeclaration should not touch the declaration's refcount. */
99     i = get_refcount((IUnknown *)decl_ptr);
100     hret = IDirect3DDevice9_SetVertexDeclaration(device_ptr, decl_ptr);
101     decl_refcount = get_refcount((IUnknown *)decl_ptr);
102     ok(hret == D3D_OK && decl_refcount == i, "SetVertexDeclaration returned: hret 0x%x, refcount %d. "
103         "Expected hret 0x%x, refcount %d.\n", hret, decl_refcount, D3D_OK, i);
104     
105     /* GetVertexDeclaration should increase the declaration's refcount by one. */
106     i = decl_refcount+1;
107     hret = IDirect3DDevice9_GetVertexDeclaration(device_ptr, &current_decl_ptr);
108     decl_refcount = get_refcount((IUnknown *)decl_ptr);
109     ok(hret == D3D_OK && decl_refcount == i && current_decl_ptr == decl_ptr, 
110         "GetVertexDeclaration returned: hret 0x%x, current_decl_ptr %p refcount %d. "
111         "Expected hret 0x%x, current_decl_ptr %p, refcount %d.\n", hret, current_decl_ptr, decl_refcount, D3D_OK, decl_ptr, i);
112 }
113
114 static void test_get_declaration(IDirect3DVertexDeclaration9 *decl_ptr, D3DVERTEXELEMENT9 *vertex_decl, UINT expected_num_elements)
115 {
116     int i;
117     UINT num_elements = 0;
118     D3DVERTEXELEMENT9 *decl = 0;
119     HRESULT hret = 0;
120
121     /* First test only getting the number of elements */
122     num_elements = 0x1337c0de;
123     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
124     ok(hret == D3D_OK && num_elements == expected_num_elements,
125             "GetDeclaration returned: hret 0x%x, num_elements %d. "
126             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
127
128     num_elements = 0;
129     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, NULL, &num_elements);
130     ok(hret == D3D_OK && num_elements == expected_num_elements,
131             "GetDeclaration returned: hret 0x%x, num_elements %d. "
132             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
133
134     /* Also test the returned data */
135     decl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);
136
137     num_elements = 0x1337c0de;
138     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
139     ok(hret == D3D_OK && num_elements == expected_num_elements,
140             "GetDeclaration returned: hret 0x%x, num_elements %d. "
141             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
142     i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
143     ok (!i, "Original and returned vertexdeclarations are not the same\n");
144     ZeroMemory(decl, sizeof(D3DVERTEXELEMENT9) * expected_num_elements);
145
146     num_elements = 0;
147     hret = IDirect3DVertexDeclaration9_GetDeclaration(decl_ptr, decl, &num_elements);
148     ok(hret == D3D_OK && num_elements == expected_num_elements,
149             "GetDeclaration returned: hret 0x%x, num_elements %d. "
150             "Expected hret 0x%x, num_elements %d.\n", hret, num_elements, D3D_OK, expected_num_elements);
151     i = memcmp(decl, vertex_decl, sizeof(vertex_decl));
152     ok (!i, "Original and returned vertexdeclarations are not the same\n");
153
154     HeapFree(GetProcessHeap(), 0, decl);
155 }
156
157 /* FIXME: also write a test, which shows that attempting to set
158  * an invalid vertex declaration returns E_FAIL */
159
160 static HRESULT test_fvf_to_decl(
161     IDirect3DDevice9* device,
162     IDirect3DVertexDeclaration9* default_decl,
163     DWORD test_fvf,
164     CONST D3DVERTEXELEMENT9 expected_elements[],
165     D3DVERTEXELEMENT9* result_elements_ptr,
166     UINT expected_size,
167     char object_should_change) 
168 {
169
170     HRESULT hr;
171     IDirect3DVertexDeclaration9 *result_decl = NULL;
172     UINT result_size = 12345;
173
174     /* Set a default declaration to make sure it is changed */
175     hr = IDirect3DDevice9_SetVertexDeclaration ( device, default_decl );
176     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
177     if (FAILED(hr)) goto fail;
178
179     /* Set an FVF */
180     hr = IDirect3DDevice9_SetFVF( device, test_fvf);
181     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
182     if (FAILED(hr)) goto fail;
183
184     /* Check if the declaration object changed underneath */
185     hr = IDirect3DDevice9_GetVertexDeclaration ( device, &result_decl);
186     ok(SUCCEEDED(hr), "GetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
187     if (FAILED(hr)) goto fail;
188     if (object_should_change) {
189        ok(result_decl != default_decl, "result declaration matches original\n");
190        if (result_decl == default_decl) goto fail;
191     } else {
192        ok(result_decl == default_decl, "result declaration does not match original\n");
193        if (result_decl != default_decl) goto fail;
194     }
195
196     /* Declaration content/size test */
197     ok(result_decl != NULL, "result declaration was null\n");
198     if (result_decl == NULL) 
199         goto fail;
200     else { 
201
202         int status;
203
204         /* Check if the size changed, and abort if it did */
205         hr = IDirect3DVertexDeclaration9_GetDeclaration( result_decl, NULL, &result_size );
206         ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
207         if (FAILED(hr)) goto fail;
208         ok(result_size == expected_size, "result declaration size: %d, "
209             "expected: %d\n", result_size, expected_size);
210         if (result_size != expected_size) goto fail;
211
212         /* Check the actual elements. Write it them in a caller-allocated array of the correct size
213          * That's fine, since we aborted above if the size didn't match the caller's expectations */
214         hr = IDirect3DVertexDeclaration9_GetDeclaration( result_decl, result_elements_ptr, &result_size );
215         ok(SUCCEEDED(hr), "GetDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
216         if (FAILED(hr)) goto fail;
217
218         ok(result_size == expected_size, "result declaration size: %d, "
219             "expected: %d\n", result_size, expected_size);
220         if (result_size != expected_size) goto fail;
221         
222         status = memcmp(expected_elements, result_elements_ptr, expected_size * sizeof(D3DVERTEXELEMENT9));  
223         ok(!status, "result declaration differs from expected\n");
224         if (status) {
225             unsigned int i;
226
227             for (i = 0; i < expected_size; i++) { 
228
229                  trace(
230                      "Stream = %d, Offset = %d, Type = %d, "
231                      "Method = %d, Usage = %d, UsageIndex = %d\n", 
232                      result_elements_ptr[i].Stream,
233                      result_elements_ptr[i].Offset,
234                      result_elements_ptr[i].Type,
235                      result_elements_ptr[i].Method,
236                      result_elements_ptr[i].Usage,
237                      result_elements_ptr[i].UsageIndex);
238             }
239             goto fail;
240         }
241     }
242
243     if (result_decl) IUnknown_Release( result_decl );
244     return S_OK;    
245
246     fail:
247     if (result_decl) IUnknown_Release( result_decl );
248     return E_FAIL;
249 }
250
251 static HRESULT test_decl_to_fvf(
252     IDirect3DDevice9* device,
253     DWORD default_fvf,
254     CONST D3DVERTEXELEMENT9 test_decl[],
255     DWORD test_fvf)
256 {
257
258     HRESULT hr;
259     IDirect3DVertexDeclaration9 *vdecl = NULL;
260
261     DWORD result_fvf = 0xdeadbeef;
262
263     /* Set a default FVF of SPECULAR and DIFFUSE to make sure it is changed back to 0 */
264     hr = IDirect3DDevice9_SetFVF( device, default_fvf);
265     ok(SUCCEEDED(hr), "SetFVF returned %#x, expected %#x\n", hr, D3D_OK);
266     if (FAILED(hr)) goto fail;
267
268     /* Create a testing declaration */
269     hr = IDirect3DDevice9_CreateVertexDeclaration( device, test_decl, &vdecl );
270     ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
271     if (FAILED(hr)) goto fail;
272
273     /* Set the declaration */
274     hr = IDirect3DDevice9_SetVertexDeclaration ( device, vdecl );
275     ok (SUCCEEDED(hr), "SetVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
276     if (FAILED(hr)) goto fail;
277
278     /* Check the FVF */
279     hr = IDirect3DDevice9_GetFVF( device, &result_fvf);
280     ok(SUCCEEDED(hr), "GetFVF returned %#x, expected %#x\n", hr, D3D_OK);
281     if (FAILED(hr)) goto fail;
282     todo_wine {
283        ok(test_fvf == result_fvf, "result FVF was: %#x, expected: %#x\n", result_fvf, test_fvf);
284     }
285     if (test_fvf != result_fvf) goto fail;
286
287     IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
288     if (vdecl) IUnknown_Release( vdecl );
289     return S_OK;
290
291     fail:
292     IDirect3DDevice9_SetVertexDeclaration ( device, NULL );
293     if (vdecl) IUnknown_Release( vdecl );
294     return E_FAIL;
295 }
296
297 static void test_fvf_decl_conversion(IDirect3DDevice9 *pDevice)
298 {
299
300     HRESULT hr;
301     D3DVERTEXELEMENT9 result_buffer[MAXD3DDECLLENGTH];
302     unsigned int i;
303
304     IDirect3DVertexDeclaration9* default_decl = NULL;
305     DWORD default_fvf = D3DFVF_SPECULAR | D3DFVF_DIFFUSE;
306     D3DVERTEXELEMENT9 default_elements[] =
307         { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
308           { 0, 4, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
309
310     /* Create a default declaration and FVF that does not match any of the tests */
311     hr = IDirect3DDevice9_CreateVertexDeclaration( pDevice, default_elements, &default_decl );
312     ok(SUCCEEDED(hr), "CreateVertexDeclaration returned %#x, expected %#x\n", hr, D3D_OK);
313     if (FAILED(hr)) goto cleanup;
314
315     /* Test conversions from vertex declaration to an FVF.
316      * For some reason those seem to occur only for POSITION/POSITIONT,
317      * Otherwise the FVF is forced to 0 - maybe this is configuration specific */
318     {
319         CONST D3DVERTEXELEMENT9 test_buffer[] =
320             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
321         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZ));
322     }
323     {
324         CONST D3DVERTEXELEMENT9 test_buffer[] =
325             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
326         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, D3DFVF_XYZRHW));
327     }
328     for (i = 0; i < 4; i++) {
329         CONST D3DVERTEXELEMENT9 test_buffer[] =
330             { { 0, 0, D3DDECLTYPE_FLOAT1+i, 0, D3DDECLUSAGE_BLENDWEIGHT, 0}, D3DDECL_END() };
331         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
332     }
333     {
334         CONST D3DVERTEXELEMENT9 test_buffer[] = 
335             { { 0, 0, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0}, D3DDECL_END() };
336         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
337     }
338     {
339         CONST D3DVERTEXELEMENT9 test_buffer[] =
340             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
341         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
342     }
343     {
344         CONST D3DVERTEXELEMENT9 test_buffer[] =
345             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
346         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
347     }
348     {
349         CONST D3DVERTEXELEMENT9 test_buffer[] =
350             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
351         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
352     }
353     {
354         CONST D3DVERTEXELEMENT9 test_buffer[] =
355             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
356         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
357     }
358
359     /* Make sure textures of different sizes work */
360     {
361         CONST D3DVERTEXELEMENT9 test_buffer[] =
362             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
363         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
364     }
365     {
366         CONST D3DVERTEXELEMENT9 test_buffer[] =
367             { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
368         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
369     }
370     {
371         CONST D3DVERTEXELEMENT9 test_buffer[] =
372             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
373         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
374     }
375     {
376         CONST D3DVERTEXELEMENT9 test_buffer[] =
377             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
378         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
379     }
380
381     /* Make sure the TEXCOORD index works correctly - try several textures */
382     {
383         CONST D3DVERTEXELEMENT9 test_buffer[] =
384             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
385               { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
386               { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
387               { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
388         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
389     }
390
391     /* No FVF mapping available */
392     {
393         CONST D3DVERTEXELEMENT9 test_buffer[] =
394             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 1 }, D3DDECL_END() };
395         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
396     }
397     {
398         CONST D3DVERTEXELEMENT9 test_buffer[] =
399             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 1 }, D3DDECL_END() };
400         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
401     }
402
403     /* Try empty declaration */
404     {
405         CONST D3DVERTEXELEMENT9 test_buffer[] = { D3DDECL_END() };
406         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
407     }
408
409     /* Now try a combination test */
410     {
411         CONST D3DVERTEXELEMENT9 test_buffer[] =
412             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITIONT, 0 },
413               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
414               { 0, 24, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 },
415               { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
416               { 0, 32, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
417               { 0, 44, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
418         VDECL_CHECK(test_decl_to_fvf(pDevice, default_fvf, test_buffer, 0));
419     }
420
421     /* Test conversions from FVF to a vertex declaration 
422      * These seem to always occur internally. A new declaration object is created if necessary */
423
424     {
425         CONST D3DVERTEXELEMENT9 test_buffer[] =
426             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 }, D3DDECL_END() };
427         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZ, test_buffer, result_buffer, 2, 1));
428     }
429     {
430         CONST D3DVERTEXELEMENT9 test_buffer[] =
431           { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITIONT, 0 }, D3DDECL_END() };
432         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZRHW, test_buffer, result_buffer, 2, 1));
433     }
434     {
435         CONST D3DVERTEXELEMENT9 test_buffer[] =
436             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
437               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
438               { 0, 28, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
439         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5 | D3DFVF_LASTBETA_UBYTE4,
440             test_buffer, result_buffer, 4, 1));
441     }
442     {
443         CONST D3DVERTEXELEMENT9 test_buffer[] =
444             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
445               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
446               { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
447         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR,
448            test_buffer, result_buffer, 4, 1));
449     }
450     {
451         CONST D3DVERTEXELEMENT9 test_buffer[] =
452             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
453               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
454               { 0, 28, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
455         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB5, test_buffer, result_buffer, 4, 1));
456     }
457     {
458         CONST D3DVERTEXELEMENT9 test_buffer[] =
459             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
460               { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
461         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1, test_buffer, result_buffer, 3, 1));
462     }
463     {
464         CONST D3DVERTEXELEMENT9 test_buffer[] =
465             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
466               { 0, 12, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
467         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4,
468             test_buffer, result_buffer, 3, 1));
469     }
470     {
471         CONST D3DVERTEXELEMENT9 test_buffer[] =
472             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
473               { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
474         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR,
475             test_buffer, result_buffer, 3, 1));
476     }
477     {
478          CONST D3DVERTEXELEMENT9 test_buffer[] =
479              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
480                { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
481          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2, test_buffer, result_buffer, 3, 1));
482     }
483     {
484          CONST D3DVERTEXELEMENT9 test_buffer[] =
485              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
486                { 0, 12, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
487                { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
488          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2 | D3DFVF_LASTBETA_UBYTE4,
489              test_buffer, result_buffer, 4, 1));
490      }
491      {
492          CONST D3DVERTEXELEMENT9 test_buffer[] =
493              { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
494                { 0, 12, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
495                { 0, 16, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
496          VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB2 | D3DFVF_LASTBETA_D3DCOLOR,
497              test_buffer, result_buffer, 4, 1));
498      }
499      {
500         CONST D3DVERTEXELEMENT9 test_buffer[] =
501             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
502               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
503         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3, test_buffer, result_buffer, 3, 1));
504     }
505     {
506         CONST D3DVERTEXELEMENT9 test_buffer[] =
507             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
508               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
509               { 0, 20, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
510         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3 | D3DFVF_LASTBETA_UBYTE4,
511             test_buffer, result_buffer, 4, 1));
512     }
513     {
514         CONST D3DVERTEXELEMENT9 test_buffer[] =
515             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
516               { 0, 12, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
517               { 0, 20, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
518         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB3 | D3DFVF_LASTBETA_D3DCOLOR,
519             test_buffer, result_buffer, 4, 1));
520     }
521     {
522         CONST D3DVERTEXELEMENT9 test_buffer[] =
523             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
524               { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 }, D3DDECL_END() };
525         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4, test_buffer, result_buffer, 3, 1));
526     }
527     {
528         CONST D3DVERTEXELEMENT9 test_buffer[] =
529             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
530               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
531               { 0, 24, D3DDECLTYPE_UBYTE4, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
532         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4,
533             test_buffer, result_buffer, 4, 1));
534     }
535     {
536         CONST D3DVERTEXELEMENT9 test_buffer[] =
537             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
538               { 0, 12, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
539               { 0, 24, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_BLENDINDICES, 0 }, D3DDECL_END() };
540         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_LASTBETA_D3DCOLOR,
541             test_buffer, result_buffer, 4, 1));
542     }
543     {
544         CONST D3DVERTEXELEMENT9 test_buffer[] =
545             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() };
546         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_NORMAL, test_buffer, result_buffer, 2, 1));
547     }
548     {
549         CONST D3DVERTEXELEMENT9 test_buffer[] =
550             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_PSIZE, 0 }, D3DDECL_END() };
551         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_PSIZE, test_buffer, result_buffer, 2, 1));
552     }
553     {
554         CONST D3DVERTEXELEMENT9 test_buffer[] =
555             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() };
556         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_DIFFUSE, test_buffer, result_buffer, 2, 1));
557     }
558     {
559         CONST D3DVERTEXELEMENT9 test_buffer[] =
560             { { 0, 0, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 }, D3DDECL_END() };
561         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_SPECULAR, test_buffer, result_buffer, 2, 1));
562     }
563
564     /* Make sure textures of different sizes work */
565     {
566         CONST D3DVERTEXELEMENT9 test_buffer[] =
567             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
568         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEX1,
569            test_buffer, result_buffer, 2, 1));
570     }
571     {
572         CONST D3DVERTEXELEMENT9 test_buffer[] =
573             { { 0, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
574         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEX1,
575            test_buffer, result_buffer, 2, 1));
576     }
577     {
578         CONST D3DVERTEXELEMENT9 test_buffer[] =
579             { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
580         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE3(0) | D3DFVF_TEX1,
581            test_buffer, result_buffer, 2, 1));
582     }
583     {
584         CONST D3DVERTEXELEMENT9 test_buffer[] =
585             { { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 0 }, D3DDECL_END() };
586         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_TEXCOORDSIZE4(0) | D3DFVF_TEX1,
587            test_buffer, result_buffer, 2, 1));
588     }
589
590     /* Make sure the TEXCOORD index works correctly - try several textures */
591     {
592         CONST D3DVERTEXELEMENT9 test_buffer[] =
593             { { 0, 0, D3DDECLTYPE_FLOAT1, 0, D3DDECLUSAGE_TEXCOORD, 0 },
594               { 0, 4, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 },
595               { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 2 },
596               { 0, 24, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_TEXCOORD, 3 }, D3DDECL_END() };
597         VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl,
598             D3DFVF_TEXCOORDSIZE1(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE2(2) |
599             D3DFVF_TEXCOORDSIZE4(3) | D3DFVF_TEX4, test_buffer, result_buffer, 5, 1));
600     }
601
602     /* Now try a combination test  */
603     {
604        CONST D3DVERTEXELEMENT9 test_buffer[] =
605                 { { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
606                   { 0, 12, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_BLENDWEIGHT, 0 },
607                   { 0, 28, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
608                   { 0, 32, D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 1 },
609                   { 0, 36, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
610                   { 0, 44, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_TEXCOORD, 1 }, D3DDECL_END() };
611        VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, D3DFVF_XYZB4 | D3DFVF_SPECULAR | D3DFVF_DIFFUSE |
612            D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEX2, test_buffer, result_buffer, 7, 1));
613     }
614
615     /* Setting the FVF to 0 should result in no change to the default decl */
616     VDECL_CHECK(test_fvf_to_decl(pDevice, default_decl, 0, default_elements, result_buffer, 3, 0));
617
618     cleanup:
619     IDirect3DDevice9_SetVertexDeclaration ( pDevice, NULL );
620     if ( default_decl ) IUnknown_Release (default_decl);
621 }
622
623 START_TEST(vertexdeclaration)
624 {
625     static D3DVERTEXELEMENT9 simple_decl[] = {
626         { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
627         D3DDECL_END()};
628     UINT simple_decl_num_elements = sizeof(simple_decl) / sizeof(*simple_decl);
629     IDirect3DDevice9 *device_ptr = 0;
630     IDirect3DVertexDeclaration9 *decl_ptr = 0;
631
632     d3d9_handle = LoadLibraryA("d3d9.dll");
633     if (!d3d9_handle)
634     {
635         skip("Could not load d3d9.dll\n");
636         return;
637     }
638
639     device_ptr = init_d3d9();
640     if (!device_ptr)
641     {
642         skip("Failed to initialise d3d9\n");
643         return;
644     }
645
646     decl_ptr = test_create_vertex_declaration(device_ptr, simple_decl);
647     if (!decl_ptr)
648     {
649         skip("Failed to create a vertex declaration\n");
650         return;
651     }
652
653     test_get_set_vertex_declaration(device_ptr, decl_ptr);
654     test_get_declaration(decl_ptr, simple_decl, simple_decl_num_elements);
655     test_fvf_decl_conversion(device_ptr);
656 }