- proper (tested on Win2K) reference counting for Direct3D object
[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 #include <math.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winerror.h"
31 #include "objbase.h"
32 #include "ddraw.h"
33 #include "d3d.h"
34 #include "wine/debug.h"
35
36 #include "mesa_private.h"
37 #include "main.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
41
42 /* x11drv GDI escapes */
43 #define X11DRV_ESCAPE 6789
44 enum x11drv_escape_codes
45 {
46     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
47     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
48     X11DRV_GET_FONT,      /* get current X font for a DC */
49 };
50
51 /* They are non-static as they are used by Direct3D in the creation function */
52 const GUID IID_D3DDEVICE_OpenGL = {
53   0x31416d44,
54   0x86ae,
55   0x11d2,
56   { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
57 };
58
59 #ifndef HAVE_GLEXT_PROTOTYPES
60 /* This is for non-OpenGL ABI compliant glext.h headers :-) */
61 typedef void (* PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat,
62                                          GLsizei width, GLenum format, GLenum type,
63                                          const GLvoid *table);
64 #endif
65
66 const float id_mat[16] = {
67     1.0, 0.0, 0.0, 0.0,
68     0.0, 1.0, 0.0, 0.0,
69     0.0, 0.0, 1.0, 0.0,
70     0.0, 0.0, 0.0, 1.0
71 };
72
73 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
74                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
75                                    DWORD d3dvtVertexType,
76                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
77                                    DWORD dwVertexCount,
78                                    LPWORD dwIndices,
79                                    DWORD dwIndexCount,
80                                    DWORD dwFlags) ;
81
82 /* retrieve the X display to use on a given DC */
83 inline static Display *get_display( HDC hdc )
84 {
85     Display *display;
86     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
87
88     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
89                     sizeof(display), (LPSTR)&display )) display = NULL;
90
91     return display;
92 }
93
94
95 /* retrieve the X drawable to use on a given DC */
96 inline static Drawable get_drawable( HDC hdc )
97 {
98     Drawable drawable;
99     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
100
101     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
102                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
103
104     return drawable;
105 }
106
107
108 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
109 {
110     IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
111     IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
112
113     TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
114     ENTER_GL();
115     if (gl_d3d_dev->state == SURFACE_MEMORY_DIRTY) {
116         d3d_dev->flush_to_framebuffer(d3d_dev, NULL, gl_d3d_dev->lock_surf);
117     }
118     gl_d3d_dev->state = SURFACE_GL;
119     gl_d3d_dev->front_state = SURFACE_GL;
120     glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
121     LEAVE_GL();
122     
123     return TRUE;
124 }
125
126
127 /*******************************************************************************
128  *                              OpenGL static functions
129  */
130 static void set_context(IDirect3DDeviceImpl* This)
131 {
132     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
133    
134     ENTER_GL();
135     TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
136     if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
137         ERR("Error in setting current context (context %p drawable %ld)!\n",
138             glThis->gl_context, glThis->drawable);
139     }
140     LEAVE_GL();
141 }
142
143 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
144 {
145     pc->dwSize = sizeof(*pc);
146     pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
147       D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKZ;
148     pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
149       D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL;
150     pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
151       D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
152     pc->dwSrcBlendCaps  = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
153       D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
154         D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
155     pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
156       D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
157         D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
158     pc->dwAlphaCmpCaps  = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
159       D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
160     pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
161       D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
162     pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
163       D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
164     pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
165       D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST;
166     pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
167       D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
168     pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
169     pc->dwStippleWidth = 32;
170     pc->dwStippleHeight = 32;
171 }
172
173 static void fill_opengl_caps(D3DDEVICEDESC *d1)
174 {
175     /* GLint maxlight; */
176
177     d1->dwSize  = sizeof(*d1);
178     d1->dwFlags = D3DDD_DEVCAPS | D3DDD_BCLIPPING | D3DDD_COLORMODEL | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH
179       | D3DDD_LIGHTINGCAPS | D3DDD_LINECAPS | D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT | D3DDD_TRANSFORMCAPS | D3DDD_TRICAPS;
180     d1->dcmColorModel = D3DCOLOR_RGB;
181     d1->dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
182       D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
183       D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
184       /* D3D 7 capabilities */
185       D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_HWRASTERIZATION;
186     d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
187     d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
188     d1->bClipping = TRUE;
189     d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
190     d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
191     d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
192     d1->dlcLightingCaps.dwNumLights = 16; /* glGetIntegerv(GL_MAX_LIGHTS, &maxlight); d1->dlcLightingCaps.dwNumLights = maxlight; */
193     fill_opengl_primcaps(&(d1->dpcLineCaps));
194     fill_opengl_primcaps(&(d1->dpcTriCaps));
195     d1->dwDeviceRenderBitDepth  = DDBD_16|DDBD_24|DDBD_32;
196     d1->dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32;
197     d1->dwMaxBufferSize = 0;
198     d1->dwMaxVertexCount = 65536;
199     d1->dwMinTextureWidth  = 1;
200     d1->dwMinTextureHeight = 1;
201     d1->dwMaxTextureWidth  = 1024;
202     d1->dwMaxTextureHeight = 1024;
203     d1->dwMinStippleWidth  = 1;
204     d1->dwMinStippleHeight = 1;
205     d1->dwMaxStippleWidth  = 32;
206     d1->dwMaxStippleHeight = 32;
207     d1->dwMaxTextureRepeat = 16;
208     d1->dwMaxTextureAspectRatio = 1024;
209     d1->dwMaxAnisotropy = 0;
210     d1->dvGuardBandLeft = 0.0;
211     d1->dvGuardBandRight = 0.0;
212     d1->dvGuardBandTop = 0.0;
213     d1->dvGuardBandBottom = 0.0;
214     d1->dvExtentsAdjust = 0.0;
215     d1->dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
216       D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
217     d1->dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
218     d1->dwTextureOpCaps = 0; /* TODO add proper caps according to OpenGL multi-texture stuff */
219     d1->wMaxTextureBlendStages = 1;  /* TODO add proper caps according to OpenGL multi-texture stuff */
220     d1->wMaxSimultaneousTextures = 1;  /* TODO add proper caps according to OpenGL multi-texture stuff */
221 }
222
223 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
224 {
225     D3DDEVICEDESC d1;
226
227     /* Copy first D3D1/2/3 capabilities */
228     fill_opengl_caps(&d1);
229
230     /* And fill the D3D7 one with it */
231     d->dwDevCaps = d1.dwDevCaps;
232     d->dpcLineCaps = d1.dpcLineCaps;
233     d->dpcTriCaps = d1.dpcTriCaps;
234     d->dwDeviceRenderBitDepth = d1.dwDeviceRenderBitDepth;
235     d->dwDeviceZBufferBitDepth = d1.dwDeviceZBufferBitDepth;
236     d->dwMinTextureWidth = d1.dwMinTextureWidth;
237     d->dwMinTextureHeight = d1.dwMinTextureHeight;
238     d->dwMaxTextureWidth = d1.dwMaxTextureWidth;
239     d->dwMaxTextureHeight = d1.dwMaxTextureHeight;
240     d->dwMaxTextureRepeat = d1.dwMaxTextureRepeat;
241     d->dwMaxTextureAspectRatio = d1.dwMaxTextureAspectRatio;
242     d->dwMaxAnisotropy = d1.dwMaxAnisotropy;
243     d->dvGuardBandLeft = d1.dvGuardBandLeft;
244     d->dvGuardBandTop = d1.dvGuardBandTop;
245     d->dvGuardBandRight = d1.dvGuardBandRight;
246     d->dvGuardBandBottom = d1.dvGuardBandBottom;
247     d->dvExtentsAdjust = d1.dvExtentsAdjust;
248     d->dwStencilCaps = d1.dwStencilCaps;
249     d->dwFVFCaps = d1.dwFVFCaps;
250     d->dwTextureOpCaps = d1.dwTextureOpCaps;
251     d->wMaxTextureBlendStages = d1.wMaxTextureBlendStages;
252     d->wMaxSimultaneousTextures = d1.wMaxSimultaneousTextures;
253     d->dwMaxActiveLights = d1.dlcLightingCaps.dwNumLights;
254     d->dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
255     d->deviceGUID = IID_IDirect3DTnLHalDevice;
256     d->wMaxUserClipPlanes = 1;
257     d->wMaxVertexBlendMatrices = 0;
258     d->dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG | D3DVTXPCAPS_DIRECTIONALLIGHTS |
259       D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
260     d->dwReserved1 = 0;
261     d->dwReserved2 = 0;
262     d->dwReserved3 = 0;
263     d->dwReserved4 = 0;
264 }
265
266 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
267 {
268     D3DDEVICEDESC dref, d1, d2;
269     HRESULT ret_value;
270
271     /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
272        Let's put the string in a sufficiently sized array in writable memory. */
273     char device_name[50];
274     strcpy(device_name,"direct3d");
275
276     fill_opengl_caps(&dref);
277
278     if (version > 1) {
279         /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
280         TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
281         d1 = dref;
282         d2 = dref;
283         ret_value = cb((LPIID) &IID_IDirect3DRefDevice, "WINE Reference Direct3DX using OpenGL", device_name, &d1, &d2, context);
284         if (ret_value != D3DENUMRET_OK)
285             return ret_value;
286     }
287     
288     TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
289     d1 = dref;
290     d2 = dref;
291     ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, "WINE Direct3DX using OpenGL", device_name, &d1, &d2, context);
292     if (ret_value != D3DENUMRET_OK)
293         return ret_value;
294
295     return D3DENUMRET_OK;
296 }
297
298 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
299 {
300     D3DDEVICEDESC7 ddesc;
301
302     fill_opengl_caps_7(&ddesc);
303     
304     TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
305     
306     return cb("WINE Direct3D7 using OpenGL", "Wine D3D7 device", &ddesc, context);
307 }
308
309 ULONG WINAPI
310 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
311 {
312     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
313     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
314     
315     TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, This->ref);
316     if (!--(This->ref)) {
317         int i;
318         IDirectDrawSurfaceImpl *surface = This->surface, *surf;
319         
320         /* Release texture associated with the device */ 
321         for (i = 0; i < MAX_TEXTURES; i++) {
322             if (This->current_texture[i] != NULL)
323                 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
324             HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
325         }
326
327         /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
328         for (surf = surface; surf != NULL; surf = surf->surface_owner) {
329             if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
330                 surf->aux_ctx  = NULL;
331                 surf->aux_data = NULL;
332                 surf->aux_flip = NULL;
333                 break;
334             }
335         }
336         for (surf = surface; surf != NULL; surf = surf->surface_owner) {
337             IDirectDrawSurfaceImpl *surf2;
338             for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
339             for (; surf2 != NULL; surf2 = surf2->next_attached) {
340                 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
341                     ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
342                     /* Override the Lock / Unlock function for all these surfaces */
343                     surf2->lock_update = surf2->lock_update_prev;
344                     surf2->unlock_update = surf2->unlock_update_prev;
345                     /* And install also the blt / bltfast overrides */
346                     surf2->aux_blt = NULL;
347                     surf2->aux_bltfast = NULL;
348                 }
349                 surf2->d3ddevice = NULL;
350             }
351         }
352         
353         /* And warn the D3D object that this device is no longer active... */
354         This->d3d->d3d_removed_device(This->d3d, This);
355
356         HeapFree(GetProcessHeap(), 0, This->world_mat);
357         HeapFree(GetProcessHeap(), 0, This->view_mat);
358         HeapFree(GetProcessHeap(), 0, This->proj_mat);
359
360         if (glThis->surface_ptr)
361             HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
362
363         DeleteCriticalSection(&(This->crit));
364         
365         ENTER_GL();
366         if (glThis->unlock_tex)
367             glDeleteTextures(1, &(glThis->unlock_tex));
368         glXDestroyContext(glThis->display, glThis->gl_context);
369         LEAVE_GL();
370         HeapFree(GetProcessHeap(), 0, This->clipping_planes);
371
372         HeapFree(GetProcessHeap(), 0, This);
373         return 0;
374     }
375     return This->ref;
376 }
377
378 HRESULT WINAPI
379 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
380                                        LPD3DDEVICEDESC lpD3DHWDevDesc,
381                                        LPD3DDEVICEDESC lpD3DHELDevDesc)
382 {
383     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
384     D3DDEVICEDESC desc;
385     DWORD dwSize;
386
387     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
388
389     fill_opengl_caps(&desc);
390     dwSize = lpD3DHWDevDesc->dwSize;
391     memset(lpD3DHWDevDesc, 0, dwSize);
392     memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
393
394     dwSize = lpD3DHELDevDesc->dwSize;
395     memset(lpD3DHELDevDesc, 0, dwSize);
396     memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
397
398     TRACE(" returning caps : (no dump function yet)\n");
399
400     return DD_OK;
401 }
402
403 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
404                                           LPD3DENUMPIXELFORMATSCALLBACK cb_2,
405                                           LPVOID context)
406 {
407     DDSURFACEDESC sdesc;
408     LPDDPIXELFORMAT pformat;
409
410     /* Do the texture enumeration */
411     sdesc.dwSize = sizeof(DDSURFACEDESC);
412     sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
413     sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
414     pformat = &(sdesc.ddpfPixelFormat);
415     pformat->dwSize = sizeof(DDPIXELFORMAT);
416     pformat->dwFourCC = 0;
417
418     TRACE("Enumerating GL_RGBA unpacked (32)\n");
419     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
420     pformat->u1.dwRGBBitCount = 32;
421     pformat->u2.dwRBitMask =        0x00FF0000;
422     pformat->u3.dwGBitMask =        0x0000FF00;
423     pformat->u4.dwBBitMask =        0x000000FF;
424     pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
425     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
426     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
427
428     TRACE("Enumerating GL_RGB unpacked (32)\n");
429     pformat->dwFlags = DDPF_RGB;
430     pformat->u1.dwRGBBitCount = 32;
431     pformat->u2.dwRBitMask =        0x00FF0000;
432     pformat->u3.dwGBitMask =        0x0000FF00;
433     pformat->u4.dwBBitMask =        0x000000FF;
434     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
435     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
436     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
437     
438     TRACE("Enumerating GL_RGB unpacked (24)\n");
439     pformat->dwFlags = DDPF_RGB;
440     pformat->u1.dwRGBBitCount = 24;
441     pformat->u2.dwRBitMask = 0x00FF0000;
442     pformat->u3.dwGBitMask = 0x0000FF00;
443     pformat->u4.dwBBitMask = 0x000000FF;
444     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
445     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
446     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
447
448     /* Note : even if this is an 'emulated' texture format, it needs to be first
449               as some dumb applications seem to rely on that. */
450     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
451     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
452     pformat->u1.dwRGBBitCount = 16;
453     pformat->u2.dwRBitMask =        0x00007C00;
454     pformat->u3.dwGBitMask =        0x000003E0;
455     pformat->u4.dwBBitMask =        0x0000001F;
456     pformat->u5.dwRGBAlphaBitMask = 0x00008000;
457     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
458     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
459
460     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
461     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
462     pformat->u1.dwRGBBitCount = 16;
463     pformat->u2.dwRBitMask =        0x00000F00;
464     pformat->u3.dwGBitMask =        0x000000F0;
465     pformat->u4.dwBBitMask =        0x0000000F;
466     pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
467     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
468     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
469
470     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
471     pformat->dwFlags = DDPF_RGB;
472     pformat->u1.dwRGBBitCount = 16;
473     pformat->u2.dwRBitMask = 0x0000F800;
474     pformat->u3.dwGBitMask = 0x000007E0;
475     pformat->u4.dwBBitMask = 0x0000001F;
476     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
477     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
478     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
479
480     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
481     pformat->dwFlags = DDPF_RGB;
482     pformat->u1.dwRGBBitCount = 16;
483     pformat->u2.dwRBitMask = 0x00007C00;
484     pformat->u3.dwGBitMask = 0x000003E0;
485     pformat->u4.dwBBitMask = 0x0000001F;
486     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
487     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
488     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
489     
490 #if 0
491     /* This is a compromise : some games choose the first 16 bit texture format with alpha they
492        find enumerated, others the last one. And both want to have the ARGB one.
493        
494        So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
495     */
496     /* See argument about the RGBA format for 'packed' texture formats */
497     TRACE("Enumerating GL_RGBA unpacked (32)\n");
498     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
499     pformat->u1.dwRGBBitCount = 32;
500     pformat->u2.dwRBitMask =        0xFF000000;
501     pformat->u3.dwGBitMask =        0x00FF0000;
502     pformat->u4.dwBBitMask =        0x0000FF00;
503     pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
504     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
505     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
506     
507     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
508     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
509     pformat->u1.dwRGBBitCount = 16;
510     pformat->u2.dwRBitMask =        0x0000F000;
511     pformat->u3.dwGBitMask =        0x00000F00;
512     pformat->u4.dwBBitMask =        0x000000F0;
513     pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
514     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
515     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
516
517     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
518     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
519     pformat->u1.dwRGBBitCount = 16;
520     pformat->u2.dwRBitMask =        0x0000F800;
521     pformat->u3.dwGBitMask =        0x000007C0;
522     pformat->u4.dwBBitMask =        0x0000003E;
523     pformat->u5.dwRGBAlphaBitMask = 0x00000001;
524     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
525     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
526 #endif
527
528     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
529     pformat->dwFlags = DDPF_RGB;
530     pformat->u1.dwRGBBitCount = 8;
531     pformat->u2.dwRBitMask =        0x000000E0;
532     pformat->u3.dwGBitMask =        0x0000001C;
533     pformat->u4.dwBBitMask =        0x00000003;
534     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
535     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
536     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
537
538     TRACE("Enumerating Paletted (8)\n");
539     pformat->dwFlags = DDPF_PALETTEINDEXED8;
540     pformat->u1.dwRGBBitCount = 8;
541     pformat->u2.dwRBitMask =        0x00000000;
542     pformat->u3.dwGBitMask =        0x00000000;
543     pformat->u4.dwBBitMask =        0x00000000;
544     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
545     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
546     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
547
548     TRACE("End of enumeration\n");
549     return DD_OK;
550 }
551
552
553 HRESULT
554 d3ddevice_find(IDirectDrawImpl *d3d,
555                LPD3DFINDDEVICESEARCH lpD3DDFS,
556                LPD3DFINDDEVICERESULT lplpD3DDevice)
557 {
558     D3DDEVICEDESC desc;
559   
560     if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
561         (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
562         TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
563         return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
564     }
565     if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
566         TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
567         if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
568             (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
569             (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
570             TRACE(" no match for this GUID.\n");
571             return DDERR_INVALIDPARAMS;
572         }
573     }
574
575     /* Now return our own GUID */
576     lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
577     fill_opengl_caps(&desc);
578     lplpD3DDevice->ddHwDesc = desc;
579     lplpD3DDevice->ddSwDesc = desc;
580
581     TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
582     
583     return D3D_OK;
584 }
585
586 HRESULT WINAPI
587 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
588                                                LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
589                                                LPVOID lpArg)
590 {
591     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
592     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
593     return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg);
594 }
595
596 HRESULT WINAPI
597 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
598                                                LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
599                                                LPVOID lpArg)
600 {
601     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
602     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
603     return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg);
604 }
605
606 HRESULT WINAPI
607 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
608                                               D3DRENDERSTATETYPE dwRenderStateType,
609                                               DWORD dwRenderState)
610 {
611     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
612     TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
613
614     /* Call the render state functions */
615     store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
616     set_render_state(This, dwRenderStateType, &This->state_block);
617
618     return DD_OK;
619 }
620
621 HRESULT WINAPI
622 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
623                                               D3DRENDERSTATETYPE dwRenderStateType,
624                                               LPDWORD lpdwRenderState)
625 {
626     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
627     TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
628
629     /* Call the render state functions */
630     get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
631
632     TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
633
634     return DD_OK;
635 }
636
637 HRESULT WINAPI
638 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
639                                           D3DLIGHTSTATETYPE dwLightStateType,
640                                           DWORD dwLightState)
641 {
642     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
643     
644     TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
645
646     if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX))
647         TRACE("Unexpected Light State Type\n");
648         return DDERR_INVALIDPARAMS;
649         
650     if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
651         IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
652
653         if (mat != NULL) {
654             ENTER_GL();
655             mat->activate(mat);
656             LEAVE_GL();
657         } else {
658             ERR(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
659         }
660     } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
661         switch (dwLightState) {
662             case D3DCOLOR_MONO:
663                ERR("DDCOLOR_MONO should not happen!\n");
664                break;
665             case D3DCOLOR_RGB:
666                /* We are already in this mode */
667                break;
668             default:
669                ERR("Unknown color model!\n");
670                break;
671         }
672     } else {
673         D3DRENDERSTATETYPE rs;
674         switch (dwLightStateType) {
675
676             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
677                 rs = D3DRENDERSTATE_AMBIENT;
678                 break;          
679             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
680                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
681                 break;
682             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
683                 rs = D3DRENDERSTATE_FOGSTART;
684                 break;
685             case D3DLIGHTSTATE_FOGEND:        /* 6 */
686                 rs = D3DRENDERSTATE_FOGEND;
687                 break;
688             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
689                 rs = D3DRENDERSTATE_FOGDENSITY;
690                 break;
691             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
692                 rs = D3DRENDERSTATE_COLORVERTEX;
693                 break;
694             default:
695                 break;
696         }
697
698         IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
699                                         rs,dwLightState);
700     }
701
702     return DD_OK;
703 }
704
705 static void draw_primitive_start_GL(D3DPRIMITIVETYPE d3dpt)
706 {
707     switch (d3dpt) {
708         case D3DPT_POINTLIST:
709             TRACE("Start POINTS\n");
710             glBegin(GL_POINTS);
711             break;
712
713         case D3DPT_LINELIST:
714             TRACE("Start LINES\n");
715             glBegin(GL_LINES);
716             break;
717
718         case D3DPT_LINESTRIP:
719             TRACE("Start LINE_STRIP\n");
720             glBegin(GL_LINE_STRIP);
721             break;
722
723         case D3DPT_TRIANGLELIST:
724             TRACE("Start TRIANGLES\n");
725             glBegin(GL_TRIANGLES);
726             break;
727
728         case D3DPT_TRIANGLESTRIP:
729             TRACE("Start TRIANGLE_STRIP\n");
730             glBegin(GL_TRIANGLE_STRIP);
731             break;
732
733         case D3DPT_TRIANGLEFAN:
734             TRACE("Start TRIANGLE_FAN\n");
735             glBegin(GL_TRIANGLE_FAN);
736             break;
737
738         default:
739             FIXME("Unhandled primitive %08x\n", d3dpt);
740             break;
741     }
742 }
743
744 /* This function calculate the Z coordinate from Zproj */ 
745 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
746 {
747     float a,b,c,d;
748     /* Assume that X = Y = 0 and W = 1 */
749     a = This->proj_mat->_33;
750     b = This->proj_mat->_34;
751     c = This->proj_mat->_43;
752     d = This->proj_mat->_44;
753     /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
754      * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
755      * And finally Z = (d * Zproj - c) / (a - b * Zproj)
756      */
757     return (d*Zproj - c) / (a - b*Zproj);
758 }
759
760 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
761     int i;
762     
763     TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
764     
765     for (i = 0; i < 3; i++) {
766         BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
767         DWORD elt;
768         for (elt = 0; elt < 0x10000; elt++) {
769             /* We apply the fog transformation and cache the result */
770             DWORD fog_intensity = elt & 0xFF;
771             DWORD vertex_color = (elt >> 8) & 0xFF;
772             fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
773         }
774     }
775 }
776
777 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
778                                            BOOLEAN vertex_transformed,
779                                            BOOLEAN vertex_lit) {
780     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
781   
782     /* Puts GL in the correct lighting / transformation mode */
783     if ((vertex_transformed == FALSE) && 
784         (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
785         /* Need to put the correct transformation again if we go from Transformed
786            vertices to non-transformed ones.
787         */
788         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
789                            This->world_mat, This->view_mat, This->proj_mat);
790         glThis->transform_state = GL_TRANSFORM_NORMAL;
791
792     } else if ((vertex_transformed == TRUE) &&
793                (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
794         /* Set our orthographic projection */
795         glThis->transform_state = GL_TRANSFORM_ORTHO;
796         d3ddevice_set_ortho(This);
797     }
798
799     /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
800              if no fogging state change occured */
801     if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
802         if (vertex_transformed == TRUE) {
803             glDisable(GL_FOG);
804             /* Now check if our fog_table still corresponds to the current vertex color.
805                Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
806             if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >>  0) & 0xFF)) ||
807                 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >>  8) & 0xFF)) ||
808                 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
809                 /* We need to rebuild our fog table.... */
810                 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
811             }
812         } else {
813             if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
814                 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
815                     case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break; 
816                     case D3DFOG_EXP:    glFogi(GL_FOG_MODE, GL_EXP); break; 
817                     case D3DFOG_EXP2:   glFogi(GL_FOG_MODE, GL_EXP2); break;
818                 }
819                 if (vertex_lit == FALSE) {
820                     glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
821                     glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
822                 } else {
823                     /* Special case of 'pixel fog' */
824                     glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
825                     glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
826                 }
827                 glEnable(GL_FOG);
828             } else {
829                 glDisable(GL_FOG);
830             }
831         }
832     } else {
833         glDisable(GL_FOG);
834     }
835     
836     /* Handle the 'no-normal' case */
837     if ((vertex_lit == FALSE) && (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE))
838         glEnable(GL_LIGHTING);
839     else 
840         glDisable(GL_LIGHTING);
841
842     /* Handle the code for pre-vertex material properties */
843     if (vertex_transformed == FALSE) {
844         if ((This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
845             (This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
846             if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
847                 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
848                 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
849                 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
850                 glEnable(GL_COLOR_MATERIAL);
851             }
852         }
853     }
854 }
855
856
857 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
858                                   D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
859 {
860     D3DDRAWPRIMITIVESTRIDEDDATA strided;
861
862     switch (d3dvt) {
863         case D3DVT_VERTEX: {
864             strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
865             strided.position.dwStride = sizeof(D3DVERTEX);
866             strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
867             strided.normal.dwStride = sizeof(D3DVERTEX);
868             strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
869             strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
870             draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
871         } break;
872
873         case D3DVT_LVERTEX: {
874             strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
875             strided.position.dwStride = sizeof(D3DLVERTEX);
876             strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
877             strided.diffuse.dwStride = sizeof(D3DLVERTEX);
878             strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
879             strided.specular.dwStride = sizeof(D3DLVERTEX);
880             strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
881             strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
882             draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
883         } break;
884
885         case D3DVT_TLVERTEX: {
886             strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
887             strided.position.dwStride = sizeof(D3DTLVERTEX);
888             strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
889             strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
890             strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
891             strided.specular.dwStride = sizeof(D3DTLVERTEX);
892             strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
893             strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
894             draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
895         } break;
896
897         default:
898             FIXME("Unhandled vertex type %08x\n", d3dvt);
899             break;
900     }
901 }
902
903 HRESULT WINAPI
904 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
905                                        D3DPRIMITIVETYPE d3dptPrimitiveType,
906                                        D3DVERTEXTYPE d3dvtVertexType,
907                                        LPVOID lpvVertices,
908                                        DWORD dwVertexCount,
909                                        DWORD dwFlags)
910 {
911     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
912
913     TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
914     if (TRACE_ON(ddraw)) {
915         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
916     }
917
918     draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
919                    
920     return DD_OK;
921 }
922
923 HRESULT WINAPI
924 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
925                                               D3DPRIMITIVETYPE d3dptPrimitiveType,
926                                               D3DVERTEXTYPE d3dvtVertexType,
927                                               LPVOID lpvVertices,
928                                               DWORD dwVertexCount,
929                                               LPWORD dwIndices,
930                                               DWORD dwIndexCount,
931                                               DWORD dwFlags)
932 {
933     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
934     TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
935     if (TRACE_ON(ddraw)) {
936         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
937     }
938
939     draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
940     
941     return DD_OK;
942 }
943
944 HRESULT WINAPI
945 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
946                                              LPD3DEXECUTEBUFFERDESC lpDesc,
947                                              LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
948                                              IUnknown* pUnkOuter)
949 {
950     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
951     IDirect3DExecuteBufferImpl *ret;
952     HRESULT ret_value;
953     
954     TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
955
956     ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
957     *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
958
959     TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
960     
961     return ret_value;
962 }
963
964 /* These are the various handler used in the generic path */
965 inline static void handle_xyz(D3DVALUE *coords) {
966     glVertex3fv(coords);
967 }
968 inline static void handle_xyzrhw(D3DVALUE *coords) {
969     if (coords[3] < 1e-8)
970         glVertex3fv(coords);
971     else {
972         GLfloat w = 1.0 / coords[3];
973         
974         glVertex4f(coords[0] * w,
975                    coords[1] * w,
976                    coords[2] * w,
977                    w);
978     }
979 }
980 inline static void handle_normal(D3DVALUE *coords) {
981     glNormal3fv(coords);
982 }
983
984 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
985     if ((sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) ||
986         (sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1] == TRUE)) {
987         glColor4ub((*color >> 16) & 0xFF,
988                    (*color >>  8) & 0xFF,
989                    (*color >>  0) & 0xFF,
990                    (*color >> 24) & 0xFF);
991     } else {
992         glColor3ub((*color >> 16) & 0xFF,
993                    (*color >>  8) & 0xFF,
994                    (*color >>  0) & 0xFF);    
995     }
996 }
997
998 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
999     glColor4ub((*color >> 16) & 0xFF,
1000                (*color >>  8) & 0xFF,
1001                (*color >>  0) & 0xFF,
1002                (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1003 }
1004
1005 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1006     if ((lighted == FALSE) &&
1007         (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1008         (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1009         if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1010             glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1011             handle_diffuse_base(sb, color);
1012         }
1013         if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1014             glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1015             handle_diffuse_base(sb, color);
1016         }
1017         if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1018             (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1019             glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1020             handle_diffuse_base(sb, color);
1021         }
1022         if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1023             glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1024             handle_diffuse_base(sb, color);
1025         }
1026     } else {
1027         handle_diffuse_base(sb, color);
1028     }    
1029 }
1030
1031 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1032     if ((lighted == FALSE) &&
1033         (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) &&
1034         (sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1] == TRUE)) {
1035         if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1036             glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1037             handle_specular_base(sb, color);
1038         }
1039         if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1040             glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1041             handle_specular_base(sb, color);
1042         }
1043         if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1044             (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE)) {
1045             glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1046             handle_specular_base(sb, color);
1047         }
1048         if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1049             glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1050             handle_specular_base(sb, color);
1051         }
1052     }
1053     /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1054 }
1055
1056 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1057     if (lighted == TRUE) {
1058         DWORD color = *color_d;
1059         if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) {
1060             /* Special case where the specular value is used to do fogging */
1061             BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1062             color &= 0xFF000000; /* Only keep the alpha component */
1063             color |= fog_table[((*color_d >>  0) & 0xFF) << 8 | fog_intensity] <<  0;
1064             color |= fog_table[((*color_d >>  8) & 0xFF) << 8 | fog_intensity] <<  8;
1065             color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1066         }
1067         if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE) {
1068             /* Standard specular value in transformed mode. TODO */
1069         }
1070         handle_diffuse_base(sb, &color);
1071     } else {
1072         if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) {
1073             handle_diffuse(sb, color_d, FALSE);
1074             handle_specular(sb, color_s, FALSE);
1075         } else {
1076             /* In that case, only put the diffuse color... */
1077             handle_diffuse_base(sb, color_d);
1078         }
1079     }
1080 }
1081
1082 inline static void handle_texture(D3DVALUE *coords) {
1083     glTexCoord2fv(coords);
1084 }
1085 inline static void handle_textures(D3DVALUE *coords, int tex_index) {
1086     /* For the moment, draw only the first texture.. */
1087     if (tex_index == 0) glTexCoord2fv(coords);
1088 }
1089
1090 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1091                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1092                                    DWORD d3dvtVertexType,
1093                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1094                                    DWORD dwVertexCount,
1095                                    LPWORD dwIndices,
1096                                    DWORD dwIndexCount,
1097                                    DWORD dwFlags)
1098 {
1099     BOOLEAN vertex_lighted = FALSE;
1100     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1101     int num_active_stages = 0;
1102
1103     /* This is to prevent 'thread contention' between a thread locking the device and another
1104        doing 3D display on it... */
1105     EnterCriticalSection(&(This->crit));   
1106     
1107     ENTER_GL();
1108     if (glThis->state == SURFACE_MEMORY_DIRTY) {
1109         This->flush_to_framebuffer(This, NULL, glThis->lock_surf);
1110     }
1111
1112     glThis->state = SURFACE_GL;
1113     
1114     /* Compute the number of active texture stages */
1115     while (This->current_texture[num_active_stages] != NULL) num_active_stages++;
1116
1117     if (TRACE_ON(ddraw)) {
1118         TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1119     }
1120
1121     /* Just a hack for now.. Will have to find better algorithm :-/ */
1122     if ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) {
1123         vertex_lighted = TRUE;
1124     } else {
1125         if ((d3dvtVertexType & D3DFVF_NORMAL) == 0) glNormal3f(0.0, 0.0, 0.0);
1126     }
1127     
1128     draw_primitive_handle_GL_state(This,
1129                                    (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1130                                    vertex_lighted);
1131     draw_primitive_start_GL(d3dptPrimitiveType);
1132
1133     /* Some fast paths first before the generic case.... */
1134     if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1135         int index;
1136         
1137         for (index = 0; index < dwIndexCount; index++) {
1138             int i = (dwIndices == NULL) ? index : dwIndices[index];
1139             D3DVALUE *normal = 
1140               (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1141             D3DVALUE *tex_coord =
1142               (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1143             D3DVALUE *position =
1144               (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1145             
1146             handle_normal(normal);
1147             handle_texture(tex_coord);
1148             handle_xyz(position);
1149             
1150             TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1151                                position[0], position[1], position[2],
1152                                normal[0], normal[1], normal[2],
1153                                tex_coord[0], tex_coord[1]);
1154         }
1155     } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1156         int index;
1157         
1158         for (index = 0; index < dwIndexCount; index++) {
1159             int i = (dwIndices == NULL) ? index : dwIndices[index];
1160             DWORD *color_d = 
1161               (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1162             DWORD *color_s = 
1163               (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1164             D3DVALUE *tex_coord =
1165               (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1166             D3DVALUE *position =
1167               (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1168
1169             handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1170             handle_texture(tex_coord);
1171             handle_xyzrhw(position);
1172
1173             TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1174                                position[0], position[1], position[2], position[3], 
1175                                (*color_d >> 16) & 0xFF,
1176                                (*color_d >>  8) & 0xFF,
1177                                (*color_d >>  0) & 0xFF,
1178                                (*color_d >> 24) & 0xFF,
1179                                (*color_s >> 16) & 0xFF,
1180                                (*color_s >>  8) & 0xFF,
1181                                (*color_s >>  0) & 0xFF,
1182                                (*color_s >> 24) & 0xFF,
1183                                tex_coord[0], tex_coord[1]);
1184         } 
1185     } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1186                ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1187         /* This is the 'slow path' but that should support all possible vertex formats out there...
1188            Note that people should write a fast path for all vertex formats out there...
1189         */  
1190         int index;
1191         int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1192         static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1193           
1194         for (index = 0; index < dwIndexCount; index++) {
1195             int i = (dwIndices == NULL) ? index : dwIndices[index];
1196             int tex_stage;
1197
1198             if (d3dvtVertexType & D3DFVF_NORMAL) { 
1199                 D3DVALUE *normal = 
1200                   (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);         
1201                 handle_normal(normal);
1202             }
1203             if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1204                 DWORD *color_d = 
1205                   (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1206                 DWORD *color_s = 
1207                   (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1208                 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1209             } else {
1210                 if (d3dvtVertexType & D3DFVF_SPECULAR) { 
1211                     DWORD *color_s = 
1212                       (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1213                     handle_specular(&(This->state_block), color_s, vertex_lighted);
1214                 } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1215                     DWORD *color_d = 
1216                       (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1217                     handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1218                 }
1219             }
1220
1221             for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1222                 int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0xFFFF000;
1223                 if (tex_index >= num_tex_index) {
1224                     handle_textures((D3DVALUE *) no_index, tex_stage);
1225                  } else {
1226                      D3DVALUE *tex_coord =
1227                        (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) + 
1228                                      i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1229                      handle_textures(tex_coord, tex_stage);
1230                 }
1231             }
1232             
1233             if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1234                 D3DVALUE *position =
1235                   (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1236                 handle_xyz(position);
1237             } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1238                 D3DVALUE *position =
1239                   (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1240                 handle_xyzrhw(position);
1241             }
1242
1243             if (TRACE_ON(ddraw_geom)) {
1244                 int tex_index;
1245
1246                 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1247                     D3DVALUE *position =
1248                       (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1249                     TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1250                 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1251                     D3DVALUE *position =
1252                       (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1253                     TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1254                 }
1255                 if (d3dvtVertexType & D3DFVF_NORMAL) { 
1256                     D3DVALUE *normal = 
1257                       (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);     
1258                     TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1259                 }
1260                 if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1261                     DWORD *color_d = 
1262                       (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1263                     TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1264                                        (*color_d >> 16) & 0xFF,
1265                                        (*color_d >>  8) & 0xFF,
1266                                        (*color_d >>  0) & 0xFF,
1267                                        (*color_d >> 24) & 0xFF);
1268                 }
1269                 if (d3dvtVertexType & D3DFVF_SPECULAR) { 
1270                     DWORD *color_s = 
1271                       (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1272                     TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1273                                        (*color_s >> 16) & 0xFF,
1274                                        (*color_s >>  8) & 0xFF,
1275                                        (*color_s >>  0) & 0xFF,
1276                                        (*color_s >> 24) & 0xFF);
1277                 }
1278                 for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1279                     D3DVALUE *tex_coord =
1280                       (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) + 
1281                                     i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1282                     TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1283                 }
1284                 TRACE_(ddraw_geom)("\n");
1285             }
1286         }
1287     } else {
1288         ERR(" matrix weighting not handled yet....\n");
1289     }
1290     
1291     glEnd();
1292
1293     /* Whatever the case, disable the color material stuff */
1294     glDisable(GL_COLOR_MATERIAL);
1295
1296     LEAVE_GL();
1297     TRACE("End\n");    
1298
1299     LeaveCriticalSection(&(This->crit));
1300 }
1301
1302 HRESULT WINAPI
1303 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1304                                           D3DPRIMITIVETYPE d3dptPrimitiveType,
1305                                           DWORD d3dvtVertexType,
1306                                           LPVOID lpvVertices,
1307                                           DWORD dwVertexCount,
1308                                           DWORD dwFlags)
1309 {
1310     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1311     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1312
1313     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1314     if (TRACE_ON(ddraw)) {
1315         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1316     }
1317
1318     convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1319     draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1320     
1321     return DD_OK;
1322 }
1323
1324 HRESULT WINAPI
1325 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1326                                                  D3DPRIMITIVETYPE d3dptPrimitiveType,
1327                                                  DWORD d3dvtVertexType,
1328                                                  LPVOID lpvVertices,
1329                                                  DWORD dwVertexCount,
1330                                                  LPWORD dwIndices,
1331                                                  DWORD dwIndexCount,
1332                                                  DWORD dwFlags)
1333 {
1334     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1335     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1336
1337     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1338     if (TRACE_ON(ddraw)) {
1339         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1340     }
1341
1342     convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1343     draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1344     
1345     return DD_OK;
1346 }
1347
1348 HRESULT WINAPI
1349 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1350                                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1351                                                    DWORD dwVertexType,
1352                                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1353                                                    DWORD dwVertexCount,
1354                                                    DWORD dwFlags)
1355 {
1356     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1357
1358     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1359     if (TRACE_ON(ddraw)) {
1360         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1361     }
1362     draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1363
1364     return DD_OK;
1365 }
1366
1367 HRESULT WINAPI
1368 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1369                                                           D3DPRIMITIVETYPE d3dptPrimitiveType,
1370                                                           DWORD dwVertexType,
1371                                                           LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1372                                                           DWORD dwVertexCount,
1373                                                           LPWORD lpIndex,
1374                                                           DWORD dwIndexCount,
1375                                                           DWORD dwFlags)
1376 {
1377     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1378
1379     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1380     if (TRACE_ON(ddraw)) {
1381         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1382     }
1383
1384     draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1385
1386     return DD_OK;
1387 }
1388
1389 HRESULT WINAPI
1390 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1391                                             D3DPRIMITIVETYPE d3dptPrimitiveType,
1392                                             LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1393                                             DWORD dwStartVertex,
1394                                             DWORD dwNumVertices,
1395                                             DWORD dwFlags)
1396 {
1397     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1398     IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1399     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1400
1401     TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1402     if (TRACE_ON(ddraw)) {
1403         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1404     }
1405
1406     if (vb_impl->processed == TRUE) {
1407         IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1408         IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1409
1410         glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1411         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1412                            &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1413
1414         convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1415         draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1416
1417     } else {
1418         convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1419         draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1420     }
1421
1422     return DD_OK;
1423 }
1424
1425 HRESULT WINAPI
1426 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1427                                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1428                                                    LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1429                                                    DWORD dwStartVertex,
1430                                                    DWORD dwNumVertices,
1431                                                    LPWORD lpwIndices,
1432                                                    DWORD dwIndexCount,
1433                                                    DWORD dwFlags)
1434 {
1435     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1436     IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1437     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1438     
1439     TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1440     if (TRACE_ON(ddraw)) {
1441         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1442     }
1443
1444     if (vb_impl->processed == TRUE) {
1445         IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1446         IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1447
1448         glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1449         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1450                            &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1451
1452         convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1453         draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1454
1455     } else {
1456         convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1457         draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1458     }
1459
1460     return DD_OK;
1461 }
1462
1463 static GLenum
1464 convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
1465 {
1466     GLenum gl_state;
1467
1468     if (dwMipState == D3DTFP_NONE) {
1469         switch (dwMinState) {
1470             case D3DTFN_POINT:  gl_state = GL_NEAREST; break;
1471             case D3DTFN_LINEAR: gl_state = GL_LINEAR;  break;
1472             default:            gl_state = GL_LINEAR;  break;
1473         }
1474     } else if (dwMipState == D3DTFP_POINT) {
1475         switch (dwMinState) {
1476             case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
1477             case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
1478             default:            gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
1479         }
1480     } else {
1481         switch (dwMinState) {
1482             case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
1483             case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
1484             default:            gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
1485         }
1486     }
1487     return gl_state;
1488 }
1489
1490 static GLenum
1491 convert_mag_filter_to_GL(D3DTEXTUREMAGFILTER dwState)
1492 {
1493     GLenum gl_state;
1494
1495     switch (dwState) {
1496         case D3DTFG_POINT:
1497             gl_state = GL_NEAREST;
1498             break;
1499         case D3DTFG_LINEAR:
1500             gl_state = GL_LINEAR;
1501             break;
1502         default:
1503             gl_state = GL_LINEAR;
1504             break;
1505     }
1506     return gl_state;
1507 }
1508
1509 static GLenum
1510 convert_tex_address_to_GL(D3DTEXTUREADDRESS dwState)
1511 {
1512     GLenum gl_state;
1513     switch (dwState) {
1514         case D3DTADDRESS_WRAP:   gl_state = GL_REPEAT; break;
1515         case D3DTADDRESS_CLAMP:  gl_state = GL_CLAMP; break;
1516         case D3DTADDRESS_BORDER: gl_state = GL_CLAMP_TO_EDGE; break;
1517 #if defined(GL_VERSION_1_4)
1518         case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT; break;
1519 #elif defined(GL_ARB_texture_mirrored_repeat)
1520         case D3DTADDRESS_MIRROR: gl_state = GL_MIRRORED_REPEAT_ARB; break;
1521 #endif
1522         default:                 gl_state = GL_REPEAT; break;
1523     }
1524     return gl_state;
1525 }
1526
1527 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1528 static BOOLEAN
1529 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1530 {
1531     BOOLEAN is_complement = FALSE;
1532     BOOLEAN is_alpha_replicate = FALSE;
1533     BOOLEAN handled = TRUE;
1534     GLenum src;
1535     BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1536     int num;
1537     
1538     if (is_color) {
1539         if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1540         else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1541         else {
1542             handled = FALSE;
1543             num = 0;
1544         }
1545         if (tex_op == D3DTOP_SELECTARG2) {
1546             num = 1 - num;
1547         }
1548     } else {
1549         if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1550         else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1551         else {
1552             handled = FALSE;
1553             num = 0;
1554         }
1555         if (tex_op == D3DTOP_SELECTARG2) {
1556             num = 1 - num;
1557         }
1558     }
1559     
1560     if (dwState & D3DTA_COMPLEMENT) {
1561         is_complement = TRUE;
1562     }
1563     if (dwState & D3DTA_ALPHAREPLICATE) {
1564         is_alpha_replicate = TRUE;
1565     }
1566     dwState &= D3DTA_SELECTMASK;
1567     if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1568         dwState = D3DTA_DIFFUSE;
1569     }
1570
1571     switch (dwState) {
1572         case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1573         case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1574         case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1575         case D3DTA_TFACTOR: {
1576             /* Get the constant value from the current rendering state */
1577             GLfloat color[4];
1578             DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1579             
1580             color[0] = ((col >> 16) & 0xFF) / 255.0f;
1581             color[1] = ((col >>  8) & 0xFF) / 255.0f;
1582             color[2] = ((col >>  0) & 0xFF) / 255.0f;
1583             color[3] = ((col >> 24) & 0xFF) / 255.0f;
1584             glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1585             
1586             src = GL_CONSTANT_EXT;
1587         } break;
1588         default: src = GL_TEXTURE; handled = FALSE; break;
1589     }
1590
1591     if (is_color) {
1592         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1593         if (is_alpha_replicate) {
1594             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1595         } else {
1596             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1597         }
1598     } else {
1599         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1600         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1601     }
1602
1603     return handled;
1604 }
1605
1606 HRESULT WINAPI
1607 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1608                                                  DWORD dwStage,
1609                                                  D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1610                                                  DWORD dwState)
1611 {
1612     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1613     const char *type;
1614     DWORD prev_state;
1615     
1616     TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1617
1618     if (dwStage > 0) return DD_OK; /* We nothing in this case for now */
1619
1620     switch (d3dTexStageStateType) {
1621 #define GEN_CASE(a) case a: type = #a; break
1622         GEN_CASE(D3DTSS_COLOROP);
1623         GEN_CASE(D3DTSS_COLORARG1);
1624         GEN_CASE(D3DTSS_COLORARG2);
1625         GEN_CASE(D3DTSS_ALPHAOP);
1626         GEN_CASE(D3DTSS_ALPHAARG1);
1627         GEN_CASE(D3DTSS_ALPHAARG2);
1628         GEN_CASE(D3DTSS_BUMPENVMAT00);
1629         GEN_CASE(D3DTSS_BUMPENVMAT01);
1630         GEN_CASE(D3DTSS_BUMPENVMAT10);
1631         GEN_CASE(D3DTSS_BUMPENVMAT11);
1632         GEN_CASE(D3DTSS_TEXCOORDINDEX);
1633         GEN_CASE(D3DTSS_ADDRESS);
1634         GEN_CASE(D3DTSS_ADDRESSU);
1635         GEN_CASE(D3DTSS_ADDRESSV);
1636         GEN_CASE(D3DTSS_BORDERCOLOR);
1637         GEN_CASE(D3DTSS_MAGFILTER);
1638         GEN_CASE(D3DTSS_MINFILTER);
1639         GEN_CASE(D3DTSS_MIPFILTER);
1640         GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1641         GEN_CASE(D3DTSS_MAXMIPLEVEL);
1642         GEN_CASE(D3DTSS_MAXANISOTROPY);
1643         GEN_CASE(D3DTSS_BUMPENVLSCALE);
1644         GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1645         GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1646 #undef GEN_CASE
1647         default: type = "UNKNOWN";
1648     }
1649
1650     /* Store the values in the state array */
1651     prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1652     This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1653     /* Some special cases when one state modifies more than one... */
1654     if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1655         This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1656         This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1657     }
1658
1659     ENTER_GL();
1660     
1661     switch (d3dTexStageStateType) {
1662         case D3DTSS_MINFILTER:
1663         case D3DTSS_MIPFILTER:
1664             if (TRACE_ON(ddraw)) {
1665                 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1666                     switch ((D3DTEXTUREMINFILTER) dwState) {
1667                         case D3DTFN_POINT:  TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1668                         case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1669                         default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1670                     }
1671                 } else {
1672                     switch ((D3DTEXTUREMIPFILTER) dwState) {
1673                         case D3DTFP_NONE:   TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1674                         case D3DTFP_POINT:  TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1675                         case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1676                         default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1677                     }
1678                 }
1679             }
1680
1681             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1682                             convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
1683                                                      This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
1684             break;
1685             
1686         case D3DTSS_MAGFILTER:
1687             if (TRACE_ON(ddraw)) {
1688                 switch ((D3DTEXTUREMAGFILTER) dwState) {
1689                     case D3DTFG_POINT:  TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_POINT\n"); break;
1690                     case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_LINEAR\n"); break;
1691                     default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1692                 }
1693             }
1694             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, convert_mag_filter_to_GL(dwState));
1695             break;
1696
1697         case D3DTSS_ADDRESS:
1698         case D3DTSS_ADDRESSU:
1699         case D3DTSS_ADDRESSV: {
1700             GLenum arg = convert_tex_address_to_GL(dwState);
1701             
1702             switch ((D3DTEXTUREADDRESS) dwState) {
1703                 case D3DTADDRESS_WRAP:   TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1704                 case D3DTADDRESS_CLAMP:  TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1705                 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1706 #if defined(GL_VERSION_1_4)
1707                 case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
1708 #elif defined(GL_ARB_texture_mirrored_repeat)
1709                 case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); break;
1710 #endif
1711                 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1712             }
1713             
1714             if ((d3dTexStageStateType == D3DTSS_ADDRESS) ||
1715                 (d3dTexStageStateType == D3DTSS_ADDRESSU))
1716                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, arg);
1717             if ((d3dTexStageStateType == D3DTSS_ADDRESS) ||
1718                 (d3dTexStageStateType == D3DTSS_ADDRESSV))
1719                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, arg);
1720         } break;
1721
1722         case D3DTSS_ALPHAOP:
1723         case D3DTSS_COLOROP: {
1724             int scale = 1;
1725             GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1726             const char *value;
1727             int handled = 1;
1728             
1729             switch (dwState) {
1730 #define GEN_CASE(a) case a: value = #a; break
1731                 GEN_CASE(D3DTOP_DISABLE);
1732                 GEN_CASE(D3DTOP_SELECTARG1);
1733                 GEN_CASE(D3DTOP_SELECTARG2);
1734                 GEN_CASE(D3DTOP_MODULATE);
1735                 GEN_CASE(D3DTOP_MODULATE2X);
1736                 GEN_CASE(D3DTOP_MODULATE4X);
1737                 GEN_CASE(D3DTOP_ADD);
1738                 GEN_CASE(D3DTOP_ADDSIGNED);
1739                 GEN_CASE(D3DTOP_ADDSIGNED2X);
1740                 GEN_CASE(D3DTOP_SUBTRACT);
1741                 GEN_CASE(D3DTOP_ADDSMOOTH);
1742                 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1743                 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1744                 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1745                 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1746                 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1747                 GEN_CASE(D3DTOP_PREMODULATE);
1748                 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1749                 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1750                 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1751                 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1752                 GEN_CASE(D3DTOP_BUMPENVMAP);
1753                 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1754                 GEN_CASE(D3DTOP_DOTPRODUCT3);
1755                 GEN_CASE(D3DTOP_FORCE_DWORD);
1756 #undef GEN_CASE
1757                 default: value = "UNKNOWN";
1758             }
1759
1760             if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE) && (dwStage == 0)) {
1761                 glDisable(GL_TEXTURE_2D);
1762                 TRACE(" disabling 2D texturing.\n");
1763             } else {
1764                 /* Re-enable texturing */
1765                 if ((dwStage == 0) && (This->current_texture[0] != NULL)) {
1766                     glEnable(GL_TEXTURE_2D);
1767                     TRACE(" enabling 2D texturing.\n");
1768                 }
1769                 
1770                 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
1771                 if (dwState != D3DTOP_DISABLE) {
1772                     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1773                 }
1774
1775                 /* Now set up the operand correctly */
1776                 switch (dwState) {
1777                     case D3DTOP_DISABLE:
1778                         /* Contrary to the docs, alpha can be disabled when colorop is enabled
1779                            and it works, so ignore this op */
1780                         TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
1781                         break;
1782
1783                     case D3DTOP_SELECTARG1:
1784                     case D3DTOP_SELECTARG2:
1785                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
1786                         break;
1787                         
1788                     case D3DTOP_MODULATE4X:
1789                         scale = scale * 2;  /* Drop through */
1790                     case D3DTOP_MODULATE2X:
1791                         scale = scale * 2;  /* Drop through */
1792                     case D3DTOP_MODULATE:
1793                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
1794                         break;
1795
1796                     case D3DTOP_ADD:
1797                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
1798                         break;
1799
1800                     case D3DTOP_ADDSIGNED2X:
1801                         scale = scale * 2;  /* Drop through */
1802                     case D3DTOP_ADDSIGNED:
1803                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
1804                         break;
1805
1806                         /* For the four blending modes, use the Arg2 parameter */
1807                     case D3DTOP_BLENDDIFFUSEALPHA:
1808                     case D3DTOP_BLENDTEXTUREALPHA:
1809                     case D3DTOP_BLENDFACTORALPHA:
1810                     case D3DTOP_BLENDCURRENTALPHA: {
1811                         GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
1812
1813                         switch (dwState) {
1814                             case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
1815                             case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
1816                             case D3DTOP_BLENDFACTORALPHA:  src = GL_CONSTANT_EXT;
1817                             case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
1818                         }
1819                         
1820                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
1821                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
1822                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
1823                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
1824                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
1825                     } break;
1826                         
1827                     default:
1828                         handled = FALSE;
1829                         break;
1830                 }
1831             }
1832
1833             if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
1834                 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
1835                 /* Switch the arguments if needed... */
1836                 if (d3dTexStageStateType == D3DTSS_COLOROP) {
1837                     handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
1838                                             This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
1839                                             dwState);
1840                     handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
1841                                             This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
1842                                             dwState);
1843                 } else {
1844                     handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
1845                                             This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
1846                                             dwState);
1847                     handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
1848                                             This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
1849                                             dwState);
1850                 }
1851             }
1852             
1853             if (handled) {
1854                 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
1855                     glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
1856                 } else {
1857                     glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
1858                 }                       
1859                 TRACE(" Stage type is : %s => %s\n", type, value);
1860             } else {
1861                 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
1862             }
1863         } break;
1864
1865         case D3DTSS_COLORARG1:
1866         case D3DTSS_COLORARG2:
1867         case D3DTSS_ALPHAARG1:
1868         case D3DTSS_ALPHAARG2: {
1869             const char *value, *value_comp = "", *value_alpha = "";
1870             BOOLEAN handled;
1871             D3DTEXTUREOP tex_op;
1872             
1873             switch (dwState & D3DTA_SELECTMASK) {
1874 #define GEN_CASE(a) case a: value = #a; break
1875                 GEN_CASE(D3DTA_DIFFUSE);
1876                 GEN_CASE(D3DTA_CURRENT);
1877                 GEN_CASE(D3DTA_TEXTURE);
1878                 GEN_CASE(D3DTA_TFACTOR);
1879                 GEN_CASE(D3DTA_SPECULAR);
1880 #undef GEN_CASE
1881                 default: value = "UNKNOWN";
1882             }
1883             if (dwState & D3DTA_COMPLEMENT) {
1884                 value_comp = " | D3DTA_COMPLEMENT";
1885             }
1886             if (dwState & D3DTA_ALPHAREPLICATE) {
1887                 value_alpha = " | D3DTA_ALPHAREPLICATE";
1888             }
1889
1890             if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
1891                 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
1892             } else {
1893                 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
1894             }
1895             
1896             handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
1897             
1898             if (handled) {
1899                 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
1900             } else {
1901                 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
1902             }
1903         } break;
1904
1905         case D3DTSS_MIPMAPLODBIAS: {
1906             D3DVALUE value = *((D3DVALUE *) &dwState);
1907             BOOLEAN handled = TRUE;
1908             
1909             if (value != 0.0)
1910                 handled = FALSE;
1911
1912             if (handled) {
1913                 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
1914             } else {
1915                 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
1916             }
1917         } break;
1918
1919         case D3DTSS_MAXMIPLEVEL: 
1920             if (dwState == 0) {
1921                 TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => 0 (disabled) \n");
1922             } else {
1923                 FIXME(" Unhandled stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
1924             }
1925             break;
1926
1927         case D3DTSS_BORDERCOLOR: {
1928             GLfloat color[4];
1929
1930             color[0] = ((dwState >> 16) & 0xFF) / 255.0;
1931             color[1] = ((dwState >>  8) & 0xFF) / 255.0;
1932             color[2] = ((dwState >>  0) & 0xFF) / 255.0;
1933             color[3] = ((dwState >> 24) & 0xFF) / 255.0;
1934
1935             glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
1936
1937             TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
1938                   ((dwState >> 16) & 0xFF),
1939                   ((dwState >>  8) & 0xFF),
1940                   ((dwState >>  0) & 0xFF),
1941                   ((dwState >> 24) & 0xFF));
1942         } break;
1943             
1944         case D3DTSS_TEXCOORDINDEX: {
1945             BOOLEAN handled = TRUE;
1946             const char *value;
1947             
1948             switch (dwState & 0xFFFF0000) {
1949 #define GEN_CASE(a) case a: value = #a; break
1950                 GEN_CASE(D3DTSS_TCI_PASSTHRU);
1951                 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
1952                 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
1953                 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
1954 #undef GEN_CASE
1955                 default: value = "UNKNOWN";
1956             }
1957             if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
1958                 handled = FALSE;
1959
1960             if (handled) {
1961                 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
1962             } else {
1963                 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
1964             }
1965         } break;
1966             
1967         case D3DTSS_TEXTURETRANSFORMFLAGS: {
1968             const char *projected = "", *value;
1969             BOOLEAN handled = TRUE;
1970             switch (dwState & 0xFF) {
1971 #define GEN_CASE(a) case a: value = #a; break
1972                 GEN_CASE(D3DTTFF_DISABLE);
1973                 GEN_CASE(D3DTTFF_COUNT1);
1974                 GEN_CASE(D3DTTFF_COUNT2);
1975                 GEN_CASE(D3DTTFF_COUNT3);
1976                 GEN_CASE(D3DTTFF_COUNT4);
1977 #undef GEN_CASE
1978                 default: value = "UNKNOWN";
1979             }
1980             if (dwState & D3DTTFF_PROJECTED) {
1981                 projected = " | D3DTTFF_PROJECTED";
1982                 handled = FALSE;
1983             }
1984
1985             if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
1986                 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
1987             }
1988
1989             if (handled == TRUE) {
1990                 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
1991             } else {
1992                 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
1993             }
1994         } break;
1995             
1996         default:
1997             FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
1998             break;
1999     }
2000
2001     LEAVE_GL();
2002     
2003     return DD_OK;
2004 }
2005
2006 HRESULT WINAPI
2007 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2008                                        DWORD dwStage,
2009                                        LPDIRECTDRAWSURFACE7 lpTexture2)
2010 {
2011     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2012     
2013     TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2014     
2015     if (dwStage > 0) return DD_OK;
2016
2017     if (This->current_texture[dwStage] != NULL) {
2018         IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2019     }
2020     
2021     ENTER_GL();
2022     if (lpTexture2 == NULL) {
2023         This->current_texture[dwStage] = NULL;
2024
2025         TRACE(" disabling 2D texturing.\n");
2026         glBindTexture(GL_TEXTURE_2D, 0);
2027         glDisable(GL_TEXTURE_2D);
2028     } else {
2029         IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2030         GLint max_mip_level;
2031         GLfloat color[4];
2032         
2033         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7)); /* Not sure about this either */
2034
2035         if (This->current_texture[dwStage] == tex_impl) {
2036             /* No need to do anything as the texture did not change. */
2037             return DD_OK;
2038         }
2039         This->current_texture[dwStage] = tex_impl;
2040         
2041         if (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2042             /* Do not re-enable texturing if it was disabled due to the COLOROP code */
2043             glEnable(GL_TEXTURE_2D);
2044             TRACE(" enabling 2D texturing.\n");
2045         }
2046         gltex_upload_texture(tex_impl);
2047
2048         if ((tex_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
2049             max_mip_level = 0;
2050         } else {
2051             max_mip_level = tex_impl->surface_desc.u2.dwMipMapCount - 1;
2052         }
2053
2054         /* Now we need to reset all glTexParameter calls for this particular texture... */
2055         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
2056                         convert_mag_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MAGFILTER - 1]));
2057         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2058                         convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
2059                                                   This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
2060         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
2061                         convert_tex_address_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1]));
2062         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
2063                         convert_tex_address_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1]));        
2064         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
2065         color[0] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >> 16) & 0xFF) / 255.0;
2066         color[1] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >>  8) & 0xFF) / 255.0;
2067         color[2] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >>  0) & 0xFF) / 255.0;
2068         color[3] = ((This->state_block.texture_stage_state[dwStage][D3DTSS_BORDERCOLOR - 1] >> 24) & 0xFF) / 255.0;
2069         glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
2070     }
2071     LEAVE_GL();
2072     
2073     return DD_OK;
2074 }
2075
2076 HRESULT WINAPI
2077 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2078                                  LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2079 {
2080     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2081     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2082
2083     fill_opengl_caps_7(lpD3DHELDevDesc);
2084
2085     TRACE(" returning caps : no dump function yet.\n");
2086
2087     return DD_OK;
2088 }
2089
2090 HRESULT WINAPI
2091 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2092                                      LPD3DMATERIAL7 lpMat)
2093 {
2094     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2095     TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2096     
2097     if (TRACE_ON(ddraw)) {
2098         TRACE(" material is : \n");
2099         dump_D3DMATERIAL7(lpMat);
2100     }
2101     
2102     This->current_material = *lpMat;
2103
2104     glMaterialfv(GL_FRONT_AND_BACK,
2105                  GL_DIFFUSE,
2106                  (float *) &(This->current_material.u.diffuse));
2107     glMaterialfv(GL_FRONT_AND_BACK,
2108                  GL_AMBIENT,
2109                  (float *) &(This->current_material.u1.ambient));
2110     glMaterialfv(GL_FRONT_AND_BACK,
2111                  GL_SPECULAR,
2112                  (float *) &(This->current_material.u2.specular));
2113     glMaterialfv(GL_FRONT_AND_BACK,
2114                  GL_EMISSION,
2115                  (float *) &(This->current_material.u3.emissive));
2116     glMaterialf(GL_FRONT_AND_BACK,
2117                 GL_SHININESS,
2118                 This->current_material.u4.power); /* Not sure about this... */
2119
2120     return DD_OK;
2121 }
2122
2123
2124 HRESULT WINAPI
2125 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2126                                   DWORD dwLightIndex,
2127                                   LPD3DLIGHT7 lpLight)
2128 {
2129     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2130     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2131     TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2132     
2133     if (TRACE_ON(ddraw)) {
2134         TRACE(" setting light : \n");
2135         dump_D3DLIGHT7(lpLight);
2136     }
2137     
2138     if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2139     This->set_lights |= 0x00000001 << dwLightIndex;
2140     This->light_parameters[dwLightIndex] = *lpLight;
2141
2142     /* Some checks to print out nice warnings :-) */
2143     switch (lpLight->dltType) {
2144         case D3DLIGHT_DIRECTIONAL:
2145         case D3DLIGHT_POINT:
2146             /* These are handled properly... */
2147             break;
2148             
2149         case D3DLIGHT_SPOT:
2150             if ((lpLight->dvTheta != 0.0) ||
2151                 (lpLight->dvTheta != lpLight->dvPhi)) {
2152                 ERR("dvTheta not fully supported yet !\n");
2153             }
2154             break;
2155
2156         default:
2157             ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2158     }
2159     
2160     /* This will force the Light setting on next drawing of primitives */
2161     glThis->transform_state = GL_TRANSFORM_NONE;
2162     
2163     return DD_OK;
2164 }
2165
2166 HRESULT WINAPI
2167 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2168                                      DWORD dwLightIndex,
2169                                      BOOL bEnable)
2170 {
2171     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2172     TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2173     
2174     if (dwLightIndex >= MAX_LIGHTS) return DDERR_INVALIDPARAMS;
2175
2176     if (bEnable) {
2177         if (((0x00000001 << dwLightIndex) & This->set_lights) == 0) {
2178             /* Set the default parameters.. */
2179             TRACE(" setting default light parameters...\n");
2180             GL_IDirect3DDeviceImpl_7_SetLight(iface, dwLightIndex, &(This->light_parameters[dwLightIndex]));
2181         }
2182         glEnable(GL_LIGHT0 + dwLightIndex);
2183         if ((This->active_lights & (0x00000001 << dwLightIndex)) == 0) {
2184             /* This light gets active... Need to update its parameters to GL before the next drawing */
2185             IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2186             
2187             This->active_lights |= 0x00000001 << dwLightIndex;
2188             glThis->transform_state = GL_TRANSFORM_NONE;
2189         }
2190     } else {
2191         glDisable(GL_LIGHT0 + dwLightIndex);
2192         This->active_lights &= ~(0x00000001 << dwLightIndex);
2193     }
2194
2195     return DD_OK;
2196 }
2197
2198 HRESULT  WINAPI  
2199 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation) 
2200 {
2201     ICOM_THIS(IDirect3DDeviceImpl,iface);
2202     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2203
2204     TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2205
2206     if (dwIndex >= This->max_clipping_planes) {
2207         return DDERR_INVALIDPARAMS;
2208     }
2209
2210     TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2211
2212     memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2213     
2214     /* This is to force the reset of the transformation matrices on the next drawing.
2215      * This is needed to use the correct matrices for the various clipping planes.
2216      */
2217     glThis->transform_state = GL_TRANSFORM_NONE;
2218     
2219     return D3D_OK;
2220 }
2221
2222 HRESULT WINAPI
2223 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2224                                      LPD3DVIEWPORT7 lpData)
2225 {
2226     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2227     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2228
2229     if (TRACE_ON(ddraw)) {
2230         TRACE(" viewport is : \n");
2231         TRACE("    - dwX = %ld   dwY = %ld\n",
2232               lpData->dwX, lpData->dwY);
2233         TRACE("    - dwWidth = %ld   dwHeight = %ld\n",
2234               lpData->dwWidth, lpData->dwHeight);
2235         TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
2236               lpData->dvMinZ, lpData->dvMaxZ);
2237     }
2238     This->active_viewport = *lpData;
2239
2240     ENTER_GL();
2241     
2242     /* Set the viewport */
2243     glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2244     glViewport(lpData->dwX,
2245                This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2246                lpData->dwWidth, lpData->dwHeight);
2247
2248     LEAVE_GL();
2249     
2250     return DD_OK;
2251 }
2252
2253 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2254 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice7.fun))
2255 #else
2256 # define XCAST(fun)     (void*)
2257 #endif
2258
2259 ICOM_VTABLE(IDirect3DDevice7) VTABLE_IDirect3DDevice7 =
2260 {
2261     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2262     XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2263     XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2264     XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2265     XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2266     XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2267     XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2268     XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2269     XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2270     XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2271     XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2272     XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2273     XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2274     XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2275     XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2276     XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2277     XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2278     XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2279     XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2280     XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2281     XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2282     XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2283     XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2284     XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2285     XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2286     XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2287     XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2288     XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2289     XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2290     XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2291     XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2292     XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2293     XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2294     XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2295     XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2296     XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2297     XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2298     XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2299     XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2300     XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2301     XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2302     XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2303     XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2304     XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2305     XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2306     XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2307     XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2308     XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2309     XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2310     XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2311 };
2312
2313 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2314 #undef XCAST
2315 #endif
2316
2317
2318 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2319 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice3.fun))
2320 #else
2321 # define XCAST(fun)     (void*)
2322 #endif
2323
2324 ICOM_VTABLE(IDirect3DDevice3) VTABLE_IDirect3DDevice3 =
2325 {
2326     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2327     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2328     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2329     XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2330     XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2331     XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2332     XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2333     XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2334     XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2335     XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2336     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2337     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2338     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2339     XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2340     XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2341     XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2342     XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2343     XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2344     XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2345     XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2346     XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2347     XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2348     XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2349     XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2350     XCAST(GetLightState) Main_IDirect3DDeviceImpl_3_2T_GetLightState,
2351     XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2352     XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2353     XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2354     XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2355     XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2356     XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2357     XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2358     XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2359     XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2360     XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2361     XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2362     XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2363     XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2364     XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2365     XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2366     XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2367     XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2368     XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2369 };
2370
2371 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2372 #undef XCAST
2373 #endif
2374
2375
2376 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2377 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice2.fun))
2378 #else
2379 # define XCAST(fun)     (void*)
2380 #endif
2381
2382 ICOM_VTABLE(IDirect3DDevice2) VTABLE_IDirect3DDevice2 =
2383 {
2384     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2385     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2386     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2387     XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2388     XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2389     XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2390     XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2391     XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2392     XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2393     XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2394     XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2395     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2396     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2397     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2398     XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2399     XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2400     XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2401     XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2402     XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2403     XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2404     XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2405     XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2406     XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2407     XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2408     XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2409     XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2410     XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2411     XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2412     XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2413     XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2414     XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2415     XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2416     XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2417     XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2418 };
2419
2420 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2421 #undef XCAST
2422 #endif
2423
2424
2425 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2426 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice.fun))
2427 #else
2428 # define XCAST(fun)     (void*)
2429 #endif
2430
2431 ICOM_VTABLE(IDirect3DDevice) VTABLE_IDirect3DDevice =
2432 {
2433     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2434     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2435     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2436     XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2437     XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2438     XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2439     XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2440     XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2441     XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2442     XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2443     XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2444     XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2445     XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2446     XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2447     XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2448     XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2449     XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2450     XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2451     XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2452     XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2453     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2454     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2455     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2456 };
2457
2458 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2459 #undef XCAST
2460 #endif
2461
2462 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2463                                DWORD dwCount,
2464                                LPD3DRECT lpRects,
2465                                DWORD dwFlags,
2466                                DWORD dwColor,
2467                                D3DVALUE dvZ,
2468                                DWORD dwStencil)
2469 {
2470     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2471     GLboolean ztest;
2472     GLfloat old_z_clear_value;
2473     GLbitfield bitfield = 0;
2474     GLint old_stencil_clear_value;
2475     GLfloat old_color_clear_value[4];
2476     D3DRECT rect;
2477     int i;
2478     
2479     TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2480     if (TRACE_ON(ddraw)) {
2481         if (dwCount > 0) {
2482             int i;
2483             TRACE(" rectangles : \n");
2484             for (i = 0; i < dwCount; i++) {
2485                 TRACE("  - %ld x %ld     %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2486             }
2487         }
2488     }
2489
2490     if (dwCount == 0) {
2491         /* Not sure if this is really needed... */
2492         dwCount = 1;
2493         rect.u1.x1 = 0;
2494         rect.u2.y1 = 0;
2495         rect.u3.x2 = This->surface->surface_desc.dwWidth;
2496         rect.u4.y2 = This->surface->surface_desc.dwHeight;
2497         lpRects = &rect;
2498     }
2499     
2500     /* Clears the screen */
2501     ENTER_GL();
2502
2503     if (glThis->state == SURFACE_MEMORY_DIRTY) {
2504         /* TODO: optimize here the case where Clear changes all the screen... */
2505         This->flush_to_framebuffer(This, NULL, glThis->lock_surf);
2506     }
2507     glThis->state = SURFACE_GL;
2508
2509     if (dwFlags & D3DCLEAR_ZBUFFER) {
2510         bitfield |= GL_DEPTH_BUFFER_BIT;
2511         glGetBooleanv(GL_DEPTH_WRITEMASK, &ztest);
2512         glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2513         glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
2514         glClearDepth(dvZ);
2515         TRACE(" depth value : %f\n", dvZ);
2516     }
2517     if (dwFlags & D3DCLEAR_STENCIL) {
2518         bitfield |= GL_STENCIL_BUFFER_BIT;
2519         glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
2520         glClearStencil(dwStencil);
2521         TRACE(" stencil value : %ld\n", dwStencil);
2522     }    
2523     if (dwFlags & D3DCLEAR_TARGET) {
2524         bitfield |= GL_COLOR_BUFFER_BIT;
2525         glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
2526         glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2527                      ((dwColor >>  8) & 0xFF) / 255.0,
2528                      ((dwColor >>  0) & 0xFF) / 255.0,
2529                      ((dwColor >> 24) & 0xFF) / 255.0);
2530         TRACE(" color value (ARGB) : %08lx\n", dwColor);
2531     }
2532
2533     glEnable(GL_SCISSOR_TEST); 
2534     for (i = 0; i < dwCount; i++) {
2535         glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2536                   lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2537         glClear(bitfield);
2538     }
2539     glDisable(GL_SCISSOR_TEST); 
2540     
2541     if (dwFlags & D3DCLEAR_ZBUFFER) {
2542         glDepthMask(ztest);
2543         glClearDepth(old_z_clear_value);
2544     }
2545      if (dwFlags & D3DCLEAR_STENCIL) {
2546         bitfield |= GL_STENCIL_BUFFER_BIT;
2547         glClearStencil(old_stencil_clear_value);
2548     }    
2549     if (dwFlags & D3DCLEAR_TARGET) {
2550         bitfield |= GL_COLOR_BUFFER_BIT;
2551         glClearColor(old_color_clear_value[0],
2552                      old_color_clear_value[1],
2553                      old_color_clear_value[2],
2554                      old_color_clear_value[3]);
2555     }
2556     
2557     LEAVE_GL();
2558     
2559     return DD_OK;
2560 }
2561
2562 HRESULT
2563 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
2564               LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
2565               DWORD dwFlags, LPDDBLTFX lpbltfx)
2566 {
2567     if (dwFlags & DDBLT_COLORFILL) {
2568         /* This is easy to handle for the D3D Device... */
2569         DWORD color = lpbltfx->u5.dwFillColor;
2570         D3DRECT rect;
2571         
2572         TRACE(" executing D3D Device override.\n");
2573
2574         if (rdst) {
2575             rect.u1.x1 = rdst->left;
2576             rect.u2.y1 = rdst->top;
2577             rect.u3.x2 = rdst->right;
2578             rect.u4.y2 = rdst->bottom;
2579         }
2580         d3ddevice_clear(This->d3ddevice, rdst != NULL ? 1 : 0, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
2581         return DD_OK;
2582     }
2583     return DDERR_INVALIDPARAMS;
2584 }
2585
2586 HRESULT
2587 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
2588                   DWORD dsty, LPDIRECTDRAWSURFACE7 src,
2589                   LPRECT rsrc, DWORD trans)
2590 {
2591      return DDERR_INVALIDPARAMS;
2592 }
2593
2594 void
2595 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
2596 {
2597     GLfloat height, width;
2598     GLfloat trans_mat[16];
2599     
2600     width = This->surface->surface_desc.dwWidth;
2601     height = This->surface->surface_desc.dwHeight;
2602     
2603     /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
2604        to OpenGL screen coordinates (ie the upper left corner is not the same).
2605        For Z, the mystery is what should it be mapped to ? Ie should the resulting range be between
2606        -1.0 and 1.0 (as the X and Y coordinates) or between 0.0 and 1.0 ? */
2607     trans_mat[ 0] = 2.0 / width;  trans_mat[ 4] = 0.0;  trans_mat[ 8] = 0.0; trans_mat[12] = -1.0;
2608     trans_mat[ 1] = 0.0; trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0; trans_mat[13] =  1.0;
2609     trans_mat[ 2] = 0.0; trans_mat[ 6] = 0.0; trans_mat[10] = 1.0;           trans_mat[14] = -1.0;
2610     trans_mat[ 3] = 0.0; trans_mat[ 7] = 0.0; trans_mat[11] = 0.0;           trans_mat[15] =  1.0;
2611     
2612     glMatrixMode(GL_MODELVIEW);
2613     glLoadIdentity();
2614     /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
2615        Correctness Tips section).
2616        
2617        Basically, from what I understood, if the game does not filter the font texture,
2618        as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
2619        one and we will have strange artifacts (as the rounding and stuff may give different results
2620        for different pixels, ie sometimes take the left pixel, sometimes the right).
2621     */
2622     glTranslatef(0.375, 0.375, 0);
2623     glMatrixMode(GL_PROJECTION);
2624     glLoadMatrixf(trans_mat);
2625 }
2626
2627 void
2628 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
2629                        D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
2630 {
2631     if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
2632         glMatrixMode(GL_MODELVIEW);
2633         glLoadMatrixf((float *) view_mat);
2634
2635         /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
2636         if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
2637             GLint i;
2638             DWORD runner;
2639             for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
2640                 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
2641                     GLdouble plane[4];
2642
2643                     plane[0] = This->clipping_planes[i].plane[0];
2644                     plane[1] = This->clipping_planes[i].plane[1];
2645                     plane[2] = This->clipping_planes[i].plane[2];
2646                     plane[3] = This->clipping_planes[i].plane[3];
2647                     
2648                     glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
2649                 }
2650             }
2651         }
2652         if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
2653             GLint i;
2654             DWORD runner;
2655
2656             for (i = 0, runner = 0x00000001; i < MAX_LIGHTS; i++, runner <<= 1) {
2657                 if (runner & This->active_lights) {
2658                     switch (This->light_parameters[i].dltType) {
2659                         case D3DLIGHT_DIRECTIONAL: {
2660                             float direction[4];
2661                             float cut_off = 180.0;
2662                             
2663                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &(This->light_parameters[i].dcvAmbient));
2664                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &(This->light_parameters[i].dcvDiffuse));
2665                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
2666                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
2667                             
2668                             direction[0] = This->light_parameters[i].dvDirection.u1.x;
2669                             direction[1] = This->light_parameters[i].dvDirection.u2.y;
2670                             direction[2] = This->light_parameters[i].dvDirection.u3.z;
2671                             direction[3] = 0.0;
2672                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
2673                         } break;
2674
2675                         case D3DLIGHT_POINT: {
2676                             float position[4];
2677                             float cut_off = 180.0;
2678                             
2679                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &(This->light_parameters[i].dcvAmbient));
2680                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &(This->light_parameters[i].dcvDiffuse));
2681                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
2682                             position[0] = This->light_parameters[i].dvPosition.u1.x;
2683                             position[1] = This->light_parameters[i].dvPosition.u2.y;
2684                             position[2] = This->light_parameters[i].dvPosition.u3.z;
2685                             position[3] = 1.0;
2686                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
2687                             glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
2688                             glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
2689                             glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
2690                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
2691                         } break;
2692
2693                         case D3DLIGHT_SPOT: {
2694                             float direction[4];
2695                             float position[4];
2696                             float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
2697                             
2698                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &(This->light_parameters[i].dcvAmbient));
2699                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &(This->light_parameters[i].dcvDiffuse));
2700                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &(This->light_parameters[i].dcvSpecular));
2701                             
2702                             direction[0] = This->light_parameters[i].dvDirection.u1.x;
2703                             direction[1] = This->light_parameters[i].dvDirection.u2.y;
2704                             direction[2] = This->light_parameters[i].dvDirection.u3.z;
2705                             direction[3] = 0.0;
2706                             glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
2707                             position[0] = This->light_parameters[i].dvPosition.u1.x;
2708                             position[1] = This->light_parameters[i].dvPosition.u2.y;
2709                             position[2] = This->light_parameters[i].dvPosition.u3.z;
2710                             position[3] = 1.0;
2711                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
2712                             glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &(This->light_parameters[i].dvAttenuation0));
2713                             glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &(This->light_parameters[i].dvAttenuation1));
2714                             glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &(This->light_parameters[i].dvAttenuation2));
2715                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
2716                             glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &(This->light_parameters[i].dvFalloff));
2717                         } break;
2718
2719                         default:
2720                             /* No warning here as it's already done at light setting */
2721                             break;
2722                     }
2723                 }
2724             }
2725         }
2726         
2727         glMultMatrixf((float *) world_mat);
2728     }
2729     if ((matrices & PROJMAT_CHANGED) != 0) {
2730         glMatrixMode(GL_PROJECTION);
2731         glLoadMatrixf((float *) proj_mat);
2732     }
2733 }
2734
2735 void
2736 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
2737 {
2738     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2739     DWORD tex_mat, tex_stage;
2740     if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) != 0) {
2741         if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
2742             /* This will force an update of the transform state at the next drawing. */
2743             glThis->transform_state = GL_TRANSFORM_NONE;
2744         }
2745     }
2746     if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
2747                     TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
2748     {
2749         ENTER_GL();
2750         for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
2751             if (matrices & tex_mat) {
2752                 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
2753                     if (tex_stage == 0) {
2754                         /* No multi-texturing support for now ... */
2755                         glMatrixMode(GL_TEXTURE);
2756                         glLoadMatrixf((float *) This->tex_mat[tex_stage]);
2757                     }
2758                 } else {
2759                     glMatrixMode(GL_TEXTURE);
2760                     glLoadIdentity();
2761                 }
2762             }
2763         }
2764         LEAVE_GL();
2765     }
2766 }
2767
2768 /* TODO for both these functions :
2769     - change / restore OpenGL parameters for pictures transfers in case they are ever modified
2770       by other OpenGL code in D3D
2771     - handle the case where no 'Begin / EndScene' was done between two locks
2772     - handle the rectangles in the unlock too
2773     - handle pitch correctly...
2774 */
2775 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
2776 {
2777     IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
2778     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
2779     BOOLEAN is_front;
2780     
2781     if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2782         is_front = TRUE;
2783         if ((gl_d3d_dev->front_state != SURFACE_GL) &&
2784             (gl_d3d_dev->front_lock_surf != This)) {
2785             ERR("Change of front buffer.. Expect graphic corruptions !\n");
2786         }
2787         gl_d3d_dev->front_lock_surf = This;
2788     } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
2789         is_front = FALSE;
2790         if ((gl_d3d_dev->state != SURFACE_GL) &&
2791             (gl_d3d_dev->lock_surf != This)) {
2792             ERR("Change of back buffer.. Expect graphic corruptions !\n");
2793         }
2794         gl_d3d_dev->lock_surf = This;
2795     } else {
2796         ERR("Wrong surface type for locking !\n");
2797         return;
2798     }
2799
2800     /* Try to acquire the device critical section */
2801     EnterCriticalSection(&(d3d_dev->crit));
2802     
2803     if (((is_front == TRUE)  && (gl_d3d_dev->front_state == SURFACE_GL)) ||
2804         ((is_front == FALSE) && (gl_d3d_dev->state       == SURFACE_GL))) {
2805         /* If the surface is already in memory, no need to do anything here... */
2806         GLenum buffer_type;
2807         GLenum buffer_color;
2808         RECT loc_rect;
2809         int y;
2810         char *dst;
2811
2812         TRACE(" copying frame buffer to main memory.\n");
2813         
2814         /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
2815            may only write to the device... But when we will blit it back to the screen, we need
2816            also to blit correctly the parts the application did not overwrite... */
2817         
2818         if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
2819             (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
2820             (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask ==        0x07E0) &&
2821             (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
2822             (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000)) {
2823             buffer_type = GL_UNSIGNED_SHORT_5_6_5;
2824             buffer_color = GL_RGB;
2825         } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
2826                    (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
2827                    (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
2828                    (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
2829                    (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
2830             buffer_type = GL_UNSIGNED_BYTE;
2831             buffer_color = GL_BGRA;
2832             glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
2833         } else {
2834             ERR(" unsupported pixel format at device locking.\n");
2835             return;
2836         }
2837
2838         ENTER_GL();
2839         
2840         if (is_front == TRUE)
2841             /* Application wants to lock the front buffer */
2842             glReadBuffer(GL_FRONT);
2843         else 
2844             /* Application wants to lock the back buffer */
2845             glReadBuffer(GL_BACK);
2846
2847         /* Just a hack while waiting for proper rectangle support */
2848         pRect = NULL;
2849         if (pRect == NULL) {
2850             loc_rect.top = 0;
2851             loc_rect.left = 0;
2852             loc_rect.bottom = This->surface_desc.dwHeight;
2853             loc_rect.right = This->surface_desc.dwWidth;
2854         } else {
2855             loc_rect = *pRect;
2856         }
2857         
2858         dst = ((char *)This->surface_desc.lpSurface) +
2859           (loc_rect.top * This->surface_desc.u1.lPitch) + (loc_rect.left * GET_BPP(This->surface_desc));
2860         for (y = (This->surface_desc.dwHeight - loc_rect.top - 1);
2861              y >= ((int) This->surface_desc.dwHeight - (int) loc_rect.bottom);
2862              y--) {
2863             glReadPixels(loc_rect.left, y,
2864                          loc_rect.right - loc_rect.left, 1,
2865                          buffer_color, buffer_type, dst);
2866             dst += This->surface_desc.u1.lPitch;
2867         }
2868
2869         glPixelStorei(GL_PACK_SWAP_BYTES, FALSE);
2870         
2871         if (is_front)
2872             gl_d3d_dev->front_state = SURFACE_MEMORY;
2873         else
2874             gl_d3d_dev->state = SURFACE_MEMORY;
2875         
2876 #if 0
2877         /* I keep this code here as it's very useful to debug :-) */
2878         {
2879             static int flush_count = 0;
2880             char buf[128];
2881             FILE *f;
2882             
2883             if ((++flush_count % 50) == 0) {
2884                 sprintf(buf, "lock_%06d.pnm", flush_count);
2885                 f = fopen(buf, "wb");
2886                 DDRAW_dump_surface_to_disk(This, f);
2887             }
2888         }
2889 #endif
2890         
2891         LEAVE_GL();
2892     }
2893 }
2894
2895 #define UNLOCK_TEX_SIZE 256
2896
2897 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
2898     RECT loc_rect;
2899     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
2900     GLint depth_test, alpha_test, cull_face, lighting, tex_env, blend, stencil_test, fog;
2901     GLuint initial_texture;
2902     GLint tex_state;
2903     int x, y;
2904     BOOLEAN initial = FALSE;
2905
2906     /* Note : no need here to lock the 'device critical section' as we are already protected by
2907        the GL critical section. */
2908     
2909     loc_rect.top = 0;
2910     loc_rect.left = 0;
2911     loc_rect.bottom = surf->surface_desc.dwHeight;
2912     loc_rect.right = surf->surface_desc.dwWidth;
2913
2914     TRACE(" flushing memory back to the frame-buffer (%ld,%ld) x (%ld,%ld).\n", loc_rect.top, loc_rect.left, loc_rect.right, loc_rect.bottom);
2915
2916     glGetIntegerv(GL_TEXTURE_BINDING_2D, &initial_texture);
2917     if (gl_d3d_dev->unlock_tex == 0) {
2918         glGenTextures(1, &gl_d3d_dev->unlock_tex);
2919         glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
2920         initial = TRUE;
2921         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2922         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2923     } else {
2924         glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
2925     }
2926     
2927     if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
2928                                           initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != D3D_OK) {
2929         ERR(" unsupported pixel format at frame buffer flush.\n");
2930         glBindTexture(GL_TEXTURE_2D, initial_texture);
2931         return;
2932     }
2933         
2934     glGetIntegerv(GL_DEPTH_TEST, &depth_test);
2935     glGetIntegerv(GL_ALPHA_TEST, &alpha_test);
2936     glGetIntegerv(GL_STENCIL_TEST, &stencil_test);
2937     glGetIntegerv(GL_CULL_FACE, &cull_face);
2938     glGetIntegerv(GL_LIGHTING, &lighting);
2939     glGetIntegerv(GL_BLEND, &blend);
2940     glGetIntegerv(GL_TEXTURE_2D, &tex_state);
2941     glGetIntegerv(GL_FOG, &fog);
2942     glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env);
2943     glMatrixMode(GL_TEXTURE);
2944     glLoadIdentity();
2945     /* TODO: scissor test if ever we use it ! */
2946     
2947     gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
2948     d3ddevice_set_ortho(d3d_dev);
2949     
2950     glDisable(GL_DEPTH_TEST);
2951     glEnable(GL_TEXTURE_2D);
2952     glEnable(GL_SCISSOR_TEST); 
2953     glDepthRange(0.0, 1.0);
2954     glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
2955     glScissor(loc_rect.left, surf->surface_desc.dwHeight - loc_rect.bottom,
2956               loc_rect.right - loc_rect.left, loc_rect.bottom - loc_rect.top);
2957     glDisable(GL_LIGHTING);
2958     glDisable(GL_CULL_FACE);
2959     glDisable(GL_ALPHA_TEST);
2960     glDisable(GL_STENCIL_TEST);
2961     glDisable(GL_BLEND);
2962     glDisable(GL_FOG);
2963     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2964     
2965     for (x = loc_rect.left; x < loc_rect.right; x += UNLOCK_TEX_SIZE) {
2966         for (y = loc_rect.top; y < loc_rect.bottom; y += UNLOCK_TEX_SIZE) {
2967             /* First, upload the texture... */
2968             RECT flush_rect;
2969
2970             flush_rect.left = x;
2971             flush_rect.top = y;
2972             flush_rect.right  = (x + UNLOCK_TEX_SIZE > surf->surface_desc.dwWidth)  ? surf->surface_desc.dwWidth  : (x + UNLOCK_TEX_SIZE);
2973             flush_rect.bottom = (y + UNLOCK_TEX_SIZE > surf->surface_desc.dwHeight) ? surf->surface_desc.dwHeight : (y + UNLOCK_TEX_SIZE);
2974
2975             upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
2976
2977             glBegin(GL_QUADS);
2978             glColor3ub(0xFF, 0xFF, 0xFF);
2979             glTexCoord2f(0.0, 0.0);
2980             glVertex3d(x, y, 0.5);
2981             glTexCoord2f(1.0, 0.0);
2982             glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
2983             glTexCoord2f(1.0, 1.0);
2984             glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
2985             glTexCoord2f(0.0, 1.0);
2986             glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
2987             glEnd();
2988         }
2989     }
2990     
2991     upload_surface_to_tex_memory_release();
2992     
2993     /* And restore all the various states modified by this code */
2994     if (depth_test != 0) glEnable(GL_DEPTH_TEST);
2995     if (lighting != 0) glEnable(GL_LIGHTING);
2996     if (alpha_test != 0) glEnable(GL_ALPHA_TEST);
2997     if (stencil_test != 0) glEnable(GL_STENCIL_TEST);
2998     if (cull_face != 0) glEnable(GL_CULL_FACE);
2999     if (blend != 0) glEnable(GL_BLEND);
3000     if (fog != 0) glEnable(GL_FOG);
3001     glBindTexture(GL_TEXTURE_2D, initial_texture);
3002     if (tex_state == 0) glDisable(GL_TEXTURE_2D);
3003     glDisable(GL_SCISSOR_TEST);
3004     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
3005     glPixelStorei(GL_UNPACK_SWAP_BYTES, FALSE);
3006     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_env);
3007     glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
3008     glViewport(d3d_dev->active_viewport.dwX,
3009                d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
3010                d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
3011     d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
3012 #if 0
3013     /* I keep this code here as it's very useful to debug :-) */
3014     {
3015         static int flush_count = 0;
3016         char buf[128];
3017         FILE *f;
3018
3019         if ((++flush_count % 50) == 0) {
3020             sprintf(buf, "flush_%06d.pnm", flush_count);
3021             f = fopen(buf, "wb");
3022             DDRAW_dump_surface_to_disk(surf, f);
3023         }
3024     }
3025 #endif
3026 }
3027
3028 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3029 {
3030     BOOLEAN is_front;
3031     IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3032     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3033   
3034     if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3035         is_front = TRUE;
3036     } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3037         is_front = FALSE;
3038     } else {
3039         ERR("Wrong surface type for locking !\n");
3040         return;
3041     }
3042     /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3043     if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3044         if (is_front == TRUE) {
3045             GLenum prev_draw;
3046             ENTER_GL();
3047             glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3048             glDrawBuffer(GL_FRONT);
3049             d3d_dev->flush_to_framebuffer(d3d_dev, pRect, gl_d3d_dev->front_lock_surf);
3050             glDrawBuffer(prev_draw);
3051             LEAVE_GL();
3052         } else {
3053             gl_d3d_dev->state = SURFACE_MEMORY_DIRTY;
3054         }
3055     }
3056
3057     /* And 'frees' the device critical section */
3058     LeaveCriticalSection(&(d3d_dev->crit));
3059 }
3060
3061 static void
3062 apply_texture_state(IDirect3DDeviceImpl *This)
3063 {
3064     int stage, state;
3065     
3066     /* Initialize texture stages states */
3067     for (stage = 0; stage < MAX_TEXTURES; stage++) {
3068        for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3069            if (This->state_block.set_flags.texture_stage_state[stage][state] == TRUE) {
3070                IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3071                                                      stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3072            }
3073        }
3074     }
3075 }     
3076
3077 HRESULT
3078 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface)
3079 {
3080     IDirect3DDeviceImpl *object;
3081     IDirect3DDeviceGLImpl *gl_object;
3082     IDirectDrawSurfaceImpl *surf;
3083     HDC device_context;
3084     XVisualInfo *vis;
3085     int num;
3086     int tex_num;
3087     XVisualInfo template;
3088     GLenum buffer = GL_FRONT;
3089     int light;
3090     GLint max_clipping_planes = 0;
3091     
3092     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3093     if (object == NULL) return DDERR_OUTOFMEMORY;
3094
3095     gl_object = (IDirect3DDeviceGLImpl *) object;
3096     
3097     object->ref = 1;
3098     object->d3d = d3d;
3099     object->surface = surface;
3100     object->set_context = set_context;
3101     object->clear = d3ddevice_clear;
3102     object->set_matrices = d3ddevice_set_matrices;
3103     object->matrices_updated = d3ddevice_matrices_updated;
3104     object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3105     
3106     InitializeCriticalSection(&(object->crit));
3107     
3108     TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
3109
3110     device_context = GetDC(surface->ddraw_owner->window);
3111     gl_object->display = get_display(device_context);
3112     gl_object->drawable = get_drawable(device_context);
3113     ReleaseDC(surface->ddraw_owner->window,device_context);
3114
3115     ENTER_GL();
3116     template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
3117     vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
3118     if (vis == NULL) {
3119         HeapFree(GetProcessHeap(), 0, object);
3120         ERR("No visual found !\n");
3121         LEAVE_GL();
3122         return DDERR_INVALIDPARAMS;
3123     } else {
3124         TRACE(" visual found\n");
3125     }
3126
3127     gl_object->gl_context = glXCreateContext(gl_object->display, vis,
3128                                              NULL, GL_TRUE);
3129
3130     if (gl_object->gl_context == NULL) {
3131         HeapFree(GetProcessHeap(), 0, object);
3132         ERR("Error in context creation !\n");
3133         LEAVE_GL();
3134         return DDERR_INVALIDPARAMS;
3135     } else {
3136         TRACE(" context created (%p)\n", gl_object->gl_context);
3137     }
3138     
3139     /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
3140     for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3141         if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
3142             surf->aux_ctx  = (LPVOID) object;
3143             surf->aux_data = (LPVOID) gl_object->drawable;
3144             surf->aux_flip = opengl_flip;
3145             buffer =  GL_BACK;
3146             break;
3147         }
3148     }
3149     /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
3150     if (surf == NULL) {
3151         TRACE(" no double buffering : drawing on the front buffer\n");
3152         buffer = GL_FRONT;
3153     }
3154     
3155     for (surf = surface; surf != NULL; surf = surf->surface_owner) {
3156         IDirectDrawSurfaceImpl *surf2;
3157         for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
3158         for (; surf2 != NULL; surf2 = surf2->next_attached) {
3159             TRACE(" checking surface %p :", surf2);
3160             if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
3161                 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
3162                 /* Override the Lock / Unlock function for all these surfaces */
3163                 surf2->lock_update_prev = surf2->lock_update;
3164                 surf2->lock_update = d3ddevice_lock_update;
3165                 surf2->unlock_update_prev = surf2->unlock_update;
3166                 surf2->unlock_update = d3ddevice_unlock_update;
3167                 /* And install also the blt / bltfast overrides */
3168                 surf2->aux_blt = d3ddevice_blt;
3169                 surf2->aux_bltfast = d3ddevice_bltfast;
3170                 
3171                 TRACE(" overiding direct surface access.\n");
3172             } else {
3173                 TRACE(" no overide.\n");
3174             }
3175             surf2->d3ddevice = object;
3176         }
3177     }
3178
3179     /* Set the various light parameters */
3180     for (light = 0; light < MAX_LIGHTS; light++) {
3181         /* Only set the fields that are not zero-created */
3182         object->light_parameters[light].dltType = D3DLIGHT_DIRECTIONAL;
3183         object->light_parameters[light].dcvDiffuse.u1.r = 1.0;
3184         object->light_parameters[light].dcvDiffuse.u2.g = 1.0;
3185         object->light_parameters[light].dcvDiffuse.u3.b = 1.0;
3186         object->light_parameters[light].dvDirection.u3.z = 1.0;
3187     }
3188     
3189     /* Allocate memory for the matrices */
3190     object->world_mat = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3191     object->view_mat  = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3192     object->proj_mat  = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3193     memcpy(object->world_mat, id_mat, 16 * sizeof(float));
3194     memcpy(object->view_mat , id_mat, 16 * sizeof(float));
3195     memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
3196     for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
3197         object->tex_mat[tex_num] = (D3DMATRIX *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
3198         memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
3199     }
3200     
3201     /* Initialisation */
3202     TRACE(" setting current context\n");
3203     object->set_context(object);
3204     TRACE(" current context set\n");
3205
3206     /* allocate the clipping planes */
3207     glGetIntegerv(GL_MAX_CLIP_PLANES,&max_clipping_planes);
3208     if (max_clipping_planes>32) {
3209         object->max_clipping_planes=32;
3210     } else {
3211         object->max_clipping_planes = max_clipping_planes;
3212     }
3213     TRACE(" capable of %d clipping planes\n", (int)object->max_clipping_planes );
3214     object->clipping_planes = (d3d7clippingplane*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
3215
3216     glHint(GL_FOG_HINT,GL_NICEST);
3217     
3218     glClearColor(0.0, 0.0, 0.0, 0.0);
3219     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
3220     glDrawBuffer(buffer);
3221     glReadBuffer(buffer);
3222     /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
3223     LEAVE_GL();
3224
3225     gl_object->state = SURFACE_GL;
3226     
3227     /* fill_device_capabilities(d3d->ddraw); */    
3228     
3229     ICOM_INIT_INTERFACE(object, IDirect3DDevice,  VTABLE_IDirect3DDevice);
3230     ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
3231     ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
3232     ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
3233
3234     *obj = object;
3235
3236     TRACE(" creating implementation at %p.\n", *obj);
3237
3238     /* And finally warn D3D that this device is now present */
3239     object->d3d->d3d_added_device(object->d3d, object);
3240
3241     /* FIXME: Should handle other versions than just 7 */
3242     InitDefaultStateBlock(&object->state_block, 7);
3243     /* Apply default render state and texture stage state values */
3244     apply_render_state(object, &object->state_block);
3245     apply_texture_state(object);
3246
3247     /* And fill the fog table with the default fog value */
3248     build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
3249     
3250     return DD_OK;
3251 }