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