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