d3dx9/tests: Avoid using FP_NAN for portability.
[wine] / dlls / d3dx9_36 / tests / core.c
1 /*
2  * Tests for the D3DX9 core interfaces
3  *
4  * Copyright 2009 Tony Wasserka
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #include "wine/test.h"
23 #include <dxerr9.h>
24 #include "d3dx9core.h"
25
26 static inline int get_ref(IUnknown *obj)
27 {
28     IUnknown_AddRef(obj);
29     return IUnknown_Release(obj);
30 }
31
32 static inline void check_ref(IUnknown *obj, int exp)
33 {
34     int ref = get_ref(obj);
35     ok (exp == ref, "Invalid refcount. Expected %d, got %d\n", exp, ref);
36 }
37
38 static inline void check_release(IUnknown *obj, int exp)
39 {
40     int ref = IUnknown_Release(obj);
41     ok (ref == exp, "Invalid refcount. Expected %d, got %d\n", exp, ref);
42 }
43
44 #define admitted_error 0.0001f
45 static inline void check_mat(D3DXMATRIX got, D3DXMATRIX exp)
46 {
47     int i, j, equal=1;
48     for (i=0; i<4; i++)
49         for (j=0; j<4; j++)
50             if (fabs(U(exp).m[i][j]-U(got).m[i][j]) > admitted_error)
51                 equal=0;
52
53     ok(equal, "Got matrix\n\t(%f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f)\n"
54        "Expected matrix=\n\t(%f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f\n\t %f,%f,%f,%f)\n",
55        U(got).m[0][0],U(got).m[0][1],U(got).m[0][2],U(got).m[0][3],
56        U(got).m[1][0],U(got).m[1][1],U(got).m[1][2],U(got).m[1][3],
57        U(got).m[2][0],U(got).m[2][1],U(got).m[2][2],U(got).m[2][3],
58        U(got).m[3][0],U(got).m[3][1],U(got).m[3][2],U(got).m[3][3],
59        U(exp).m[0][0],U(exp).m[0][1],U(exp).m[0][2],U(exp).m[0][3],
60        U(exp).m[1][0],U(exp).m[1][1],U(exp).m[1][2],U(exp).m[1][3],
61        U(exp).m[2][0],U(exp).m[2][1],U(exp).m[2][2],U(exp).m[2][3],
62        U(exp).m[3][0],U(exp).m[3][1],U(exp).m[3][2],U(exp).m[3][3]);
63 }
64
65 static void test_ID3DXBuffer(void)
66 {
67     ID3DXBuffer *buffer;
68     HRESULT hr;
69     ULONG count;
70     DWORD size;
71
72     hr = D3DXCreateBuffer(10, NULL);
73     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
74
75     hr = D3DXCreateBuffer(0, &buffer);
76     ok(hr == D3D_OK, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3D_OK);
77
78     size = ID3DXBuffer_GetBufferSize(buffer);
79     ok(!size, "GetBufferSize failed, got %u, expected %u\n", size, 0);
80
81     count = ID3DXBuffer_Release(buffer);
82     ok(!count, "ID3DBuffer has %u references left\n", count);
83
84     hr = D3DXCreateBuffer(3, &buffer);
85     ok(hr == D3D_OK, "D3DXCreateBuffer failed, got %#x, expected %#x\n", hr, D3D_OK);
86
87     size = ID3DXBuffer_GetBufferSize(buffer);
88     ok(size == 3, "GetBufferSize failed, got %u, expected %u\n", size, 3);
89
90     count = ID3DXBuffer_Release(buffer);
91     ok(!count, "ID3DBuffer has %u references left\n", count);
92 }
93
94 static void test_ID3DXSprite(IDirect3DDevice9 *device)
95 {
96     ID3DXSprite *sprite;
97     IDirect3D9 *d3d;
98     IDirect3DDevice9 *cmpdev;
99     IDirect3DTexture9 *tex1, *tex2;
100     D3DXMATRIX mat, cmpmat;
101     D3DVIEWPORT9 vp;
102     RECT rect;
103     D3DXVECTOR3 pos, center;
104     HRESULT hr;
105
106     IDirect3DDevice9_GetDirect3D(device, &d3d);
107     hr = IDirect3D9_CheckDeviceFormat(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
108     IDirect3D9_Release(d3d);
109     ok (hr == D3D_OK, "D3DFMT_A8R8G8B8 not supported\n");
110     if (FAILED(hr)) return;
111
112     hr = IDirect3DDevice9_CreateTexture(device, 64, 64, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex1, NULL);
113     ok (hr == D3D_OK, "Failed to create first texture (error code: %#x)\n", hr);
114     if (FAILED(hr)) return;
115
116     hr = IDirect3DDevice9_CreateTexture(device, 32, 32, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tex2, NULL);
117     ok (hr == D3D_OK, "Failed to create second texture (error code: %#x)\n", hr);
118     if (FAILED(hr)) {
119         IDirect3DTexture9_Release(tex1);
120         return;
121     }
122
123     /* Test D3DXCreateSprite */
124     hr = D3DXCreateSprite(device, NULL);
125     ok (hr == D3DERR_INVALIDCALL, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
126
127     hr = D3DXCreateSprite(NULL, &sprite);
128     ok (hr == D3DERR_INVALIDCALL, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
129
130     hr = D3DXCreateSprite(device, &sprite);
131     ok (hr == D3D_OK, "D3DXCreateSprite returned %#x, expected %#x\n", hr, D3D_OK);
132
133
134     /* Test ID3DXSprite_GetDevice */
135     hr = ID3DXSprite_GetDevice(sprite, NULL);
136     ok (hr == D3DERR_INVALIDCALL, "GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
137
138     hr = ID3DXSprite_GetDevice(sprite, &cmpdev);  /* cmpdev == NULL */
139     ok (hr == D3D_OK, "GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
140
141     hr = ID3DXSprite_GetDevice(sprite, &cmpdev);  /* cmpdev != NULL */
142     ok (hr == D3D_OK, "GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
143
144     IDirect3DDevice9_Release(device);
145     IDirect3DDevice9_Release(device);
146
147
148     /* Test ID3DXSprite_GetTransform */
149     hr = ID3DXSprite_GetTransform(sprite, NULL);
150     ok (hr == D3DERR_INVALIDCALL, "GetTransform returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
151     hr = ID3DXSprite_GetTransform(sprite, &mat);
152     ok (hr == D3D_OK, "GetTransform returned %#x, expected %#x\n", hr, D3D_OK);
153     if(SUCCEEDED(hr)) {
154         D3DXMATRIX identity;
155         D3DXMatrixIdentity(&identity);
156         check_mat(mat, identity);
157     }
158
159     /* Test ID3DXSprite_SetTransform */
160     /* Set a transform and test if it gets returned correctly */
161     U(mat).m[0][0]=2.1f;  U(mat).m[0][1]=6.5f;  U(mat).m[0][2]=-9.6f; U(mat).m[0][3]=1.7f;
162     U(mat).m[1][0]=4.2f;  U(mat).m[1][1]=-2.5f; U(mat).m[1][2]=2.1f;  U(mat).m[1][3]=5.5f;
163     U(mat).m[2][0]=-2.6f; U(mat).m[2][1]=0.3f;  U(mat).m[2][2]=8.6f;  U(mat).m[2][3]=8.4f;
164     U(mat).m[3][0]=6.7f;  U(mat).m[3][1]=-5.1f; U(mat).m[3][2]=6.1f;  U(mat).m[3][3]=2.2f;
165
166     hr = ID3DXSprite_SetTransform(sprite, NULL);
167     ok (hr == D3DERR_INVALIDCALL, "SetTransform returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
168
169     hr = ID3DXSprite_SetTransform(sprite, &mat);
170     ok (hr == D3D_OK, "SetTransform returned %#x, expected %#x\n", hr, D3D_OK);
171     if(SUCCEEDED(hr)) {
172         hr=ID3DXSprite_GetTransform(sprite, &cmpmat);
173         if(SUCCEEDED(hr)) check_mat(cmpmat, mat);
174         else skip("GetTransform returned %#x\n", hr);
175     }
176
177     /* Test ID3DXSprite_SetWorldViewLH/RH */
178     todo_wine {
179         hr = ID3DXSprite_SetWorldViewLH(sprite, &mat, &mat);
180         ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
181         hr = ID3DXSprite_SetWorldViewLH(sprite, NULL, &mat);
182         ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
183         hr = ID3DXSprite_SetWorldViewLH(sprite, &mat, NULL);
184         ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
185         hr = ID3DXSprite_SetWorldViewLH(sprite, NULL, NULL);
186         ok (hr == D3D_OK, "SetWorldViewLH returned %#x, expected %#x\n", hr, D3D_OK);
187
188         hr = ID3DXSprite_SetWorldViewRH(sprite, &mat, &mat);
189         ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
190         hr = ID3DXSprite_SetWorldViewRH(sprite, NULL, &mat);
191         ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
192         hr = ID3DXSprite_SetWorldViewRH(sprite, &mat, NULL);
193         ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
194         hr = ID3DXSprite_SetWorldViewRH(sprite, NULL, NULL);
195         ok (hr == D3D_OK, "SetWorldViewRH returned %#x, expected %#x\n", hr, D3D_OK);
196     }
197     IDirect3DDevice9_BeginScene(device);
198
199     /* Test ID3DXSprite_Begin*/
200     hr = ID3DXSprite_Begin(sprite, 0);
201     ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
202
203     IDirect3DDevice9_GetTransform(device, D3DTS_WORLD, &mat);
204     D3DXMatrixIdentity(&cmpmat);
205     check_mat(mat, cmpmat);
206
207     IDirect3DDevice9_GetTransform(device, D3DTS_VIEW, &mat);
208     check_mat(mat, cmpmat);
209
210     IDirect3DDevice9_GetTransform(device, D3DTS_PROJECTION, &mat);
211     IDirect3DDevice9_GetViewport(device, &vp);
212     D3DXMatrixOrthoOffCenterLH(&cmpmat, vp.X+0.5f, (float)vp.Width+vp.X+0.5f, (float)vp.Height+vp.Y+0.5f, vp.Y+0.5f, vp.MinZ, vp.MaxZ);
213     check_mat(mat, cmpmat);
214
215     /* Test ID3DXSprite_Flush and ID3DXSprite_End */
216     hr = ID3DXSprite_Flush(sprite);
217     ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
218
219     hr = ID3DXSprite_End(sprite);
220     ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
221
222     hr = ID3DXSprite_Flush(sprite); /* May not be called before next Begin */
223     ok (hr == D3DERR_INVALIDCALL, "Flush returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
224     hr = ID3DXSprite_End(sprite);
225     ok (hr == D3DERR_INVALIDCALL, "End returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
226
227     /* Test ID3DXSprite_Draw */
228     hr = ID3DXSprite_Begin(sprite, 0);
229     ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
230
231     if(FAILED(hr)) skip("Couldn't ID3DXSprite_Begin, can't test ID3DXSprite_Draw\n");
232     else { /* Feed the sprite batch */
233         int texref1, texref2;
234
235         SetRect(&rect, 53, 12, 142, 165);
236         pos.x    =  2.2f; pos.y    = 4.5f; pos.z    = 5.1f;
237         center.x = 11.3f; center.y = 3.4f; center.z = 1.2f;
238
239         texref1 = get_ref((IUnknown*)tex1);
240         texref2 = get_ref((IUnknown*)tex2);
241
242         hr = ID3DXSprite_Draw(sprite, NULL, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
243         ok (hr == D3DERR_INVALIDCALL, "Draw returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
244
245         hr = ID3DXSprite_Draw(sprite, tex1, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
246         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
247         hr = ID3DXSprite_Draw(sprite, tex2, &rect, &center, &pos, D3DCOLOR_XRGB(  3,  45,  66));
248         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
249         hr = ID3DXSprite_Draw(sprite, tex1,  NULL, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
250         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
251         hr = ID3DXSprite_Draw(sprite, tex1, &rect,    NULL, &pos, D3DCOLOR_XRGB(255, 255, 255));
252         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
253         hr = ID3DXSprite_Draw(sprite, tex1, &rect, &center, NULL, D3DCOLOR_XRGB(255, 255, 255));
254         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
255         hr = ID3DXSprite_Draw(sprite, tex1,  NULL,    NULL, NULL,                            0);
256         ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
257
258         check_ref((IUnknown*)tex1, texref1+5); check_ref((IUnknown*)tex2, texref2+1);
259         hr = ID3DXSprite_Flush(sprite);
260         ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
261         hr = ID3DXSprite_Flush(sprite);   /* Flushing twice should work */
262         ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
263         check_ref((IUnknown*)tex1, texref1);   check_ref((IUnknown*)tex2, texref2);
264
265         hr = ID3DXSprite_End(sprite);
266         ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
267     }
268
269     /* Test ID3DXSprite_OnLostDevice and ID3DXSprite_OnResetDevice */
270     /* Both can be called twice */
271     hr = ID3DXSprite_OnLostDevice(sprite);
272     ok (hr == D3D_OK, "OnLostDevice returned %#x, expected %#x\n", hr, D3D_OK);
273     hr = ID3DXSprite_OnLostDevice(sprite);
274     ok (hr == D3D_OK, "OnLostDevice returned %#x, expected %#x\n", hr, D3D_OK);
275     hr = ID3DXSprite_OnResetDevice(sprite);
276     ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
277     hr = ID3DXSprite_OnResetDevice(sprite);
278     ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
279
280     /* Make sure everything works like before */
281     hr = ID3DXSprite_Begin(sprite, 0);
282     ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
283     hr = ID3DXSprite_Draw(sprite, tex2, &rect, &center, &pos, D3DCOLOR_XRGB(255, 255, 255));
284     ok (hr == D3D_OK, "Draw returned %#x, expected %#x\n", hr, D3D_OK);
285     hr = ID3DXSprite_Flush(sprite);
286     ok (hr == D3D_OK, "Flush returned %#x, expected %#x\n", hr, D3D_OK);
287     hr = ID3DXSprite_End(sprite);
288     ok (hr == D3D_OK, "End returned %#x, expected %#x\n", hr, D3D_OK);
289
290     /* OnResetDevice makes the interface "forget" the Begin call */
291     hr = ID3DXSprite_Begin(sprite, 0);
292     ok (hr == D3D_OK, "Begin returned %#x, expected %#x\n", hr, D3D_OK);
293     hr = ID3DXSprite_OnResetDevice(sprite);
294     ok (hr == D3D_OK, "OnResetDevice returned %#x, expected %#x\n", hr, D3D_OK);
295     hr = ID3DXSprite_End(sprite);
296     ok (hr == D3DERR_INVALIDCALL, "End returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
297
298     IDirect3DDevice9_EndScene(device);
299     check_release((IUnknown*)sprite, 0);
300     check_release((IUnknown*)tex2, 0);
301     check_release((IUnknown*)tex1, 0);
302 }
303
304 static void test_ID3DXFont(IDirect3DDevice9 *device)
305 {
306     D3DXFONT_DESC desc;
307     ID3DXFont *font;
308     HRESULT hr;
309     int ref;
310
311
312     /* D3DXCreateFont */
313     ref = get_ref((IUnknown*)device);
314     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
315     ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
316     check_ref((IUnknown*)device, ref + 1);
317     check_release((IUnknown*)font, 0);
318     check_ref((IUnknown*)device, ref);
319
320     hr = D3DXCreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
321     ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
322     ID3DXFont_Release(font);
323
324     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL, &font);
325     ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
326     ID3DXFont_Release(font);
327
328     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "", &font);
329     ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK);
330     ID3DXFont_Release(font);
331
332     hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
333     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
334
335     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL);
336     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
337
338     hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL);
339     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
340
341
342     /* D3DXCreateFontIndirect */
343     desc.Height = 12;
344     desc.Width = 0;
345     desc.Weight = FW_DONTCARE;
346     desc.MipLevels = 0;
347     desc.Italic = FALSE;
348     desc.CharSet = DEFAULT_CHARSET;
349     desc.OutputPrecision = OUT_DEFAULT_PRECIS;
350     desc.Quality = DEFAULT_QUALITY;
351     desc.PitchAndFamily = DEFAULT_PITCH;
352     strcpy(desc.FaceName, "Arial");
353     hr = D3DXCreateFontIndirectA(device, &desc, &font);
354     ok(hr == D3D_OK, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3D_OK);
355     ID3DXFont_Release(font);
356
357     hr = D3DXCreateFontIndirectA(NULL, &desc, &font);
358     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
359
360     hr = D3DXCreateFontIndirectA(device, NULL, &font);
361     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
362
363     hr = D3DXCreateFontIndirectA(device, &desc, NULL);
364     ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
365
366
367     /* ID3DXFont_GetDevice */
368     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
369     if(SUCCEEDED(hr)) {
370         IDirect3DDevice9 *bufdev;
371
372         hr = ID3DXFont_GetDevice(font, NULL);
373         ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
374
375         ref = get_ref((IUnknown*)device);
376         hr = ID3DXFont_GetDevice(font, &bufdev);
377         ok(hr == D3D_OK, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
378         check_release((IUnknown*)bufdev, ref);
379
380         ID3DXFont_Release(font);
381     } else skip("Failed to create a ID3DXFont object\n");
382
383
384     /* ID3DXFont_GetDesc */
385     hr = D3DXCreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, "Arial", &font);
386     if(SUCCEEDED(hr)) {
387         hr = ID3DXFont_GetDescA(font, NULL);
388         ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
389
390         hr = ID3DXFont_GetDescA(font, &desc);
391         ok(hr == D3D_OK, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3D_OK);
392
393         ok(desc.Height == 12, "ID3DXFont_GetDesc returned font height %d, expected %d\n", desc.Height, 12);
394         ok(desc.Width == 8, "ID3DXFont_GetDesc returned font width %d, expected %d\n", desc.Width, 8);
395         ok(desc.Weight == FW_BOLD, "ID3DXFont_GetDesc returned font weight %d, expected %d\n", desc.Weight, FW_BOLD);
396         ok(desc.MipLevels == 2, "ID3DXFont_GetDesc returned font miplevels %d, expected %d\n", desc.MipLevels, 2);
397         ok(desc.Italic == TRUE, "ID3DXFont_GetDesc says Italic was %d, but Italic should be %d\n", desc.Italic, TRUE);
398         ok(desc.CharSet == ANSI_CHARSET, "ID3DXFont_GetDesc returned font charset %d, expected %d\n", desc.CharSet, ANSI_CHARSET);
399         ok(desc.OutputPrecision == OUT_RASTER_PRECIS, "ID3DXFont_GetDesc returned an output precision of %d, expected %d\n", desc.OutputPrecision, OUT_RASTER_PRECIS);
400         ok(desc.Quality == ANTIALIASED_QUALITY, "ID3DXFont_GetDesc returned font quality %d, expected %d\n", desc.Quality, ANTIALIASED_QUALITY);
401         ok(desc.PitchAndFamily == VARIABLE_PITCH, "ID3DXFont_GetDesc returned pitch and family %d, expected %d\n", desc.PitchAndFamily, VARIABLE_PITCH);
402         ok(strcmp(desc.FaceName, "Arial") == 0, "ID3DXFont_GetDesc returned facename \"%s\", expected \"%s\"\n", desc.FaceName, "Arial");
403
404         ID3DXFont_Release(font);
405     } else skip("Failed to create a ID3DXFont object\n");
406
407
408     /* ID3DXFont_GetDC + ID3DXFont_GetTextMetrics */
409     hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font);
410     if(SUCCEEDED(hr)) {
411         HDC hdc;
412
413         hdc = ID3DXFont_GetDC(font);
414         ok(hdc != NULL, "ID3DXFont_GetDC returned an invalid handle\n");
415         if(hdc) {
416             TEXTMETRICA metrics, expmetrics;
417             BOOL ret;
418
419             ret = ID3DXFont_GetTextMetricsA(font, &metrics);
420             ok(ret, "ID3DXFont_GetTextMetricsA failed\n");
421             ret = GetTextMetricsA(hdc, &expmetrics);
422             ok(ret, "GetTextMetricsA failed\n");
423
424             ok(metrics.tmHeight == expmetrics.tmHeight, "Returned height %d, expected %d\n", metrics.tmHeight, expmetrics.tmHeight);
425             ok(metrics.tmAscent == expmetrics.tmAscent, "Returned ascent %d, expected %d\n", metrics.tmAscent, expmetrics.tmAscent);
426             ok(metrics.tmDescent == expmetrics.tmDescent, "Returned descent %d, expected %d\n", metrics.tmDescent, expmetrics.tmDescent);
427             ok(metrics.tmInternalLeading == expmetrics.tmInternalLeading, "Returned internal leading %d, expected %d\n", metrics.tmInternalLeading, expmetrics.tmInternalLeading);
428             ok(metrics.tmExternalLeading == expmetrics.tmExternalLeading, "Returned external leading %d, expected %d\n", metrics.tmExternalLeading, expmetrics.tmExternalLeading);
429             ok(metrics.tmAveCharWidth == expmetrics.tmAveCharWidth, "Returned average char width %d, expected %d\n", metrics.tmAveCharWidth, expmetrics.tmAveCharWidth);
430             ok(metrics.tmMaxCharWidth == expmetrics.tmMaxCharWidth, "Returned maximum char width %d, expected %d\n", metrics.tmMaxCharWidth, expmetrics.tmMaxCharWidth);
431             ok(metrics.tmWeight == expmetrics.tmWeight, "Returned weight %d, expected %d\n", metrics.tmWeight, expmetrics.tmWeight);
432             ok(metrics.tmOverhang == expmetrics.tmOverhang, "Returned overhang %d, expected %d\n", metrics.tmOverhang, expmetrics.tmOverhang);
433             ok(metrics.tmDigitizedAspectX == expmetrics.tmDigitizedAspectX, "Returned digitized x aspect %d, expected %d\n", metrics.tmDigitizedAspectX, expmetrics.tmDigitizedAspectX);
434             ok(metrics.tmDigitizedAspectY == expmetrics.tmDigitizedAspectY, "Returned digitized y aspect %d, expected %d\n", metrics.tmDigitizedAspectY, expmetrics.tmDigitizedAspectY);
435             ok(metrics.tmFirstChar == expmetrics.tmFirstChar, "Returned first char %d, expected %d\n", metrics.tmFirstChar, expmetrics.tmFirstChar);
436             ok(metrics.tmLastChar == expmetrics.tmLastChar, "Returned last char %d, expected %d\n", metrics.tmLastChar, expmetrics.tmLastChar);
437             ok(metrics.tmDefaultChar == expmetrics.tmDefaultChar, "Returned default char %d, expected %d\n", metrics.tmDefaultChar, expmetrics.tmDefaultChar);
438             ok(metrics.tmBreakChar == expmetrics.tmBreakChar, "Returned break char %d, expected %d\n", metrics.tmBreakChar, expmetrics.tmBreakChar);
439             ok(metrics.tmItalic == expmetrics.tmItalic, "Returned italic %d, expected %d\n", metrics.tmItalic, expmetrics.tmItalic);
440             ok(metrics.tmUnderlined == expmetrics.tmUnderlined, "Returned underlined %d, expected %d\n", metrics.tmUnderlined, expmetrics.tmUnderlined);
441             ok(metrics.tmStruckOut == expmetrics.tmStruckOut, "Returned struck out %d, expected %d\n", metrics.tmStruckOut, expmetrics.tmStruckOut);
442             ok(metrics.tmPitchAndFamily == expmetrics.tmPitchAndFamily, "Returned pitch and family %d, expected %d\n", metrics.tmPitchAndFamily, expmetrics.tmPitchAndFamily);
443             ok(metrics.tmCharSet == expmetrics.tmCharSet, "Returned charset %d, expected %d\n", metrics.tmCharSet, expmetrics.tmCharSet);
444         }
445         ID3DXFont_Release(font);
446     } else skip("Failed to create a ID3DXFont object\n");
447 }
448
449 START_TEST(core)
450 {
451     HWND wnd;
452     IDirect3D9 *d3d;
453     IDirect3DDevice9 *device;
454     D3DPRESENT_PARAMETERS d3dpp;
455     HRESULT hr;
456
457     wnd = CreateWindow("static", "d3dx9_test", 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
458     d3d = Direct3DCreate9(D3D_SDK_VERSION);
459     if (!wnd) {
460         skip("Couldn't create application window\n");
461         return;
462     }
463    if (!d3d) {
464         skip("Couldn't create IDirect3D9 object\n");
465         DestroyWindow(wnd);
466         return;
467     }
468
469     ZeroMemory(&d3dpp, sizeof(d3dpp));
470     d3dpp.Windowed   = TRUE;
471     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
472     hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &device);
473     if(FAILED(hr)) {
474         skip("Failed to create IDirect3DDevice9 object %#x\n", hr);
475         IDirect3D9_Release(d3d);
476         DestroyWindow(wnd);
477         return;
478     }
479
480     test_ID3DXBuffer();
481     test_ID3DXSprite(device);
482     test_ID3DXFont(device);
483
484     check_release((IUnknown*)device, 0);
485     check_release((IUnknown*)d3d, 0);
486     if (wnd) DestroyWindow(wnd);
487 }