Added regedit unit test, a couple minor changes to regedit.
[wine] / dlls / ddraw / d3ddevice / mesa.c
1 /* Direct3D Device
2  * Copyright (c) 1998 Lionel ULMER
3  *
4  * This file contains the MESA implementation of all the D3D devices that
5  * Wine supports.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winerror.h"
28 #include "wine/obj_base.h"
29 #include "ddraw.h"
30 #include "d3d.h"
31 #include "wine/debug.h"
32
33 #include "mesa_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36
37 ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable;
38 ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3;
39
40 /* Define this variable if you have an unpatched Mesa 3.0 (patches are available
41    on Mesa's home page) or version 3.1b.
42
43    Version 3.1b2 should correct this bug */
44 #undef HAVE_BUGGY_MESAGL
45
46 #define D3DDPRIVATE(x) mesa_d3dd_private *odev=((mesa_d3dd_private*)x->private)
47
48 #ifndef HAVE_GLEXT_PROTOTYPES
49 /* This is for non-OpenGL ABI compliant glext.h headers :-) */
50 typedef void (* PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat,
51                                          GLsizei width, GLenum format, GLenum type,
52                                          const GLvoid *table);
53 #endif
54
55 static const float id_mat[16] = {
56   1.0, 0.0, 0.0, 0.0,
57   0.0, 1.0, 0.0, 0.0,
58   0.0, 0.0, 1.0, 0.0,
59   0.0, 0.0, 0.0, 1.0
60 };
61
62 /*******************************************************************************
63  *                              OpenGL static functions
64  */
65 static void set_context(IDirect3DDevice2Impl* This) {
66 #if COMPILABLE
67     D3DDPRIVATE(This);
68
69     if (glXMakeCurrent(gdi_display,ddpriv->drawable, odev->ctx) == False) {
70         ERR("Error in setting current context (context %p drawable %ld)!\n",
71             odev->ctx, ddpriv->drawable);
72     }
73 #endif
74 }
75
76 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
77 {
78   pc->dwSize = sizeof(*pc);
79   pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
80     D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
81   pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
82     D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST;
83   pc->dwZCmpCaps = 0xFFFFFFFF; /* All Z test can be done */
84   pc->dwSrcBlendCaps  = 0xFFFFFFFF; /* FIXME: need REAL values */
85   pc->dwDestBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
86   pc->dwAlphaCmpCaps  = 0xFFFFFFFF; /* FIXME: need REAL values */
87   pc->dwShadeCaps = 0xFFFFFFFF;     /* FIXME: need REAL values */
88   pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
89     D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
90   pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
91     D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
92   pc->dwTextureBlendCaps = 0xFFFFFFFF; /* FIXME: need REAL values */
93   pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP;
94   pc->dwStippleWidth = 32;
95   pc->dwStippleHeight = 32;
96 }
97
98 static void fill_opengl_caps(D3DDEVICEDESC *d1, D3DDEVICEDESC *d2)
99 {
100   /* GLint maxlight; */
101
102   d1->dwSize  = sizeof(*d1);
103   d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
104     | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
105   d1->dcmColorModel = D3DCOLOR_RGB;
106   d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
107     D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
108       D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
109   d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
110   d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
111   d1->bClipping = TRUE;
112   d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
113   d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
114   d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
115   d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
116   fill_opengl_primcaps(&(d1->dpcLineCaps));
117   fill_opengl_primcaps(&(d1->dpcTriCaps));
118   d1->dwDeviceRenderBitDepth  = DDBD_16;
119   d1->dwDeviceZBufferBitDepth = DDBD_16;
120   d1->dwMaxBufferSize = 0;
121   d1->dwMaxVertexCount = 65536;
122   d1->dwMinTextureWidth  = 1;
123   d1->dwMinTextureHeight = 1;
124   d1->dwMaxTextureWidth  = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
125   d1->dwMaxTextureHeight = 256; /* This is for Mesa on top of Glide (in the future :-) ) */
126   d1->dwMinStippleWidth  = 1;
127   d1->dwMinStippleHeight = 1;
128   d1->dwMaxStippleWidth  = 32;
129   d1->dwMaxStippleHeight = 32;
130
131   d2->dwSize  = sizeof(*d2);
132   d2->dwFlags = 0;
133 }
134
135 static void fill_device_capabilities(IDirectDrawImpl* ddraw) {
136 #if COMPILABLE
137   x11_dd_private *private = (x11_dd_private *) ddraw->d->private;
138   const char *ext_string;
139   Mesa_DeviceCapabilities *devcap;
140
141   private->device_capabilities = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Mesa_DeviceCapabilities));
142   devcap = (Mesa_DeviceCapabilities *) private->device_capabilities;
143
144   ENTER_GL();
145   ext_string = glGetString(GL_EXTENSIONS);
146   /* Query for the ColorTable Extension */
147   if (strstr(ext_string, "GL_EXT_paletted_texture")) {
148     devcap->ptr_ColorTableEXT = (PFNGLCOLORTABLEEXTPROC) glXGetProcAddressARB("glColorTableEXT");
149     TRACE("Color table extension supported (function at %p)\n", devcap->ptr_ColorTableEXT);
150   } else {
151     TRACE("Color table extension not found.\n");
152   }
153   LEAVE_GL();
154 #endif
155 }
156
157 int d3d_OpenGL(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
158   D3DDEVICEDESC d1,d2;
159   TRACE(" Enumerating OpenGL D3D2 device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE2_OpenGL));
160   fill_opengl_caps(&d1, &d2);
161   return cb((void*)&IID_D3DDEVICE2_OpenGL,"WINE Direct3D2 using OpenGL","direct3d",&d1,&d2,context);
162 }
163
164 int
165 is_OpenGL(
166     REFCLSID rguid, IDirectDrawSurfaceImpl* surface,
167     IDirect3DDevice2Impl** device, IDirect3D2Impl* d3d
168 ) {
169   mesa_d3dd_private *odev = NULL;
170
171   if (/* Default device */
172       (rguid == NULL) ||
173       /* HAL Device */
174       (!memcmp(&IID_IDirect3DHALDevice,rguid,sizeof(IID_IDirect3DHALDevice))) ||
175       /* OpenGL Device */
176       (!memcmp(&IID_D3DDEVICE2_OpenGL,rguid,sizeof(IID_D3DDEVICE2_OpenGL)))) {
177
178     *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDevice2Impl));
179     (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
180     odev = (mesa_d3dd_private*)(*device)->private;
181     (*device)->ref = 1;
182     ICOM_VTBL(*device) = &OpenGL_vtable;
183     (*device)->d3d = d3d;
184     (*device)->surface = surface;
185     (*device)->viewport_list = NULL;
186     (*device)->current_viewport = NULL;
187     (*device)->set_context = set_context;
188
189     TRACE("Creating OpenGL device for surface %p\n", surface);
190     /* Create the OpenGL context */
191 #if COMPILABLE
192     /* First get the correct visual */
193     ENTER_GL();
194     /* Create the context */
195     {
196       XVisualInfo *vis;
197       int num;
198       XVisualInfo template;
199
200       template.visualid = XVisualIDFromVisual(visual);
201       vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
202
203       odev->ctx = glXCreateContext(gdi_display, vis,
204                                    NULL, GL_TRUE);
205     }
206
207     if (odev->ctx == NULL)
208       ERR("Error in context creation !\n");
209     else
210       TRACE("Context created (%p)\n", odev->ctx);
211
212     /* Now override the surface's Flip method (if in double buffering) */
213     ((x11_ds_private *) surface->private)->opengl_flip = TRUE;
214     {
215         int i;
216         struct _surface_chain *chain = surface->s.chain;
217         for (i=0;i<chain->nrofsurfaces;i++)
218           if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
219               ((x11_ds_private *) chain->surfaces[i]->private)->opengl_flip = TRUE;
220     }
221 #endif
222
223     odev->rs.src = GL_ONE;
224     odev->rs.dst = GL_ZERO;
225     odev->rs.mag = GL_NEAREST;
226     odev->rs.min = GL_NEAREST;
227     odev->vt     = 0;
228
229     /* Allocate memory for the matrices */
230     odev->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
231     odev->view_mat  = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
232     odev->proj_mat  = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
233
234     memcpy(odev->world_mat, id_mat, 16 * sizeof(float));
235     memcpy(odev->view_mat , id_mat, 16 * sizeof(float));
236     memcpy(odev->proj_mat , id_mat, 16 * sizeof(float));
237
238     /* Initialisation */
239     TRACE("Setting current context\n");
240     (*device)->set_context(*device);
241     TRACE("Current context set\n");
242     glClearColor(0.0, 0.0, 0.0, 0.0);
243     glColor3f(1.0, 1.0, 1.0);
244     LEAVE_GL();
245
246     fill_device_capabilities(d3d->ddraw);
247
248     TRACE("OpenGL device created \n");
249     return 1;
250   }
251   FIXME("bad IID %s\n",debugstr_guid(rguid));
252   /* This is not the OpenGL UID */
253   return 0;
254 }
255
256 /*******************************************************************************
257  *                              MESA IDirect3DDevice2
258  */
259 static ULONG WINAPI MESA_IDirect3DDevice2Impl_Release(LPDIRECT3DDEVICE2 iface)
260 {
261   ICOM_THIS(IDirect3DDevice2Impl,iface);
262   FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
263
264   if (!--(This->ref)) {
265 #if 0  /* broken for now */
266     D3DDPRIVATE(This);
267     ENTER_GL();
268     glXDestroyContext(gdi_display, odev->ctx);
269     LEAVE_GL();
270 #endif
271     This->private = NULL;
272     HeapFree(GetProcessHeap(),0,This);
273     return 0;
274   }
275   return This->ref;
276 }
277
278 /*** IDirect3DDevice2 methods ***/
279 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_GetCaps(
280     LPDIRECT3DDEVICE2 iface, LPD3DDEVICEDESC lpdescsoft,
281     LPD3DDEVICEDESC lpdeschard
282 ) {
283   ICOM_THIS(IDirect3DDevice2Impl,iface);
284   FIXME("(%p)->(%p,%p): stub\n", This, lpdescsoft, lpdeschard);
285   fill_opengl_caps(lpdescsoft, lpdeschard);
286   return DD_OK;
287 }
288
289 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb,
290                                           LPVOID context) {
291   DDSURFACEDESC sdesc;
292   LPDDPIXELFORMAT pformat;
293
294   /* Do the texture enumeration */
295   sdesc.dwSize = sizeof(DDSURFACEDESC);
296   sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
297   sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
298   pformat = &(sdesc.ddpfPixelFormat);
299   pformat->dwSize = sizeof(DDPIXELFORMAT);
300   pformat->dwFourCC = 0;
301
302   TRACE("Enumerating GL_RGBA unpacked (32)\n");
303   pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
304   pformat->u1.dwRGBBitCount = 32;
305   pformat->u2.dwRBitMask =         0xFF000000;
306   pformat->u3.dwGBitMask =         0x00FF0000;
307   pformat->u4.dwBBitMask =        0x0000FF00;
308   pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
309   if (cb(&sdesc, context) == 0)
310     return DD_OK;
311
312   TRACE("Enumerating GL_RGB unpacked (24)\n");
313   pformat->dwFlags = DDPF_RGB;
314   pformat->u1.dwRGBBitCount = 24;
315   pformat->u2.dwRBitMask =  0x00FF0000;
316   pformat->u3.dwGBitMask =  0x0000FF00;
317   pformat->u4.dwBBitMask = 0x000000FF;
318   pformat->u5.dwRGBAlphaBitMask = 0x00000000;
319   if (cb(&sdesc, context) == 0)
320     return DD_OK;
321
322 #ifndef HAVE_BUGGY_MESAGL
323   /* The packed texture format are buggy in Mesa. The bug was reported and corrected,
324      so that future version will work great. */
325   TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
326   pformat->dwFlags = DDPF_RGB;
327   pformat->u1.dwRGBBitCount = 16;
328   pformat->u2.dwRBitMask =  0x0000F800;
329   pformat->u3.dwGBitMask =  0x000007E0;
330   pformat->u4.dwBBitMask = 0x0000001F;
331   pformat->u5.dwRGBAlphaBitMask = 0x00000000;
332   if (cb(&sdesc, context) == 0)
333     return DD_OK;
334
335   TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
336   pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
337   pformat->u1.dwRGBBitCount = 16;
338   pformat->u2.dwRBitMask =         0x0000F800;
339   pformat->u3.dwGBitMask =         0x000007C0;
340   pformat->u4.dwBBitMask =        0x0000003E;
341   pformat->u5.dwRGBAlphaBitMask = 0x00000001;
342   if (cb(&sdesc, context) == 0)
343     return DD_OK;
344
345   TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
346   pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
347   pformat->u1.dwRGBBitCount = 16;
348   pformat->u2.dwRBitMask =         0x0000F000;
349   pformat->u3.dwGBitMask =         0x00000F00;
350   pformat->u4.dwBBitMask =        0x000000F0;
351   pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
352   if (cb(&sdesc, context) == 0)
353     return DD_OK;
354
355   TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
356   pformat->dwFlags = DDPF_RGB;
357   pformat->u1.dwRGBBitCount = 8;
358   pformat->u2.dwRBitMask =         0x0000F800;
359   pformat->u3.dwGBitMask =         0x000007C0;
360   pformat->u4.dwBBitMask =        0x0000003E;
361   pformat->u5.dwRGBAlphaBitMask = 0x00000001;
362   if (cb(&sdesc, context) == 0)
363     return DD_OK;
364 #endif
365
366   TRACE("Enumerating GL_ARGB (no direct OpenGL equivalent - conversion needed)\n");
367   pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
368   pformat->u1.dwRGBBitCount = 16;
369   pformat->u2.dwRBitMask =         0x00007C00;
370   pformat->u3.dwGBitMask =         0x000003E0;
371   pformat->u4.dwBBitMask =         0x0000001F;
372   pformat->u5.dwRGBAlphaBitMask =  0x00008000;
373   if (cb(&sdesc, context) == 0)
374     return DD_OK;
375
376   TRACE("Enumerating Paletted (8)\n");
377   pformat->dwFlags = DDPF_PALETTEINDEXED8;
378   pformat->u1.dwRGBBitCount = 8;
379   pformat->u2.dwRBitMask =  0x00000000;
380   pformat->u3.dwGBitMask =  0x00000000;
381   pformat->u4.dwBBitMask = 0x00000000;
382   pformat->u5.dwRGBAlphaBitMask = 0x00000000;
383   if (cb(&sdesc, context) == 0)
384     return DD_OK;
385
386   TRACE("End of enumeration\n");
387
388   return DD_OK;
389 }
390
391 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_EnumTextureFormats(
392     LPDIRECT3DDEVICE2 iface, LPD3DENUMTEXTUREFORMATSCALLBACK cb, LPVOID context
393 ) {
394   ICOM_THIS(IDirect3DDevice2Impl,iface);
395   FIXME("(%p)->(%p,%p): stub\n", This, cb, context);
396
397   return enum_texture_format_OpenGL(cb, context);
398 }
399
400 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_BeginScene(
401     LPDIRECT3DDEVICE2 iface
402 ) {
403   ICOM_THIS(IDirect3DDevice2Impl,iface);
404
405   FIXME("(%p)->(): stub\n", This);
406
407   /* Here, we should get the DDraw surface and 'copy it' to the
408      OpenGL surface.... */
409
410   return DD_OK;
411 }
412
413 HRESULT WINAPI MESA_IDirect3DDevice2Impl_EndScene(LPDIRECT3DDEVICE2 iface) {
414   ICOM_THIS(IDirect3DDevice2Impl,iface);
415
416   FIXME("(%p)->(): stub\n", This);
417
418   /* No need to do anything here... */
419
420   return DD_OK;
421 }
422
423 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetRenderState(
424     LPDIRECT3DDEVICE2 iface, D3DRENDERSTATETYPE dwRenderStateType,
425     DWORD dwRenderState
426 ) {
427   ICOM_THIS(IDirect3DDevice2Impl,iface);
428   D3DDPRIVATE(This);
429
430   TRACE("(%p)->(%d,%ld)\n", This, dwRenderStateType, dwRenderState);
431
432   /* Call the render state functions */
433   set_render_state(dwRenderStateType, dwRenderState, &(odev->rs));
434
435   return DD_OK;
436 }
437
438 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetLightState(
439     LPDIRECT3DDEVICE2 iface, D3DLIGHTSTATETYPE dwLightStateType,
440     DWORD dwLightState
441 ) {
442   ICOM_THIS(IDirect3DDevice2Impl,iface);
443   FIXME("(%p)->(%d,%08lx): stub\n", This, dwLightStateType, dwLightState);
444
445   switch (dwLightStateType) {
446   case D3DLIGHTSTATE_MATERIAL: {  /* 1 */
447     IDirect3DMaterial2Impl* mat = (IDirect3DMaterial2Impl*) dwLightState;
448
449     if (mat != NULL) {
450       ENTER_GL();
451       mat->activate(mat);
452       LEAVE_GL();
453     } else {
454       TRACE("Zoups !!!\n");
455     }
456   } break;
457
458   case D3DLIGHTSTATE_AMBIENT: {   /* 2 */
459     float light[4];
460
461     light[0] = ((dwLightState >> 16) & 0xFF) / 255.0;
462     light[1] = ((dwLightState >>  8) & 0xFF) / 255.0;
463     light[2] = ((dwLightState >>  0) & 0xFF) / 255.0;
464     light[3] = 1.0;
465     ENTER_GL();
466     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (float *) light);
467     LEAVE_GL();
468   } break;
469
470 #define UNSUP(x) case D3DLIGHTSTATE_##x: FIXME("unsupported D3DLIGHTSTATE_" #x "!\n");break;
471   UNSUP(COLORMODEL);
472   UNSUP(FOGMODE);
473   UNSUP(FOGSTART);
474   UNSUP(FOGEND);
475   UNSUP(FOGDENSITY);
476 #undef UNSUP
477   default:
478     TRACE("Unexpected Light State Type\n");
479     return DDERR_INVALIDPARAMS;
480   }
481
482   return DD_OK;
483 }
484
485 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_SetTransform(
486     LPDIRECT3DDEVICE2 iface, D3DTRANSFORMSTATETYPE d3dts,
487     LPD3DMATRIX lpmatrix
488 ) {
489   ICOM_THIS(IDirect3DDevice2Impl,iface);
490   D3DDPRIVATE(This);
491
492   FIXME("(%p)->(%d,%p): stub\n", This, d3dts, lpmatrix);
493
494   ENTER_GL();
495
496   /* Using a trial and failure approach, I found that the order of
497      Direct3D transformations that works best is :
498
499      ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
500
501      As OpenGL uses only two matrices, I combined PROJECTION and VIEW into
502      OpenGL's GL_PROJECTION matrix and the WORLD into GL_MODELVIEW.
503
504      If anyone has a good explanation of the three different matrices in
505      the SDK online documentation, feel free to point it to me. For example,
506      which matrices transform lights ? In OpenGL only the PROJECTION matrix
507      transform the lights, not the MODELVIEW. Using the matrix names, I
508      supposed that PROJECTION and VIEW (all 'camera' related names) do
509      transform lights, but WORLD do not. It may be wrong though... */
510
511   /* After reading through both OpenGL and Direct3D documentations, I
512      thought that D3D matrices were written in 'line major mode' transposed
513      from OpenGL's 'column major mode'. But I found out that a simple memcpy
514      works fine to transfer one matrix format to the other (it did not work
515      when transposing)....
516
517      So :
518       1) are the documentations wrong
519       2) does the matrix work even if they are not read correctly
520       3) is Mesa's implementation of OpenGL not compliant regarding Matrix
521          loading using glLoadMatrix ?
522
523      Anyway, I always use 'conv_mat' to transfer the matrices from one format
524      to the other so that if I ever find out that I need to transpose them, I
525      will able to do it quickly, only by changing the macro conv_mat. */
526
527   switch (d3dts) {
528   case D3DTRANSFORMSTATE_WORLD: {
529     conv_mat(lpmatrix, odev->world_mat);
530     glMatrixMode(GL_MODELVIEW);
531     glLoadMatrixf((float *) odev->world_mat);
532   } break;
533
534   case D3DTRANSFORMSTATE_VIEW: {
535     conv_mat(lpmatrix, odev->view_mat);
536     glMatrixMode(GL_PROJECTION);
537     glLoadMatrixf((float *) odev->proj_mat);
538     glMultMatrixf((float *) odev->view_mat);
539   } break;
540
541   case D3DTRANSFORMSTATE_PROJECTION: {
542     conv_mat(lpmatrix, odev->proj_mat);
543     glMatrixMode(GL_PROJECTION);
544     glLoadMatrixf((float *) odev->proj_mat);
545     glMultMatrixf((float *) odev->view_mat);
546   } break;
547
548   default:
549     break;
550   }
551   LEAVE_GL();
552   return DD_OK;
553 }
554
555 #define DRAW_PRIMITIVE(MAXVERT,INDEX)                                   \
556   /* Puts GL in the correct lighting mode */                            \
557   if (odev->vt != d3dv) {                                               \
558     if (odev->vt == D3DVT_TLVERTEX) {                                   \
559       /* Need to put the correct transformation again */                \
560       glMatrixMode(GL_MODELVIEW);                                       \
561       glLoadMatrixf((float *) odev->world_mat);                      \
562       glMatrixMode(GL_PROJECTION);                                      \
563       glLoadMatrixf((float *) odev->proj_mat);                  \
564       glMultMatrixf((float *) odev->view_mat);                  \
565     }                                                                   \
566                                                                         \
567     switch (d3dv) {                                                     \
568     case D3DVT_VERTEX:                                                  \
569       TRACE("Standard Vertex\n");                                       \
570       glEnable(GL_LIGHTING);                                            \
571       break;                                                            \
572                                                                         \
573     case D3DVT_LVERTEX:                                                 \
574       TRACE("Lighted Vertex\n");                                        \
575       glDisable(GL_LIGHTING);                                           \
576       break;                                                            \
577                                                                         \
578     case D3DVT_TLVERTEX: {                                              \
579       GLdouble height, width, minZ, maxZ;                               \
580                                                                         \
581       TRACE("Transformed - Lighted Vertex\n");                          \
582       /* First, disable lighting */                                     \
583       glDisable(GL_LIGHTING);                                           \
584                                                                         \
585       /* Then do not put any transformation matrixes */                 \
586       glMatrixMode(GL_MODELVIEW);                                       \
587       glLoadIdentity();                                                 \
588       glMatrixMode(GL_PROJECTION);                                      \
589       glLoadIdentity();                                                 \
590                                                                         \
591       if (This->current_viewport == NULL) {                             \
592         ERR("No current viewport !\n");                                 \
593         /* Using standard values */                                     \
594         height = 640.0;                                                 \
595         width = 480.0;                                                  \
596         minZ = -10.0;                                                   \
597         maxZ = 10.0;                                                    \
598       } else {                                                          \
599         if (This->current_viewport->use_vp2) {                          \
600           height = (GLdouble) This->current_viewport->viewport.vp2.dwHeight;\
601           width  = (GLdouble) This->current_viewport->viewport.vp2.dwWidth;\
602           minZ   = (GLdouble) This->current_viewport->viewport.vp2.dvMinZ;\
603           maxZ   = (GLdouble) This->current_viewport->viewport.vp2.dvMaxZ;\
604         } else {                                                        \
605           height = (GLdouble) This->current_viewport->viewport.vp1.dwHeight;\
606           width  = (GLdouble) This->current_viewport->viewport.vp1.dwWidth;\
607           minZ   = (GLdouble) This->current_viewport->viewport.vp1.dvMinZ;\
608           maxZ   = (GLdouble) This->current_viewport->viewport.vp1.dvMaxZ;\
609         }                                                               \
610       }                                                                 \
611                                                                         \
612       glOrtho(0.0, width, height, 0.0, -minZ, -maxZ);                   \
613     } break;                                                            \
614                                                                         \
615     default:                                                            \
616       ERR("Unhandled vertex type\n");                                   \
617       break;                                                            \
618     }                                                                   \
619                                                                         \
620     odev->vt = d3dv;                                                    \
621   }                                                                     \
622                                                                         \
623   switch (d3dp) {                                                       \
624   case D3DPT_POINTLIST:                                                 \
625     TRACE("Start POINTS\n");                                            \
626     glBegin(GL_POINTS);                                                 \
627     break;                                                              \
628                                                                         \
629   case D3DPT_LINELIST:                                                  \
630     TRACE("Start LINES\n");                                             \
631     glBegin(GL_LINES);                                                  \
632     break;                                                              \
633                                                                         \
634   case D3DPT_LINESTRIP:                                                 \
635     TRACE("Start LINE_STRIP\n");                                        \
636     glBegin(GL_LINE_STRIP);                                             \
637     break;                                                              \
638                                                                         \
639   case D3DPT_TRIANGLELIST:                                              \
640     TRACE("Start TRIANGLES\n");                                         \
641     glBegin(GL_TRIANGLES);                                              \
642     break;                                                              \
643                                                                         \
644   case D3DPT_TRIANGLESTRIP:                                             \
645     TRACE("Start TRIANGLE_STRIP\n");                                    \
646     glBegin(GL_TRIANGLE_STRIP);                                         \
647     break;                                                              \
648                                                                         \
649   case D3DPT_TRIANGLEFAN:                                               \
650     TRACE("Start TRIANGLE_FAN\n");                                      \
651     glBegin(GL_TRIANGLE_FAN);                                           \
652     break;                                                              \
653                                                                         \
654   default:                                                              \
655     TRACE("Unhandled primitive\n");                                     \
656     break;                                                              \
657   }                                                                     \
658                                                                         \
659   /* Draw the primitives */                                             \
660   for (vx_index = 0; vx_index < MAXVERT; vx_index++) {                  \
661     switch (d3dv) {                                                     \
662     case D3DVT_VERTEX: {                                                \
663       D3DVERTEX *vx = ((D3DVERTEX *) lpvertex) + INDEX;                 \
664                                                                         \
665       glNormal3f(vx->u4.nx, vx->u5.ny, vx->u6.nz);                      \
666       glVertex3f(vx->u1.x, vx->u2.y, vx->u3.z);                         \
667       TRACE("   V: %f %f %f\n", vx->u1.x, vx->u2.y, vx->u3.z);          \
668     } break;                                                            \
669                                                                         \
670     case D3DVT_LVERTEX: {                                               \
671       D3DLVERTEX *vx = ((D3DLVERTEX *) lpvertex) + INDEX;               \
672       DWORD col = vx->u4.color;                                         \
673                                                                         \
674       glColor3f(((col >> 16) & 0xFF) / 255.0,                           \
675                 ((col >>  8) & 0xFF) / 255.0,                           \
676                 ((col >>  0) & 0xFF) / 255.0);                          \
677       glVertex3f(vx->u1.x, vx->u2.y, vx->u3.z);                         \
678       TRACE("  LV: %f %f %f (%02lx %02lx %02lx)\n",                     \
679             vx->u1.x, vx->u2.y, vx->u3.z,                               \
680             ((col >> 16) & 0xFF), ((col >>  8) & 0xFF), ((col >>  0) & 0xFF));\
681     } break;                                                            \
682                                                                         \
683     case D3DVT_TLVERTEX: {                                              \
684       D3DTLVERTEX *vx = ((D3DTLVERTEX *) lpvertex) + INDEX;             \
685       DWORD col = vx->u5.color;                                         \
686                                                                         \
687       glColor3f(((col >> 16) & 0xFF) / 255.0,                           \
688                 ((col >>  8) & 0xFF) / 255.0,                           \
689                 ((col >>  0) & 0xFF) / 255.0);                          \
690       glTexCoord2f(vx->u7.tu, vx->u8.tv);                               \
691       if (vx->u4.rhw < 0.01)                                            \
692         glVertex3f(vx->u1.sx,                                           \
693                    vx->u2.sy,                                           \
694                    vx->u3.sz);                                          \
695       else                                                              \
696         glVertex4f(vx->u1.sx / vx->u4.rhw,                              \
697                    vx->u2.sy / vx->u4.rhw,                              \
698                    vx->u3.sz / vx->u4.rhw,                              \
699                    1.0 / vx->u4.rhw);                                   \
700       TRACE(" TLV: %f %f %f (%02lx %02lx %02lx) (%f %f) (%f)\n",        \
701             vx->u1.sx, vx->u2.sy, vx->u3.sz,                            \
702             ((col >> 16) & 0xFF), ((col >>  8) & 0xFF), ((col >>  0) & 0xFF),\
703             vx->u7.tu, vx->u8.tv, vx->u4.rhw);                          \
704     } break;                                                            \
705                                                                         \
706     default:                                                            \
707       FIXME("Unhandled vertex type\n");                                 \
708       break;                                                            \
709     }                                                                   \
710   }                                                                     \
711                                                                         \
712   glEnd();                                                              \
713   TRACE("End\n");
714
715
716 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawPrimitive(
717     LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
718     LPVOID lpvertex, DWORD vertcount, DWORD dwFlags
719 ) {
720   ICOM_THIS(IDirect3DDevice2Impl,iface);
721   D3DDPRIVATE(This);
722   int vx_index;
723
724   TRACE("(%p)->(%d,%d,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, dwFlags);
725
726   ENTER_GL();
727   DRAW_PRIMITIVE(vertcount, vx_index);
728   LEAVE_GL();
729
730   return D3D_OK;
731 }
732
733 static HRESULT WINAPI MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive(
734     LPDIRECT3DDEVICE2 iface, D3DPRIMITIVETYPE d3dp, D3DVERTEXTYPE d3dv,
735     LPVOID lpvertex, DWORD vertcount, LPWORD lpindexes, DWORD indexcount,
736     DWORD dwFlags
737 ) {
738   ICOM_THIS(IDirect3DDevice2Impl,iface);
739   D3DDPRIVATE(This);
740   int vx_index;
741
742   TRACE("(%p)->(%d,%d,%p,%ld,%p,%ld,%08lx): stub\n", This, d3dp, d3dv, lpvertex, vertcount, lpindexes, indexcount, dwFlags);
743
744   ENTER_GL();
745   DRAW_PRIMITIVE(indexcount, lpindexes[vx_index]);
746   LEAVE_GL();
747
748   return D3D_OK;
749 }
750
751 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_CreateExecuteBuffer(
752     LPDIRECT3DDEVICE iface, LPD3DEXECUTEBUFFERDESC lpDesc,
753     LPDIRECT3DEXECUTEBUFFER *lplpDirect3DExecuteBuffer, IUnknown *pUnkOuter
754 ) {
755     ICOM_THIS(IDirect3DDeviceImpl,iface);
756     TRACE("(%p)->(%p,%p,%p)\n", This, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
757     *lplpDirect3DExecuteBuffer = d3dexecutebuffer_create(This, lpDesc);
758     return DD_OK;
759 }
760
761
762 /*******************************************************************************
763  *                              OpenGL-specific IDirect3DDevice2
764  */
765
766 /*******************************************************************************
767  *                              OpenGL-specific VTable
768  */
769
770 ICOM_VTABLE(IDirect3DDevice2) OpenGL_vtable =
771 {
772   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
773   IDirect3DDevice2Impl_QueryInterface,
774   IDirect3DDevice2Impl_AddRef,
775   MESA_IDirect3DDevice2Impl_Release,
776   /*** IDirect3DDevice2 methods ***/
777   MESA_IDirect3DDevice2Impl_GetCaps,
778   IDirect3DDevice2Impl_SwapTextureHandles,
779   IDirect3DDevice2Impl_GetStats,
780   IDirect3DDevice2Impl_AddViewport,
781   IDirect3DDevice2Impl_DeleteViewport,
782   IDirect3DDevice2Impl_NextViewport,
783   MESA_IDirect3DDevice2Impl_EnumTextureFormats,
784   MESA_IDirect3DDevice2Impl_BeginScene,
785   MESA_IDirect3DDevice2Impl_EndScene,
786   IDirect3DDevice2Impl_GetDirect3D,
787
788   /*** DrawPrimitive API ***/
789   IDirect3DDevice2Impl_SetCurrentViewport,
790   IDirect3DDevice2Impl_GetCurrentViewport,
791
792   IDirect3DDevice2Impl_SetRenderTarget,
793   IDirect3DDevice2Impl_GetRenderTarget,
794
795   IDirect3DDevice2Impl_Begin,
796   IDirect3DDevice2Impl_BeginIndexed,
797   IDirect3DDevice2Impl_Vertex,
798   IDirect3DDevice2Impl_Index,
799   IDirect3DDevice2Impl_End,
800
801   IDirect3DDevice2Impl_GetRenderState,
802   MESA_IDirect3DDevice2Impl_SetRenderState,
803   IDirect3DDevice2Impl_GetLightState,
804   MESA_IDirect3DDevice2Impl_SetLightState,
805   MESA_IDirect3DDevice2Impl_SetTransform,
806   IDirect3DDevice2Impl_GetTransform,
807   IDirect3DDevice2Impl_MultiplyTransform,
808
809   MESA_IDirect3DDevice2Impl_DrawPrimitive,
810   MESA_IDirect3DDevice2Impl_DrawIndexedPrimitive,
811
812   IDirect3DDevice2Impl_SetClipStatus,
813   IDirect3DDevice2Impl_GetClipStatus,
814 };
815
816 /*******************************************************************************
817  *                              Direct3DDevice
818  */
819 int d3d_OpenGL_dx3(LPD3DENUMDEVICESCALLBACK cb, LPVOID context) {
820   D3DDEVICEDESC d1,d2;
821
822   TRACE(" Enumerating OpenGL D3D device (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
823
824   fill_opengl_caps(&d1, &d2);
825
826   return cb((void*)&IID_D3DDEVICE_OpenGL,"WINE Direct3D using OpenGL","direct3d",&d1,&d2,context);
827 }
828
829 int is_OpenGL_dx3(REFCLSID rguid, IDirectDrawSurfaceImpl* surface, IDirect3DDeviceImpl** device)
830 {
831   if (!memcmp(&IID_D3DDEVICE_OpenGL,rguid,sizeof(IID_D3DDEVICE_OpenGL))) {
832     mesa_d3dd_private *odev;
833 #if 0 /* See below */
834     int attributeList[]={ GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None };
835     XVisualInfo *xvis;
836 #endif
837
838     *device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirect3DDeviceImpl));
839     (*device)->private = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(mesa_d3dd_private));
840     odev = (mesa_d3dd_private*)(*device)->private;
841     (*device)->ref = 1;
842     ICOM_VTBL(*device) = &OpenGL_vtable_dx3;
843     (*device)->d3d = NULL;
844     (*device)->surface = surface;
845
846     (*device)->viewport_list = NULL;
847     (*device)->current_viewport = NULL;
848
849     (*device)->set_context = (void*)set_context;
850
851     TRACE("OpenGL device created \n");
852
853     /* Create the OpenGL context */
854     /* First get the correct visual */
855     /* if (surface->s.backbuffer == NULL)
856        attributeList[3] = None; */
857 #if 0 /* non working currently */
858     ENTER_GL();
859     xvis = glXChooseVisual(gdi_display,
860                            DefaultScreen(gdi_display),
861                            attributeList);
862     if (xvis == NULL)
863       ERR("No visual found !\n");
864     else
865       TRACE("Visual found\n");
866     /* Create the context */
867     odev->ctx = glXCreateContext(gdi_display,
868                                  xvis,
869                                  NULL,
870                                  GL_TRUE);
871     TRACE("Context created\n");
872
873     /* Now override the surface's Flip method (if in double buffering) */
874     surface->s.d3d_device = (void *) odev;
875     {
876         int i;
877         struct _surface_chain *chain = surface->s.chain;
878         for (i=0;i<chain->nrofsurfaces;i++)
879           if (chain->surfaces[i]->s.surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)
880               chain->surfaces[i]->s.d3d_device = (void *) odev;
881     }
882 #endif
883     odev->rs.src = GL_ONE;
884     odev->rs.dst = GL_ZERO;
885     odev->rs.mag = GL_NEAREST;
886     odev->rs.min = GL_NEAREST;
887
888     odev->world_mat = (LPD3DMATRIX) &id_mat;
889     odev->view_mat  = (LPD3DMATRIX) &id_mat;
890     odev->proj_mat  = (LPD3DMATRIX) &id_mat;
891
892     /* Initialisation */
893     (*device)->set_context(*device);
894     glClearColor(0.0, 0.0, 0.0, 0.0);
895     glColor3f(1.0, 1.0, 1.0);
896
897     fill_device_capabilities((IDirectDrawImpl *) surface->ddraw_owner);
898
899     return 1;
900   }
901
902   /* This is not the OpenGL UID */
903   return DD_OK;
904 }
905
906 static ULONG WINAPI MESA_IDirect3DDeviceImpl_Release(LPDIRECT3DDEVICE iface)
907 {
908   ICOM_THIS(IDirect3DDeviceImpl,iface);
909   FIXME("(%p)->() decrementing from %lu.\n", This, This->ref );
910
911   if (!--(This->ref)) {
912 #if 0  /* broken for now */
913     D3DDPRIVATE(This);
914     ENTER_GL();
915     glXDestroyContext(gdi_display, odev->ctx);
916     LEAVE_GL();
917 #endif
918     This->private = NULL;
919     HeapFree(GetProcessHeap(),0,This);
920     return 0;
921   }
922   return This->ref;
923 }
924
925 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EnumTextureFormats(
926     LPDIRECT3DDEVICE iface,LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc,
927     LPVOID lpArg)
928 {
929   ICOM_THIS(IDirect3DDeviceImpl,iface);
930   TRACE("(%p)->(%p,%p): stub\n", This, lpd3dEnumTextureProc, lpArg);
931
932   return enum_texture_format_OpenGL(lpd3dEnumTextureProc, lpArg);
933 }
934
935
936 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_BeginScene(LPDIRECT3DDEVICE iface)
937 {
938   ICOM_THIS(IDirect3DDeviceImpl,iface);
939   /* OpenGL_IDirect3DDevice *odev = (OpenGL_IDirect3DDevice *) This; */
940
941   FIXME("(%p)->(): stub\n", This);
942
943   /* We get the pointer to the surface (should be done on flip) */
944   /* odev->zb->pbuf = This->surface->s.surface_desc.u2.lpSurface; */
945
946   return DD_OK;
947 }
948
949
950 /* This is for the moment copy-pasted from IDirect3DDevice2...
951    Will make a common function ... */
952 static HRESULT WINAPI MESA_IDirect3DDeviceImpl_EndScene(LPDIRECT3DDEVICE iface)
953 {
954   ICOM_THIS(IDirect3DDeviceImpl,iface);
955
956   FIXME("(%p)->(): stub\n", This);
957
958   /* No need to do anything here... */
959
960   return DD_OK;
961 }
962
963 /*******************************************************************************
964  *                              Direct3DDevice VTable
965  */
966 ICOM_VTABLE(IDirect3DDevice) OpenGL_vtable_dx3 =
967 {
968   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
969   IDirect3DDeviceImpl_QueryInterface,
970   IDirect3DDeviceImpl_AddRef,
971   MESA_IDirect3DDeviceImpl_Release,
972   IDirect3DDeviceImpl_Initialize,
973   IDirect3DDeviceImpl_GetCaps,
974   IDirect3DDeviceImpl_SwapTextureHandles,
975   MESA_IDirect3DDeviceImpl_CreateExecuteBuffer,
976   IDirect3DDeviceImpl_GetStats,
977   IDirect3DDeviceImpl_Execute,
978   IDirect3DDeviceImpl_AddViewport,
979   IDirect3DDeviceImpl_DeleteViewport,
980   IDirect3DDeviceImpl_NextViewport,
981   IDirect3DDeviceImpl_Pick,
982   IDirect3DDeviceImpl_GetPickRecords,
983   MESA_IDirect3DDeviceImpl_EnumTextureFormats,
984   IDirect3DDeviceImpl_CreateMatrix,
985   IDirect3DDeviceImpl_SetMatrix,
986   IDirect3DDeviceImpl_GetMatrix,
987   IDirect3DDeviceImpl_DeleteMatrix,
988   MESA_IDirect3DDeviceImpl_BeginScene,
989   MESA_IDirect3DDeviceImpl_EndScene,
990   IDirect3DDeviceImpl_GetDirect3D,
991 };