- Fix text placement.
[wine] / dlls / ddraw / direct3d_opengl.c
1 /*
2  * Copyright 2000 Marcus Meissner
3  * Copyright 2000 Peter Hunnisett
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include "config.h"
21
22 #include <assert.h>
23 #ifdef HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
26 #include <fcntl.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "d3d.h"
38 #include "ddraw.h"
39 #include "winerror.h"
40
41 #include "ddraw_private.h"
42 #include "d3d_private.h"
43 #include "opengl_private.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
48
49 HRESULT WINAPI
50 GL_IDirect3DImpl_1_EnumDevices(LPDIRECT3D iface,
51                                LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback,
52                                LPVOID lpUserArg)
53 {
54     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
55     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
56
57     /* Call functions defined in d3ddevices.c */
58     if (d3ddevice_enumerate(lpEnumDevicesCallback, lpUserArg, 1) != D3DENUMRET_OK)
59         return D3D_OK;
60
61     return D3D_OK;
62 }
63
64 HRESULT WINAPI
65 GL_IDirect3DImpl_2_EnumDevices(LPDIRECT3D2 iface,
66                                   LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback,
67                                   LPVOID lpUserArg)
68 {
69     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
70     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
71
72     /* Call functions defined in d3ddevices.c */
73     if (d3ddevice_enumerate(lpEnumDevicesCallback, lpUserArg, 2) != D3DENUMRET_OK)
74         return D3D_OK;
75
76     return D3D_OK;
77 }
78
79 HRESULT WINAPI
80 GL_IDirect3DImpl_3_EnumDevices(LPDIRECT3D3 iface,
81                                   LPD3DENUMDEVICESCALLBACK lpEnumDevicesCallback,
82                                   LPVOID lpUserArg)
83 {
84     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
85     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
86
87     /* Call functions defined in d3ddevices.c */
88     if (d3ddevice_enumerate(lpEnumDevicesCallback, lpUserArg, 3) != D3DENUMRET_OK)
89         return D3D_OK;
90
91     return D3D_OK;
92 }
93
94 HRESULT WINAPI
95 GL_IDirect3DImpl_3_2T_1T_CreateLight(LPDIRECT3D3 iface,
96                                      LPDIRECT3DLIGHT* lplpDirect3DLight,
97                                      IUnknown* pUnkOuter)
98 {
99     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
100     IDirect3DGLImpl *glThis = (IDirect3DGLImpl *) This->d3d_private;
101     int fl;
102     IDirect3DLightImpl *d3dlimpl;
103     HRESULT ret_value;
104     
105     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpDirect3DLight, pUnkOuter);
106     for (fl = 0; fl < MAX_LIGHTS; fl++) {
107         if ((glThis->free_lights & (0x01 << fl)) != 0) {
108             glThis->free_lights &= ~(0x01 << fl);
109             break;
110         }
111     }
112     if (fl == MAX_LIGHTS) {
113         return DDERR_INVALIDPARAMS; /* No way to say 'max lights reached' ... */
114     }
115     ret_value = d3dlight_create(&d3dlimpl, This, GL_LIGHT0 + fl);
116     *lplpDirect3DLight = ICOM_INTERFACE(d3dlimpl, IDirect3DLight);
117
118     return ret_value;
119 }
120
121 HRESULT WINAPI
122 GL_IDirect3DImpl_3_2T_1T_CreateMaterial(LPDIRECT3D3 iface,
123                                         LPDIRECT3DMATERIAL3* lplpDirect3DMaterial3,
124                                         IUnknown* pUnkOuter)
125 {
126     IDirect3DMaterialImpl *D3Dmat_impl;
127     HRESULT ret_value;
128     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
129     
130     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpDirect3DMaterial3, pUnkOuter);
131     ret_value = d3dmaterial_create(&D3Dmat_impl, This);
132
133     *lplpDirect3DMaterial3 = ICOM_INTERFACE(D3Dmat_impl, IDirect3DMaterial3);
134
135     return ret_value;
136 }
137
138 HRESULT WINAPI
139 GL_IDirect3DImpl_3_2T_1T_CreateViewport(LPDIRECT3D3 iface,
140                                         LPDIRECT3DVIEWPORT3* lplpD3DViewport3,
141                                         IUnknown* pUnkOuter)
142 {
143     IDirect3DViewportImpl *D3Dvp_impl;
144     HRESULT ret_value;
145     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
146     
147     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lplpD3DViewport3, pUnkOuter);
148     ret_value = d3dviewport_create(&D3Dvp_impl, This);
149
150     *lplpD3DViewport3 = ICOM_INTERFACE(D3Dvp_impl, IDirect3DViewport3);
151
152     return ret_value;
153 }
154
155 static HRESULT
156 create_device_helper(IDirectDrawImpl *This,
157                      REFCLSID iid,
158                      IDirectDrawSurfaceImpl *lpDDS,
159                      void **obj,
160                      int version) {
161     IDirect3DDeviceImpl *lpd3ddev;
162     HRESULT ret_value;
163
164     ret_value = d3ddevice_create(&lpd3ddev, This, lpDDS, version);
165     if (FAILED(ret_value)) return ret_value;
166     
167     if ((iid == NULL) ||
168         (IsEqualGUID(&IID_D3DDEVICE_OpenGL, iid)) ||
169         (IsEqualGUID(&IID_IDirect3DHALDevice, iid)) ||
170         (IsEqualGUID(&IID_IDirect3DTnLHalDevice, iid)) ||
171         (IsEqualGUID(&IID_IDirect3DRGBDevice, iid)) ||
172         (IsEqualGUID(&IID_IDirect3DRefDevice, iid))) {
173         switch (version) {
174             case 1:
175                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice);
176                 TRACE(" returning OpenGL D3DDevice %p.\n", *obj);
177                 return D3D_OK;
178
179             case 2:
180                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice2);
181                 TRACE(" returning OpenGL D3DDevice2 %p.\n", *obj);
182                 return D3D_OK;
183
184             case 3:
185                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice3);
186                 TRACE(" returning OpenGL D3DDevice3 %p.\n", *obj);
187                 return D3D_OK;
188
189             case 7:
190                 *obj = ICOM_INTERFACE(lpd3ddev, IDirect3DDevice7);
191                 TRACE(" returning OpenGL D3DDevice7 %p.\n", *obj);
192                 return D3D_OK;
193         }
194     }
195
196     *obj = NULL;
197     ERR(" Interface unknown when creating D3DDevice (%s)\n", debugstr_guid(iid));
198     IDirect3DDevice7_Release(ICOM_INTERFACE(lpd3ddev, IDirect3DDevice7));
199     return DDERR_INVALIDPARAMS;
200 }
201      
202
203 HRESULT WINAPI
204 GL_IDirect3DImpl_2_CreateDevice(LPDIRECT3D2 iface,
205                                 REFCLSID rclsid,
206                                 LPDIRECTDRAWSURFACE lpDDS,
207                                 LPDIRECT3DDEVICE2* lplpD3DDevice2)
208 {
209     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
210     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface3, lpDDS);
211     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice2);
212     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice2, 2);
213 }
214
215 HRESULT WINAPI
216 GL_IDirect3DImpl_3_CreateDevice(LPDIRECT3D3 iface,
217                                 REFCLSID rclsid,
218                                 LPDIRECTDRAWSURFACE4 lpDDS,
219                                 LPDIRECT3DDEVICE3* lplpD3DDevice3,
220                                 LPUNKNOWN lpUnk)
221 {
222     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
223     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpDDS);
224     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice3);
225     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice3, 3);
226 }
227
228 HRESULT WINAPI
229 GL_IDirect3DImpl_3_2T_1T_FindDevice(LPDIRECT3D3 iface,
230                                     LPD3DFINDDEVICESEARCH lpD3DDFS,
231                                     LPD3DFINDDEVICERESULT lpD3DFDR)
232 {
233     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
234     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DDFS, lpD3DFDR);
235     return d3ddevice_find(This, lpD3DDFS, lpD3DFDR);
236 }
237
238 HRESULT WINAPI
239 GL_IDirect3DImpl_7_3T_EnumZBufferFormats(LPDIRECT3D7 iface,
240                                          REFCLSID riidDevice,
241                                          LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback,
242                                          LPVOID lpContext)
243 {
244     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
245     DDPIXELFORMAT pformat;
246     
247     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(riidDevice), lpEnumCallback, lpContext);
248
249     memset(&pformat, 0, sizeof(pformat));
250     pformat.dwSize = sizeof(DDPIXELFORMAT);
251     pformat.dwFourCC = 0;   
252     TRACE("Enumerating dummy ZBuffer format (16 bits)\n");
253     pformat.dwFlags = DDPF_ZBUFFER;
254     pformat.u1.dwZBufferBitDepth = 16;
255     pformat.u3.dwZBitMask =    0x0000FFFF;
256     pformat.u5.dwRGBZBitMask = 0x0000FFFF;
257
258     /* Whatever the return value, stop here.. */
259     lpEnumCallback(&pformat, lpContext);
260     
261     return D3D_OK;
262 }
263
264 HRESULT WINAPI
265 GL_IDirect3DImpl_7_EnumDevices(LPDIRECT3D7 iface,
266                                LPD3DENUMDEVICESCALLBACK7 lpEnumDevicesCallback,
267                                LPVOID lpUserArg)
268 {
269     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
270     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpEnumDevicesCallback, lpUserArg);
271
272     if (d3ddevice_enumerate7(lpEnumDevicesCallback, lpUserArg) != D3DENUMRET_OK)
273         return D3D_OK;
274     
275     return D3D_OK;
276 }
277
278 HRESULT WINAPI
279 GL_IDirect3DImpl_7_CreateDevice(LPDIRECT3D7 iface,
280                                 REFCLSID rclsid,
281                                 LPDIRECTDRAWSURFACE7 lpDDS,
282                                 LPDIRECT3DDEVICE7* lplpD3DDevice)
283 {
284     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
285     IDirectDrawSurfaceImpl *ddsurfaceimpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpDDS);
286     TRACE("(%p/%p)->(%s,%p,%p)\n", This, iface, debugstr_guid(rclsid), lpDDS, lplpD3DDevice);
287     return create_device_helper(This, rclsid, ddsurfaceimpl, (void **) lplpD3DDevice, 7);
288 }
289
290 HRESULT WINAPI
291 GL_IDirect3DImpl_7_3T_CreateVertexBuffer(LPDIRECT3D7 iface,
292                                          LPD3DVERTEXBUFFERDESC lpD3DVertBufDesc,
293                                          LPDIRECT3DVERTEXBUFFER7* lplpD3DVertBuf,
294                                          DWORD dwFlags)
295 {
296     ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
297     IDirect3DVertexBufferImpl *vbimpl;
298     HRESULT res;
299     
300     TRACE("(%p/%p)->(%p,%p,%08lx)\n", This, iface, lpD3DVertBufDesc, lplpD3DVertBuf, dwFlags);
301
302     res = d3dvertexbuffer_create(&vbimpl, This, lpD3DVertBufDesc, dwFlags);
303
304     *lplpD3DVertBuf = ICOM_INTERFACE(vbimpl, IDirect3DVertexBuffer7);
305     
306     return res;
307 }
308
309 static void light_released(IDirectDrawImpl *This, GLenum light_num)
310 {
311     IDirect3DGLImpl *glThis = (IDirect3DGLImpl *) This->d3d_private;
312     glThis->free_lights |= (light_num - GL_LIGHT0);
313 }
314
315 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
316 # define XCAST(fun)     (typeof(VTABLE_IDirect3D7.fun))
317 #else
318 # define XCAST(fun)     (void*)
319 #endif
320
321 static const IDirect3D7Vtbl VTABLE_IDirect3D7 =
322 {
323     XCAST(QueryInterface) Thunk_IDirect3DImpl_7_QueryInterface,
324     XCAST(AddRef) Thunk_IDirect3DImpl_7_AddRef,
325     XCAST(Release) Thunk_IDirect3DImpl_7_Release,
326     XCAST(EnumDevices) GL_IDirect3DImpl_7_EnumDevices,
327     XCAST(CreateDevice) GL_IDirect3DImpl_7_CreateDevice,
328     XCAST(CreateVertexBuffer) GL_IDirect3DImpl_7_3T_CreateVertexBuffer,
329     XCAST(EnumZBufferFormats) GL_IDirect3DImpl_7_3T_EnumZBufferFormats,
330     XCAST(EvictManagedTextures) Main_IDirect3DImpl_7_3T_EvictManagedTextures,
331 };
332
333 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
334 #undef XCAST
335 #endif
336
337
338 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
339 # define XCAST(fun)     (typeof(VTABLE_IDirect3D3.fun))
340 #else
341 # define XCAST(fun)     (void*)
342 #endif
343
344 static const IDirect3D3Vtbl VTABLE_IDirect3D3 =
345 {
346     XCAST(QueryInterface) Thunk_IDirect3DImpl_3_QueryInterface,
347     XCAST(AddRef) Thunk_IDirect3DImpl_3_AddRef,
348     XCAST(Release) Thunk_IDirect3DImpl_3_Release,
349     XCAST(EnumDevices) GL_IDirect3DImpl_3_EnumDevices,
350     XCAST(CreateLight) GL_IDirect3DImpl_3_2T_1T_CreateLight,
351     XCAST(CreateMaterial) GL_IDirect3DImpl_3_2T_1T_CreateMaterial,
352     XCAST(CreateViewport) GL_IDirect3DImpl_3_2T_1T_CreateViewport,
353     XCAST(FindDevice) GL_IDirect3DImpl_3_2T_1T_FindDevice,
354     XCAST(CreateDevice) GL_IDirect3DImpl_3_CreateDevice,
355     XCAST(CreateVertexBuffer) Thunk_IDirect3DImpl_3_CreateVertexBuffer,
356     XCAST(EnumZBufferFormats) Thunk_IDirect3DImpl_3_EnumZBufferFormats,
357     XCAST(EvictManagedTextures) Thunk_IDirect3DImpl_3_EvictManagedTextures,
358 };
359
360 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
361 #undef XCAST
362 #endif
363
364
365 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
366 # define XCAST(fun)     (typeof(VTABLE_IDirect3D2.fun))
367 #else
368 # define XCAST(fun)     (void*)
369 #endif
370
371 static const IDirect3D2Vtbl VTABLE_IDirect3D2 =
372 {
373     XCAST(QueryInterface) Thunk_IDirect3DImpl_2_QueryInterface,
374     XCAST(AddRef) Thunk_IDirect3DImpl_2_AddRef,
375     XCAST(Release) Thunk_IDirect3DImpl_2_Release,
376     XCAST(EnumDevices) GL_IDirect3DImpl_2_EnumDevices,
377     XCAST(CreateLight) Thunk_IDirect3DImpl_2_CreateLight,
378     XCAST(CreateMaterial) Thunk_IDirect3DImpl_2_CreateMaterial,
379     XCAST(CreateViewport) Thunk_IDirect3DImpl_2_CreateViewport,
380     XCAST(FindDevice) Thunk_IDirect3DImpl_2_FindDevice,
381     XCAST(CreateDevice) GL_IDirect3DImpl_2_CreateDevice,
382 };
383
384 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
385 #undef XCAST
386 #endif
387
388
389 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
390 # define XCAST(fun)     (typeof(VTABLE_IDirect3D.fun))
391 #else
392 # define XCAST(fun)     (void*)
393 #endif
394
395 static const IDirect3DVtbl VTABLE_IDirect3D =
396 {
397     XCAST(QueryInterface) Thunk_IDirect3DImpl_1_QueryInterface,
398     XCAST(AddRef) Thunk_IDirect3DImpl_1_AddRef,
399     XCAST(Release) Thunk_IDirect3DImpl_1_Release,
400     XCAST(Initialize) Main_IDirect3DImpl_1_Initialize,
401     XCAST(EnumDevices) GL_IDirect3DImpl_1_EnumDevices,
402     XCAST(CreateLight) Thunk_IDirect3DImpl_1_CreateLight,
403     XCAST(CreateMaterial) Thunk_IDirect3DImpl_1_CreateMaterial,
404     XCAST(CreateViewport) Thunk_IDirect3DImpl_1_CreateViewport,
405     XCAST(FindDevice) Thunk_IDirect3DImpl_1_FindDevice,
406 };
407
408 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
409 #undef XCAST
410 #endif
411
412 static HRESULT d3d_add_device(IDirectDrawImpl *This, IDirect3DDeviceImpl *device)
413 {
414     if  (This->current_device == NULL) {
415         /* Create delayed textures now that we have an OpenGL context...
416            For that, go through all surface attached to our DDraw object and create
417            OpenGL textures for all textures.. */
418         IDirectDrawSurfaceImpl *surf = This->surfaces;
419
420         while (surf != NULL) {
421             if (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) {
422                 /* Found a texture.. Now create the OpenGL part */
423                 d3dtexture_create(This, surf, FALSE, surf->mip_main);
424             }
425             surf = surf->next_ddraw;
426         }
427     }
428     /* For the moment, only one device 'supported'... */
429     This->current_device = device;
430
431     return DD_OK;
432 }
433
434 static HRESULT d3d_remove_device(IDirectDrawImpl *This, IDirect3DDeviceImpl *device)
435 {
436     This->current_device = NULL;
437     return DD_OK;
438 }
439
440 HRESULT direct3d_create(IDirectDrawImpl *This)
441 {
442     IDirect3DGLImpl *globject;
443     
444     globject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DGLImpl));
445     if (globject == NULL) return DDERR_OUTOFMEMORY;
446
447     This->d3d_create_texture = d3dtexture_create;
448     This->d3d_added_device = d3d_add_device;
449     This->d3d_removed_device = d3d_remove_device;
450
451     ICOM_INIT_INTERFACE(This, IDirect3D,  VTABLE_IDirect3D);
452     ICOM_INIT_INTERFACE(This, IDirect3D2, VTABLE_IDirect3D2);
453     ICOM_INIT_INTERFACE(This, IDirect3D3, VTABLE_IDirect3D3);
454     ICOM_INIT_INTERFACE(This, IDirect3D7, VTABLE_IDirect3D7);
455
456     globject->free_lights = (0x01 << MAX_LIGHTS) - 1; /* There are, in total, 8 lights in OpenGL */
457     globject->light_released = light_released;
458
459     This->d3d_private = globject;
460
461     TRACE(" creating OpenGL private storage at %p.\n", globject);
462     
463     return D3D_OK;
464 }