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