Rewrote the light management API to allow for an unlimited amount of
[wine] / dlls / ddraw / device_opengl.c
1 /* Direct3D Device
2  * Copyright (c) 1998-2004 Lionel ULMER
3  * Copyright (c) 2002-2004 Christian Costa
4  *
5  * This file contains the MESA implementation of all the D3D devices that
6  * Wine supports.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <math.h>
29
30 #define NONAMELESSUNION
31 #define NONAMELESSSTRUCT
32
33 #define CONST_VTABLE
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winerror.h"
38 #include "objbase.h"
39 #include "wingdi.h"
40 #include "ddraw.h"
41 #include "d3d.h"
42 #include "wine/debug.h"
43 #include "wine/library.h"
44
45 #include "d3d_private.h"
46 #include "opengl_private.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
49 WINE_DECLARE_DEBUG_CHANNEL(ddraw_geom);
50
51 /* x11drv GDI escapes */
52 #define X11DRV_ESCAPE 6789
53 enum x11drv_escape_codes
54 {
55     X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
56     X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
57     X11DRV_GET_FONT,      /* get current X font for a DC */
58 };
59
60 /* They are non-static as they are used by Direct3D in the creation function */
61 const GUID IID_D3DDEVICE_OpenGL = {
62   0x31416d44,
63   0x86ae,
64   0x11d2,
65   { 0x82,0x2d,0xa8,0xd5,0x31,0x87,0xca,0xfa }
66 };
67
68 const float id_mat[16] = {
69     1.0, 0.0, 0.0, 0.0,
70     0.0, 1.0, 0.0, 0.0,
71     0.0, 0.0, 1.0, 0.0,
72     0.0, 0.0, 0.0, 1.0
73 };
74
75 /* This is filled at DLL loading time */
76 static D3DDEVICEDESC7 opengl_device_caps;
77 GL_EXTENSIONS_LIST GL_extensions;
78
79 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
80                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
81                                    DWORD d3dvtVertexType,
82                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
83                                    DWORD dwVertexCount,
84                                    LPWORD dwIndices,
85                                    DWORD dwIndexCount,
86                                    DWORD dwFlags) ;
87
88 static DWORD draw_primitive_handle_textures(IDirect3DDeviceImpl *This);
89
90 /* retrieve the X display to use on a given DC */
91 inline static Display *get_display( HDC hdc )
92 {
93     Display *display;
94     enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
95
96     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
97                     sizeof(display), (LPSTR)&display )) display = NULL;
98
99     return display;
100 }
101
102 #define UNLOCK_TEX_SIZE 256
103
104 #define DEPTH_RANGE_BIT (0x00000001 << 0)
105 #define VIEWPORT_BIT    (0x00000001 << 1)
106
107 static DWORD d3ddevice_set_state_for_flush(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, BOOLEAN use_alpha, BOOLEAN *initial) {
108     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
109     DWORD opt_bitmap = 0x00000000;
110     
111     if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
112         ((d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE))) {
113         if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
114             GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
115             gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
116         }
117         /* Disable multi-texturing for level 1 to disable all others */
118         glDisable(GL_TEXTURE_2D);
119     }
120     if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
121         GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
122         gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
123     }
124     if ((gl_d3d_dev->current_bound_texture[0] == NULL) ||
125         (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE))
126         glEnable(GL_TEXTURE_2D);
127     if (gl_d3d_dev->unlock_tex == 0) {
128         glGenTextures(1, &gl_d3d_dev->unlock_tex);
129         glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
130         *initial = TRUE;
131         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
132         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
133         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
134         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
135     } else {
136         glBindTexture(GL_TEXTURE_2D, gl_d3d_dev->unlock_tex);
137         *initial = FALSE;
138     }
139     if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
140         glMatrixMode(GL_TEXTURE);
141         glLoadIdentity();
142     }
143     
144     if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
145         gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
146         d3ddevice_set_ortho(d3d_dev);
147     }
148     
149     if (gl_d3d_dev->depth_test != FALSE) glDisable(GL_DEPTH_TEST);
150     glEnable(GL_SCISSOR_TEST);
151     if ((d3d_dev->active_viewport.dvMinZ != 0.0) ||
152         (d3d_dev->active_viewport.dvMaxZ != 1.0)) {
153         glDepthRange(0.0, 1.0);
154         opt_bitmap |= DEPTH_RANGE_BIT;
155     }
156     if ((d3d_dev->active_viewport.dwX != 0) ||
157         (d3d_dev->active_viewport.dwY != 0) ||
158         (d3d_dev->active_viewport.dwWidth != d3d_dev->surface->surface_desc.dwWidth) ||
159         (d3d_dev->active_viewport.dwHeight != d3d_dev->surface->surface_desc.dwHeight)) {
160         glViewport(0, 0, d3d_dev->surface->surface_desc.dwWidth, d3d_dev->surface->surface_desc.dwHeight);
161         opt_bitmap |= VIEWPORT_BIT;
162     }
163     glScissor(pRect->left, d3d_dev->surface->surface_desc.dwHeight - pRect->bottom,
164               pRect->right - pRect->left, pRect->bottom - pRect->top);
165     if (gl_d3d_dev->lighting != FALSE) glDisable(GL_LIGHTING);
166     if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
167     if (use_alpha) {
168         if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
169         if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
170             glAlphaFunc(GL_NOTEQUAL, 0.0);
171     } else {
172         if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
173     }
174     if (gl_d3d_dev->stencil_test != FALSE) glDisable(GL_STENCIL_TEST);
175     if (gl_d3d_dev->blending != FALSE) glDisable(GL_BLEND);
176     if (gl_d3d_dev->fogging != FALSE) glDisable(GL_FOG);
177     if (gl_d3d_dev->current_tex_env != GL_REPLACE)
178         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
179     
180     return opt_bitmap;
181 }
182
183 static void d3ddevice_restore_state_after_flush(IDirect3DDeviceImpl *d3d_dev, DWORD opt_bitmap, BOOLEAN use_alpha) {
184     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
185
186     /* And restore all the various states modified by this code */
187     if (gl_d3d_dev->depth_test != 0) glEnable(GL_DEPTH_TEST);
188     if (gl_d3d_dev->lighting != 0) glEnable(GL_LIGHTING);
189     if ((gl_d3d_dev->alpha_test != 0) && (use_alpha == 0))
190         glEnable(GL_ALPHA_TEST);
191     else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
192         glDisable(GL_ALPHA_TEST);
193     if (use_alpha) {
194         if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
195             glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
196     }
197     if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
198     if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
199     if (gl_d3d_dev->blending != 0) glEnable(GL_BLEND);
200     if (gl_d3d_dev->fogging != 0) glEnable(GL_FOG);
201     glDisable(GL_SCISSOR_TEST);
202     if (opt_bitmap & DEPTH_RANGE_BIT) {
203         glDepthRange(d3d_dev->active_viewport.dvMinZ, d3d_dev->active_viewport.dvMaxZ);
204     }
205     if (opt_bitmap & VIEWPORT_BIT) {
206         glViewport(d3d_dev->active_viewport.dwX,
207                    d3d_dev->surface->surface_desc.dwHeight - (d3d_dev->active_viewport.dwHeight + d3d_dev->active_viewport.dwY),
208                    d3d_dev->active_viewport.dwWidth, d3d_dev->active_viewport.dwHeight);
209     }
210     if (d3d_dev->tex_mat_is_identity[0] == FALSE) {
211         d3d_dev->matrices_updated(d3d_dev, TEXMAT0_CHANGED);
212     }
213     
214     if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE0_WINE) {
215         GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
216         gl_d3d_dev->current_active_tex_unit = GL_TEXTURE0_WINE;
217     }
218     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, gl_d3d_dev->current_tex_env);
219     /* Note that here we could directly re-bind the previous texture... But it would in some case be a spurious
220        bind if ever the game changes the texture just after.
221
222        So choose 0x00000001 to postpone the binding to the next time we draw something on screen. */
223     gl_d3d_dev->current_bound_texture[0] = (IDirectDrawSurfaceImpl *) 0x00000001;
224     if (d3d_dev->state_block.texture_stage_state[0][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE) glDisable(GL_TEXTURE_2D);
225
226     /* And re-enabled if needed texture level 1 */
227     if ((gl_d3d_dev->current_bound_texture[1] != NULL) &&
228         (d3d_dev->state_block.texture_stage_state[1][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
229         if (gl_d3d_dev->current_active_tex_unit != GL_TEXTURE1_WINE) {
230             GL_extensions.glActiveTexture(GL_TEXTURE1_WINE);
231             gl_d3d_dev->current_active_tex_unit = GL_TEXTURE1_WINE;
232         }
233         glEnable(GL_TEXTURE_2D);
234     }
235 }
236
237 /* retrieve the X drawable to use on a given DC */
238 inline static Drawable get_drawable( HDC hdc )
239 {
240     Drawable drawable;
241     enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
242
243     if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
244                     sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
245
246     return drawable;
247 }
248
249 static BOOL opengl_flip( LPVOID dev, LPVOID drawable)
250 {
251     IDirect3DDeviceImpl *d3d_dev = (IDirect3DDeviceImpl *) dev;
252     IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) dev;
253
254     TRACE("(%p, %ld)\n", gl_d3d_dev->display,(Drawable)drawable);
255     ENTER_GL();
256     if (gl_d3d_dev->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
257         d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_BACK]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK]);
258     }
259     gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
260     gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
261     glXSwapBuffers(gl_d3d_dev->display, (Drawable)drawable);
262     LEAVE_GL();
263     
264     return TRUE;
265 }
266
267
268 /*******************************************************************************
269  *                              OpenGL static functions
270  */
271 static void set_context(IDirect3DDeviceImpl* This)
272 {
273     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
274    
275     TRACE("glxMakeCurrent %p, %ld, %p\n",glThis->display,glThis->drawable, glThis->gl_context);
276     ENTER_GL();
277     if (glXMakeCurrent(glThis->display, glThis->drawable, glThis->gl_context) == False) {
278         ERR("Error in setting current context (context %p drawable %ld)!\n",
279             glThis->gl_context, glThis->drawable);
280     }
281     LEAVE_GL();
282 }
283
284 static void fill_opengl_caps(D3DDEVICEDESC *d1)
285 {
286     d1->dwSize  = sizeof(*d1);
287     d1->dwFlags = D3DDD_COLORMODEL | D3DDD_DEVCAPS | D3DDD_TRANSFORMCAPS | D3DDD_BCLIPPING | D3DDD_LIGHTINGCAPS |
288         D3DDD_LINECAPS | D3DDD_TRICAPS | D3DDD_DEVICERENDERBITDEPTH | D3DDD_DEVICEZBUFFERBITDEPTH |
289         D3DDD_MAXBUFFERSIZE | D3DDD_MAXVERTEXCOUNT;
290     d1->dcmColorModel = D3DCOLOR_RGB;
291     d1->dwDevCaps = opengl_device_caps.dwDevCaps;
292     d1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
293     d1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
294     d1->bClipping = TRUE;
295     d1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
296     d1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL | D3DLIGHTCAPS_PARALLELPOINT | D3DLIGHTCAPS_POINT | D3DLIGHTCAPS_SPOT;
297     d1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
298     d1->dlcLightingCaps.dwNumLights = opengl_device_caps.dwMaxActiveLights;
299     d1->dpcLineCaps = opengl_device_caps.dpcLineCaps;
300     d1->dpcTriCaps = opengl_device_caps.dpcTriCaps;
301     d1->dwDeviceRenderBitDepth  = opengl_device_caps.dwDeviceRenderBitDepth;
302     d1->dwDeviceZBufferBitDepth = opengl_device_caps.dwDeviceZBufferBitDepth;
303     d1->dwMaxBufferSize = 0;
304     d1->dwMaxVertexCount = 65536;
305     d1->dwMinTextureWidth  = opengl_device_caps.dwMinTextureWidth;
306     d1->dwMinTextureHeight = opengl_device_caps.dwMinTextureHeight;
307     d1->dwMaxTextureWidth  = opengl_device_caps.dwMaxTextureWidth;
308     d1->dwMaxTextureHeight = opengl_device_caps.dwMaxTextureHeight;
309     d1->dwMinStippleWidth  = 1;
310     d1->dwMinStippleHeight = 1;
311     d1->dwMaxStippleWidth  = 32;
312     d1->dwMaxStippleHeight = 32;
313     d1->dwMaxTextureRepeat = opengl_device_caps.dwMaxTextureRepeat;
314     d1->dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureAspectRatio;
315     d1->dwMaxAnisotropy = opengl_device_caps.dwMaxAnisotropy;
316     d1->dvGuardBandLeft = opengl_device_caps.dvGuardBandLeft;
317     d1->dvGuardBandRight = opengl_device_caps.dvGuardBandRight;
318     d1->dvGuardBandTop = opengl_device_caps.dvGuardBandTop;
319     d1->dvGuardBandBottom = opengl_device_caps.dvGuardBandBottom;
320     d1->dvExtentsAdjust = opengl_device_caps.dvExtentsAdjust;
321     d1->dwStencilCaps = opengl_device_caps.dwStencilCaps;
322     d1->dwFVFCaps = opengl_device_caps.dwFVFCaps;
323     d1->dwTextureOpCaps = opengl_device_caps.dwTextureOpCaps;
324     d1->wMaxTextureBlendStages = opengl_device_caps.wMaxTextureBlendStages;
325     d1->wMaxSimultaneousTextures = opengl_device_caps.wMaxSimultaneousTextures;
326 }
327
328 static void fill_opengl_caps_7(D3DDEVICEDESC7 *d)
329 {
330     *d = opengl_device_caps;
331 }
332
333 HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version)
334 {
335     D3DDEVICEDESC dref, d1, d2;
336     HRESULT ret_value;
337
338     /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
339        Let's put the string in a sufficiently sized array in writable memory. */
340     char device_name[50];
341     strcpy(device_name,"direct3d");
342
343     fill_opengl_caps(&dref);
344
345     if (version > 1) {
346         /* It seems that enumerating the reference IID on Direct3D 1 games (AvP / Motoracer2) breaks them */
347         char interface_name[] = "WINE Reference Direct3DX using OpenGL";
348         TRACE(" enumerating OpenGL D3DDevice interface using reference IID (IID %s).\n", debugstr_guid(&IID_IDirect3DRefDevice));
349         d1 = dref;
350         d2 = dref;
351         ret_value = cb((LPIID) &IID_IDirect3DRefDevice, interface_name, device_name, &d1, &d2, context);
352         if (ret_value != D3DENUMRET_OK)
353             return ret_value;
354     }
355
356     {
357         char interface_name[] = "WINE Direct3DX using OpenGL";
358         TRACE(" enumerating OpenGL D3DDevice interface (IID %s).\n", debugstr_guid(&IID_D3DDEVICE_OpenGL));
359         d1 = dref;
360         d2 = dref;
361         ret_value = cb((LPIID) &IID_D3DDEVICE_OpenGL, interface_name, device_name, &d1, &d2, context);
362         if (ret_value != D3DENUMRET_OK)
363             return ret_value;
364     }
365
366     return D3DENUMRET_OK;
367 }
368
369 HRESULT d3ddevice_enumerate7(LPD3DENUMDEVICESCALLBACK7 cb, LPVOID context)
370 {
371     D3DDEVICEDESC7 ddesc;
372     char interface_name[] = "WINE Direct3D7 using OpenGL";
373     char device_name[] = "Wine D3D7 device";
374
375     fill_opengl_caps_7(&ddesc);
376     
377     TRACE(" enumerating OpenGL D3DDevice7 interface.\n");
378     
379     return cb(interface_name, device_name, &ddesc, context);
380 }
381
382 ULONG WINAPI
383 GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release(LPDIRECT3DDEVICE7 iface)
384 {
385     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
386     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
387     ULONG ref = InterlockedDecrement(&This->ref);
388     
389     TRACE("(%p/%p)->() decrementing from %lu.\n", This, iface, ref + 1);
390
391     if (!ref) {
392         int i;
393         IDirectDrawSurfaceImpl *surface = This->surface, *surf;
394         
395         /* Release texture associated with the device */ 
396         for (i = 0; i < MAX_TEXTURES; i++) {
397             if (This->current_texture[i] != NULL)
398                 IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
399             HeapFree(GetProcessHeap(), 0, This->tex_mat[i]);
400         }
401
402         /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
403         for (surf = surface; surf != NULL; surf = surf->surface_owner) {
404             if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
405                 surf->aux_ctx  = NULL;
406                 surf->aux_data = NULL;
407                 surf->aux_flip = NULL;
408                 break;
409             }
410         }
411         for (surf = surface; surf != NULL; surf = surf->surface_owner) {
412             IDirectDrawSurfaceImpl *surf2;
413             for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
414             for (; surf2 != NULL; surf2 = surf2->next_attached) {
415                 if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
416                     ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
417                     /* Override the Lock / Unlock function for all these surfaces */
418                     surf2->lock_update = surf2->lock_update_prev;
419                     surf2->unlock_update = surf2->unlock_update_prev;
420                     /* And install also the blt / bltfast overrides */
421                     surf2->aux_blt = NULL;
422                     surf2->aux_bltfast = NULL;
423                 }
424                 surf2->d3ddevice = NULL;
425             }
426         }
427         
428         /* And warn the D3D object that this device is no longer active... */
429         This->d3d->d3d_removed_device(This->d3d, This);
430
431         /* Free light arrays */
432         if (This->light_parameters)
433             HeapFree(GetProcessHeap(), 0, This->light_parameters);
434         HeapFree(GetProcessHeap(), 0, This->active_lights);
435
436         HeapFree(GetProcessHeap(), 0, This->world_mat);
437         HeapFree(GetProcessHeap(), 0, This->view_mat);
438         HeapFree(GetProcessHeap(), 0, This->proj_mat);
439
440         if (glThis->surface_ptr)
441             HeapFree(GetProcessHeap(), 0, glThis->surface_ptr);
442
443         DeleteCriticalSection(&(This->crit));
444         
445         ENTER_GL();
446         if (glThis->unlock_tex)
447             glDeleteTextures(1, &(glThis->unlock_tex));
448         glXDestroyContext(glThis->display, glThis->gl_context);
449         LEAVE_GL();
450         HeapFree(GetProcessHeap(), 0, This->clipping_planes);
451
452         HeapFree(GetProcessHeap(), 0, This);
453         return 0;
454     }
455     return ref;
456 }
457
458 HRESULT WINAPI
459 GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps(LPDIRECT3DDEVICE3 iface,
460                                        LPD3DDEVICEDESC lpD3DHWDevDesc,
461                                        LPD3DDEVICEDESC lpD3DHELDevDesc)
462 {
463     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
464     D3DDEVICEDESC desc;
465     DWORD dwSize;
466
467     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DHWDevDesc, lpD3DHELDevDesc);
468
469     fill_opengl_caps(&desc);
470     dwSize = lpD3DHWDevDesc->dwSize;
471     memset(lpD3DHWDevDesc, 0, dwSize);
472     memcpy(lpD3DHWDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
473
474     dwSize = lpD3DHELDevDesc->dwSize;
475     memset(lpD3DHELDevDesc, 0, dwSize);
476     memcpy(lpD3DHELDevDesc, &desc, (dwSize <= desc.dwSize ? dwSize : desc.dwSize));
477
478     TRACE(" returning caps : (no dump function yet)\n");
479
480     return DD_OK;
481 }
482
483 static HRESULT enum_texture_format_OpenGL(LPD3DENUMTEXTUREFORMATSCALLBACK cb_1,
484                                           LPD3DENUMPIXELFORMATSCALLBACK cb_2,
485                                           LPVOID context, int version)
486 {
487     DDSURFACEDESC sdesc;
488     LPDDPIXELFORMAT pformat;
489
490     /* Do the texture enumeration */
491     sdesc.dwSize = sizeof(DDSURFACEDESC);
492     sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
493     sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
494     pformat = &(sdesc.ddpfPixelFormat);
495     pformat->dwSize = sizeof(DDPIXELFORMAT);
496     pformat->dwFourCC = 0;
497
498     TRACE("Enumerating GL_RGBA unpacked (32)\n");
499     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
500     pformat->u1.dwRGBBitCount = 32;
501     pformat->u2.dwRBitMask =        0x00FF0000;
502     pformat->u3.dwGBitMask =        0x0000FF00;
503     pformat->u4.dwBBitMask =        0x000000FF;
504     pformat->u5.dwRGBAlphaBitMask = 0xFF000000;
505     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
506     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
507
508     TRACE("Enumerating GL_RGB unpacked (32)\n");
509     pformat->dwFlags = DDPF_RGB;
510     pformat->u1.dwRGBBitCount = 32;
511     pformat->u2.dwRBitMask =        0x00FF0000;
512     pformat->u3.dwGBitMask =        0x0000FF00;
513     pformat->u4.dwBBitMask =        0x000000FF;
514     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
515     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
516     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
517     
518     TRACE("Enumerating GL_RGB unpacked (24)\n");
519     pformat->dwFlags = DDPF_RGB;
520     pformat->u1.dwRGBBitCount = 24;
521     pformat->u2.dwRBitMask = 0x00FF0000;
522     pformat->u3.dwGBitMask = 0x0000FF00;
523     pformat->u4.dwBBitMask = 0x000000FF;
524     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
525     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
526     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
527
528     /* Note : even if this is an 'emulated' texture format, it needs to be first
529               as some dumb applications seem to rely on that. */
530     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_1_5_5_5 (ARGB) (16)\n");
531     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
532     pformat->u1.dwRGBBitCount = 16;
533     pformat->u2.dwRBitMask =        0x00007C00;
534     pformat->u3.dwGBitMask =        0x000003E0;
535     pformat->u4.dwBBitMask =        0x0000001F;
536     pformat->u5.dwRGBAlphaBitMask = 0x00008000;
537     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
538     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
539
540     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (ARGB) (16)\n");
541     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
542     pformat->u1.dwRGBBitCount = 16;
543     pformat->u2.dwRBitMask =        0x00000F00;
544     pformat->u3.dwGBitMask =        0x000000F0;
545     pformat->u4.dwBBitMask =        0x0000000F;
546     pformat->u5.dwRGBAlphaBitMask = 0x0000F000;
547     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
548     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
549
550     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_6_5 (16)\n");
551     pformat->dwFlags = DDPF_RGB;
552     pformat->u1.dwRGBBitCount = 16;
553     pformat->u2.dwRBitMask = 0x0000F800;
554     pformat->u3.dwGBitMask = 0x000007E0;
555     pformat->u4.dwBBitMask = 0x0000001F;
556     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
557     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
558     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
559
560     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_SHORT_5_5_5 (16)\n");
561     pformat->dwFlags = DDPF_RGB;
562     pformat->u1.dwRGBBitCount = 16;
563     pformat->u2.dwRBitMask = 0x00007C00;
564     pformat->u3.dwGBitMask = 0x000003E0;
565     pformat->u4.dwBBitMask = 0x0000001F;
566     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
567     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
568     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
569     
570 #if 0
571     /* This is a compromise : some games choose the first 16 bit texture format with alpha they
572        find enumerated, others the last one. And both want to have the ARGB one.
573        
574        So basically, forget our OpenGL roots and do not even enumerate our RGBA ones.
575     */
576     /* See argument about the RGBA format for 'packed' texture formats */
577     TRACE("Enumerating GL_RGBA unpacked (32)\n");
578     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
579     pformat->u1.dwRGBBitCount = 32;
580     pformat->u2.dwRBitMask =        0xFF000000;
581     pformat->u3.dwGBitMask =        0x00FF0000;
582     pformat->u4.dwBBitMask =        0x0000FF00;
583     pformat->u5.dwRGBAlphaBitMask = 0x000000FF;
584     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
585     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
586     
587     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_4_4_4_4 (16)\n");
588     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
589     pformat->u1.dwRGBBitCount = 16;
590     pformat->u2.dwRBitMask =        0x0000F000;
591     pformat->u3.dwGBitMask =        0x00000F00;
592     pformat->u4.dwBBitMask =        0x000000F0;
593     pformat->u5.dwRGBAlphaBitMask = 0x0000000F;
594     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
595     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
596
597     TRACE("Enumerating GL_RGBA packed GL_UNSIGNED_SHORT_5_5_5_1 (16)\n");
598     pformat->dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
599     pformat->u1.dwRGBBitCount = 16;
600     pformat->u2.dwRBitMask =        0x0000F800;
601     pformat->u3.dwGBitMask =        0x000007C0;
602     pformat->u4.dwBBitMask =        0x0000003E;
603     pformat->u5.dwRGBAlphaBitMask = 0x00000001;
604     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
605     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
606 #endif
607
608     TRACE("Enumerating GL_RGB packed GL_UNSIGNED_BYTE_3_3_2 (8)\n");
609     pformat->dwFlags = DDPF_RGB;
610     pformat->u1.dwRGBBitCount = 8;
611     pformat->u2.dwRBitMask =        0x000000E0;
612     pformat->u3.dwGBitMask =        0x0000001C;
613     pformat->u4.dwBBitMask =        0x00000003;
614     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
615     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
616     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
617
618     TRACE("Enumerating Paletted (8)\n");
619     pformat->dwFlags = DDPF_PALETTEINDEXED8;
620     pformat->u1.dwRGBBitCount = 8;
621     pformat->u2.dwRBitMask =        0x00000000;
622     pformat->u3.dwGBitMask =        0x00000000;
623     pformat->u4.dwBBitMask =        0x00000000;
624     pformat->u5.dwRGBAlphaBitMask = 0x00000000;
625     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
626     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
627
628     /* DXT textures only exist for devices created from IDirect3D3 and above */
629     if ((version >= 3) && GL_extensions.s3tc_compressed_texture) {
630         TRACE("Enumerating DXT1\n");
631         pformat->dwFlags = DDPF_FOURCC;
632         pformat->dwFourCC = MAKE_FOURCC('D','X','T','1');
633         if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
634         if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
635
636         TRACE("Enumerating DXT3\n");
637         pformat->dwFlags = DDPF_FOURCC;
638         pformat->dwFourCC = MAKE_FOURCC('D','X','T','3');
639         if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
640         if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
641
642         TRACE("Enumerating DXT5\n");
643         pformat->dwFlags = DDPF_FOURCC;
644         pformat->dwFourCC = MAKE_FOURCC('D','X','T','5');
645         if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
646         if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
647     }
648
649     TRACE("End of enumeration\n");
650     return DD_OK;
651 }
652
653
654 HRESULT
655 d3ddevice_find(IDirectDrawImpl *d3d,
656                LPD3DFINDDEVICESEARCH lpD3DDFS,
657                LPD3DFINDDEVICERESULT lplpD3DDevice)
658 {
659     D3DDEVICEDESC desc;
660   
661     if ((lpD3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
662         (lpD3DDFS->dcmColorModel != D3DCOLOR_RGB)) {
663         TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
664         return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
665     }
666     if (lpD3DDFS->dwFlags & D3DFDS_GUID) {
667         TRACE(" trying to match guid %s.\n", debugstr_guid(&(lpD3DDFS->guid)));
668         if ((IsEqualGUID(&IID_D3DDEVICE_OpenGL, &(lpD3DDFS->guid)) == 0) &&
669             (IsEqualGUID(&IID_IDirect3DHALDevice, &(lpD3DDFS->guid)) == 0) &&
670             (IsEqualGUID(&IID_IDirect3DRefDevice, &(lpD3DDFS->guid)) == 0)) {
671             TRACE(" no match for this GUID.\n");
672             return DDERR_INVALIDPARAMS;
673         }
674     }
675
676     /* Now return our own GUID */
677     lplpD3DDevice->guid = IID_D3DDEVICE_OpenGL;
678     fill_opengl_caps(&desc);
679     lplpD3DDevice->ddHwDesc = desc;
680     lplpD3DDevice->ddSwDesc = desc;
681
682     TRACE(" returning Wine's OpenGL device with (undumped) capabilities\n");
683     
684     return D3D_OK;
685 }
686
687 HRESULT WINAPI
688 GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats(LPDIRECT3DDEVICE2 iface,
689                                                LPD3DENUMTEXTUREFORMATSCALLBACK lpD3DEnumTextureProc,
690                                                LPVOID lpArg)
691 {
692     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
693     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumTextureProc, lpArg);
694     return enum_texture_format_OpenGL(lpD3DEnumTextureProc, NULL, lpArg, This->version);
695 }
696
697 HRESULT WINAPI
698 GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats(LPDIRECT3DDEVICE7 iface,
699                                                LPD3DENUMPIXELFORMATSCALLBACK lpD3DEnumPixelProc,
700                                                LPVOID lpArg)
701 {
702     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
703     TRACE("(%p/%p)->(%p,%p)\n", This, iface, lpD3DEnumPixelProc, lpArg);
704     return enum_texture_format_OpenGL(NULL, lpD3DEnumPixelProc, lpArg, This->version);
705 }
706
707 HRESULT WINAPI
708 GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState(LPDIRECT3DDEVICE7 iface,
709                                               D3DRENDERSTATETYPE dwRenderStateType,
710                                               DWORD dwRenderState)
711 {
712     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
713     TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwRenderStateType, dwRenderState);
714
715     /* Call the render state functions */
716     store_render_state(This, dwRenderStateType, dwRenderState, &This->state_block);
717     set_render_state(This, dwRenderStateType, &This->state_block);
718
719     return DD_OK;
720 }
721
722 HRESULT WINAPI
723 GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState(LPDIRECT3DDEVICE7 iface,
724                                               D3DRENDERSTATETYPE dwRenderStateType,
725                                               LPDWORD lpdwRenderState)
726 {
727     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
728     TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwRenderStateType, lpdwRenderState);
729
730     /* Call the render state functions */
731     get_render_state(This, dwRenderStateType, lpdwRenderState, &This->state_block);
732
733     TRACE(" - asked for rendering state : %s, returning value %08lx.\n", _get_renderstate(dwRenderStateType), *lpdwRenderState);
734
735     return DD_OK;
736 }
737
738 HRESULT WINAPI
739 GL_IDirect3DDeviceImpl_3_2T_GetLightState(LPDIRECT3DDEVICE3 iface,
740                                           D3DLIGHTSTATETYPE dwLightStateType,
741                                           LPDWORD lpdwLightState)
742 {
743     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
744     
745     TRACE("(%p/%p)->(%08x,%p)\n", This, iface, dwLightStateType, lpdwLightState);
746
747     if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
748         TRACE("Unexpected Light State Type\n");
749         return DDERR_INVALIDPARAMS;
750     }
751         
752     if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
753         *lpdwLightState = This->material;
754     } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
755         *lpdwLightState = D3DCOLOR_RGB;
756     } else {
757         D3DRENDERSTATETYPE rs;
758         switch (dwLightStateType) {
759             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
760                 rs = D3DRENDERSTATE_AMBIENT;
761                 break;          
762             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
763                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
764                 break;
765             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
766                 rs = D3DRENDERSTATE_FOGSTART;
767                 break;
768             case D3DLIGHTSTATE_FOGEND:        /* 6 */
769                 rs = D3DRENDERSTATE_FOGEND;
770                 break;
771             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
772                 rs = D3DRENDERSTATE_FOGDENSITY;
773                 break;
774             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
775                 rs = D3DRENDERSTATE_COLORVERTEX;
776                 break;
777             default:
778                 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
779                 return DDERR_INVALIDPARAMS;
780         }
781
782         IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
783                                         rs,lpdwLightState);
784     }
785
786     return DD_OK;
787 }
788
789 HRESULT WINAPI
790 GL_IDirect3DDeviceImpl_3_2T_SetLightState(LPDIRECT3DDEVICE3 iface,
791                                           D3DLIGHTSTATETYPE dwLightStateType,
792                                           DWORD dwLightState)
793 {
794     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
795     
796     TRACE("(%p/%p)->(%08x,%08lx)\n", This, iface, dwLightStateType, dwLightState);
797
798     if (!dwLightStateType && (dwLightStateType > D3DLIGHTSTATE_COLORVERTEX)) {
799         TRACE("Unexpected Light State Type\n");
800         return DDERR_INVALIDPARAMS;
801     }
802         
803     if (dwLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
804         IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) dwLightState;
805
806         if (mat != NULL) {
807             TRACE(" activating material %p.\n", mat);
808             mat->activate(mat);
809         } else {
810             FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
811         }
812         This->material = dwLightState;
813     } else if (dwLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
814         switch (dwLightState) {
815             case D3DCOLOR_MONO:
816                ERR("DDCOLOR_MONO should not happen!\n");
817                break;
818             case D3DCOLOR_RGB:
819                /* We are already in this mode */
820                TRACE("Setting color model to RGB (no-op).\n");
821                break;
822             default:
823                ERR("Unknown color model!\n");
824                return DDERR_INVALIDPARAMS;
825         }
826     } else {
827         D3DRENDERSTATETYPE rs;
828         switch (dwLightStateType) {
829             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
830                 rs = D3DRENDERSTATE_AMBIENT;
831                 break;          
832             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
833                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
834                 break;
835             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
836                 rs = D3DRENDERSTATE_FOGSTART;
837                 break;
838             case D3DLIGHTSTATE_FOGEND:        /* 6 */
839                 rs = D3DRENDERSTATE_FOGEND;
840                 break;
841             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
842                 rs = D3DRENDERSTATE_FOGDENSITY;
843                 break;
844             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
845                 rs = D3DRENDERSTATE_COLORVERTEX;
846                 break;
847             default:
848                 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", dwLightStateType);
849                 return DDERR_INVALIDPARAMS;
850         }
851
852         IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7),
853                                         rs,dwLightState);
854     }
855
856     return DD_OK;
857 }
858
859 static GLenum convert_D3D_ptype_to_GL(D3DPRIMITIVETYPE d3dpt)
860 {
861     switch (d3dpt) {
862         case D3DPT_POINTLIST:
863             TRACE(" primitive type is POINTS\n");
864             return GL_POINTS;
865
866         case D3DPT_LINELIST:
867             TRACE(" primitive type is LINES\n");
868             return GL_LINES;
869                 
870         case D3DPT_LINESTRIP:
871             TRACE(" primitive type is LINE_STRIP\n");
872             return GL_LINE_STRIP;
873             
874         case D3DPT_TRIANGLELIST:
875             TRACE(" primitive type is TRIANGLES\n");
876             return GL_TRIANGLES;
877             
878         case D3DPT_TRIANGLESTRIP:
879             TRACE(" primitive type is TRIANGLE_STRIP\n");
880             return GL_TRIANGLE_STRIP;
881             
882         case D3DPT_TRIANGLEFAN:
883             TRACE(" primitive type is TRIANGLE_FAN\n");
884             return GL_TRIANGLE_FAN;
885             
886         default:
887             FIXME("Unhandled primitive %08x\n", d3dpt);
888             return GL_POINTS;
889     }
890 }
891
892 /* This function calculate the Z coordinate from Zproj */ 
893 static float ZfromZproj(IDirect3DDeviceImpl *This, D3DVALUE Zproj)
894 {
895     float a,b,c,d;
896     /* Assume that X = Y = 0 and W = 1 */
897     a = This->proj_mat->_33;
898     b = This->proj_mat->_34;
899     c = This->proj_mat->_43;
900     d = This->proj_mat->_44;
901     /* We have in homogenous coordinates Z' = a * Z + c and W' = b * Z + d
902      * So in non homogenous coordinates we have Zproj = (a * Z + c) / (b * Z + d)
903      * And finally Z = (d * Zproj - c) / (a - b * Zproj)
904      */
905     return (d*Zproj - c) / (a - b*Zproj);
906 }
907
908 static void build_fog_table(BYTE *fog_table, DWORD fog_color) {
909     int i;
910     
911     TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF);
912     
913     for (i = 0; i < 3; i++) {
914         BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF;
915         DWORD elt;
916         for (elt = 0; elt < 0x10000; elt++) {
917             /* We apply the fog transformation and cache the result */
918             DWORD fog_intensity = elt & 0xFF;
919             DWORD vertex_color = (elt >> 8) & 0xFF;
920             fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF;
921         }
922     }
923 }
924
925 static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This,
926                                            BOOLEAN vertex_transformed,
927                                            BOOLEAN vertex_lit) {
928     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
929   
930     /* Puts GL in the correct lighting / transformation mode */
931     if ((vertex_transformed == FALSE) && 
932         (glThis->transform_state != GL_TRANSFORM_NORMAL)) {
933         /* Need to put the correct transformation again if we go from Transformed
934            vertices to non-transformed ones.
935         */
936         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
937                            This->world_mat, This->view_mat, This->proj_mat);
938         glThis->transform_state = GL_TRANSFORM_NORMAL;
939
940     } else if (vertex_transformed &&
941                (glThis->transform_state != GL_TRANSFORM_ORTHO)) {
942         /* Set our orthographic projection */
943         if (glThis->transform_state != GL_TRANSFORM_ORTHO) {
944             glThis->transform_state = GL_TRANSFORM_ORTHO;
945             d3ddevice_set_ortho(This);
946         }
947     }
948
949     /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call
950              if no fogging state change occurred */
951     if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
952         if (vertex_transformed) {
953             if (glThis->fogging != 0) {
954                 glDisable(GL_FOG);
955                 glThis->fogging = 0;
956             }
957             /* Now check if our fog_table still corresponds to the current vertex color.
958                Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */
959             if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >>  0) & 0xFF)) ||
960                 (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >>  8) & 0xFF)) ||
961                 (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) {
962                 /* We need to rebuild our fog table.... */
963                 build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
964             }
965         } else {
966             if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) {
967                 switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) {
968                     case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break; 
969                     case D3DFOG_EXP:    glFogi(GL_FOG_MODE, GL_EXP); break; 
970                     case D3DFOG_EXP2:   glFogi(GL_FOG_MODE, GL_EXP2); break;
971                 }
972                 if (vertex_lit == FALSE) {
973                     glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]);
974                     glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]);
975                 } else {
976                     /* Special case of 'pixel fog' */
977                     glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]));
978                     glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]));
979                 }
980                 if (glThis->fogging == 0) {
981                     glEnable(GL_FOG);
982                     glThis->fogging = 1;
983                 }
984             } else {
985                 if (glThis->fogging != 0) {
986                     glDisable(GL_FOG);
987                     glThis->fogging = 0;
988                 }
989             }
990         }
991     } else {
992         if (glThis->fogging != 0) {
993             glDisable(GL_FOG);
994             glThis->fogging = 0;
995         }
996     }
997     
998     /* Handle the 'no-normal' case */
999     if ((vertex_lit == FALSE) && This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1000         if (glThis->lighting == 0) {
1001             glEnable(GL_LIGHTING);
1002             glThis->lighting = 1;
1003         }
1004     } else {
1005         if (glThis->lighting != 0) {
1006             glDisable(GL_LIGHTING);
1007             glThis->lighting = 0;
1008         }
1009     }
1010
1011     /* Handle the code for pre-vertex material properties */
1012     if (vertex_transformed == FALSE) {
1013         if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1014             This->state_block.render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1015             if ((This->state_block.render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1016                 (This->state_block.render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1017                 (This->state_block.render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] != D3DMCS_MATERIAL) ||
1018                 (This->state_block.render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] != D3DMCS_MATERIAL)) {
1019                 glEnable(GL_COLOR_MATERIAL);
1020             }
1021         }
1022     }
1023 }
1024
1025
1026 inline static void draw_primitive(IDirect3DDeviceImpl *This, DWORD maxvert, WORD *index,
1027                                   D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex)
1028 {
1029     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1030
1031     switch (d3dvt) {
1032         case D3DVT_VERTEX: {
1033             strided.position.lpvData = &((D3DVERTEX *) lpvertex)->u1.x;
1034             strided.position.dwStride = sizeof(D3DVERTEX);
1035             strided.normal.lpvData = &((D3DVERTEX *) lpvertex)->u4.nx;
1036             strided.normal.dwStride = sizeof(D3DVERTEX);
1037             strided.textureCoords[0].lpvData = &((D3DVERTEX *) lpvertex)->u7.tu;
1038             strided.textureCoords[0].dwStride = sizeof(D3DVERTEX);
1039             draw_primitive_strided(This, d3dpt, D3DFVF_VERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1040         } break;
1041
1042         case D3DVT_LVERTEX: {
1043             strided.position.lpvData = &((D3DLVERTEX *) lpvertex)->u1.x;
1044             strided.position.dwStride = sizeof(D3DLVERTEX);
1045             strided.diffuse.lpvData = &((D3DLVERTEX *) lpvertex)->u4.color;
1046             strided.diffuse.dwStride = sizeof(D3DLVERTEX);
1047             strided.specular.lpvData = &((D3DLVERTEX *) lpvertex)->u5.specular;
1048             strided.specular.dwStride = sizeof(D3DLVERTEX);
1049             strided.textureCoords[0].lpvData = &((D3DLVERTEX *) lpvertex)->u6.tu;
1050             strided.textureCoords[0].dwStride = sizeof(D3DLVERTEX);
1051             draw_primitive_strided(This, d3dpt, D3DFVF_LVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1052         } break;
1053
1054         case D3DVT_TLVERTEX: {
1055             strided.position.lpvData = &((D3DTLVERTEX *) lpvertex)->u1.sx;
1056             strided.position.dwStride = sizeof(D3DTLVERTEX);
1057             strided.diffuse.lpvData = &((D3DTLVERTEX *) lpvertex)->u5.color;
1058             strided.diffuse.dwStride = sizeof(D3DTLVERTEX);
1059             strided.specular.lpvData = &((D3DTLVERTEX *) lpvertex)->u6.specular;
1060             strided.specular.dwStride = sizeof(D3DTLVERTEX);
1061             strided.textureCoords[0].lpvData = &((D3DTLVERTEX *) lpvertex)->u7.tu;
1062             strided.textureCoords[0].dwStride = sizeof(D3DTLVERTEX);
1063             draw_primitive_strided(This, d3dpt, D3DFVF_TLVERTEX, &strided, 0 /* Unused */, index, maxvert, 0 /* Unused */);
1064         } break;
1065
1066         default:
1067             FIXME("Unhandled vertex type %08x\n", d3dvt);
1068             break;
1069     }
1070 }
1071
1072 HRESULT WINAPI
1073 GL_IDirect3DDeviceImpl_2_DrawPrimitive(LPDIRECT3DDEVICE2 iface,
1074                                        D3DPRIMITIVETYPE d3dptPrimitiveType,
1075                                        D3DVERTEXTYPE d3dvtVertexType,
1076                                        LPVOID lpvVertices,
1077                                        DWORD dwVertexCount,
1078                                        DWORD dwFlags)
1079 {
1080     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1081
1082     TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1083     if (TRACE_ON(ddraw)) {
1084         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1085     }
1086
1087     draw_primitive(This, dwVertexCount, NULL, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1088                    
1089     return DD_OK;
1090 }
1091
1092 HRESULT WINAPI
1093 GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(LPDIRECT3DDEVICE2 iface,
1094                                               D3DPRIMITIVETYPE d3dptPrimitiveType,
1095                                               D3DVERTEXTYPE d3dvtVertexType,
1096                                               LPVOID lpvVertices,
1097                                               DWORD dwVertexCount,
1098                                               LPWORD dwIndices,
1099                                               DWORD dwIndexCount,
1100                                               DWORD dwFlags)
1101 {
1102     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
1103     TRACE("(%p/%p)->(%08x,%08x,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1104     if (TRACE_ON(ddraw)) {
1105         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1106     }
1107
1108     draw_primitive(This, dwIndexCount, dwIndices, d3dvtVertexType, d3dptPrimitiveType, lpvVertices);
1109     
1110     return DD_OK;
1111 }
1112
1113 HRESULT WINAPI
1114 GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer(LPDIRECT3DDEVICE iface,
1115                                              LPD3DEXECUTEBUFFERDESC lpDesc,
1116                                              LPDIRECT3DEXECUTEBUFFER* lplpDirect3DExecuteBuffer,
1117                                              IUnknown* pUnkOuter)
1118 {
1119     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
1120     IDirect3DExecuteBufferImpl *ret;
1121     HRESULT ret_value;
1122     
1123     TRACE("(%p/%p)->(%p,%p,%p)\n", This, iface, lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
1124
1125     ret_value = d3dexecutebuffer_create(&ret, This->d3d, This, lpDesc);
1126     *lplpDirect3DExecuteBuffer = ICOM_INTERFACE(ret, IDirect3DExecuteBuffer);
1127
1128     TRACE(" returning %p.\n", *lplpDirect3DExecuteBuffer);
1129     
1130     return ret_value;
1131 }
1132
1133 static void flush_zbuffer_to_GL(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
1134     static BOOLEAN first = TRUE;
1135     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
1136     unsigned int row;
1137     GLenum type;
1138     
1139     if (first) {
1140         MESSAGE("Warning : application does direct locking of ZBuffer - expect slowdowns on many GL implementations :-)\n");
1141         first = FALSE;
1142     }
1143     
1144     TRACE("flushing ZBuffer back to GL\n");
1145     
1146     if (gl_d3d_dev->transform_state != GL_TRANSFORM_ORTHO) {
1147         gl_d3d_dev->transform_state = GL_TRANSFORM_ORTHO;
1148         d3ddevice_set_ortho(d3d_dev);
1149     }
1150     
1151     glMatrixMode(GL_MODELVIEW);
1152     glLoadIdentity();
1153
1154     if (gl_d3d_dev->depth_test == 0) glEnable(GL_DEPTH_TEST);
1155     if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS) glDepthFunc(GL_ALWAYS);
1156     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 
1157
1158     /* This loop here is to prevent using PixelZoom that may be unoptimized for the 1.0 / -1.0 case
1159        in some drivers...
1160     */
1161     switch (surf->surface_desc.u4.ddpfPixelFormat.u1.dwZBufferBitDepth) {
1162         case 16: type = GL_UNSIGNED_SHORT; break;
1163         case 32: type = GL_UNSIGNED_INT; break;
1164         default: FIXME("Unhandled ZBuffer format !\n"); goto restore_state;
1165     }
1166         
1167     for (row = 0; row < surf->surface_desc.dwHeight; row++) {
1168         /* glRasterPos3d(0.0, row + 1.0, 0.5); */
1169         glRasterPos2i(0, row + 1);
1170         glDrawPixels(surf->surface_desc.dwWidth, 1, GL_DEPTH_COMPONENT, type,
1171                      ((unsigned char *) surf->surface_desc.lpSurface) + (row * surf->surface_desc.u1.lPitch));
1172     }
1173
1174   restore_state:
1175     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1176     if (d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1] != D3DCMP_ALWAYS)
1177         glDepthFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ZFUNC - 1]));
1178     if (gl_d3d_dev->depth_test == 0) glDisable(GL_DEPTH_TEST);
1179 }
1180
1181 /* These are the various handler used in the generic path */
1182 inline static void handle_xyz(D3DVALUE *coords) {
1183     glVertex3fv(coords);
1184 }
1185 inline static void handle_xyzrhw(D3DVALUE *coords) {
1186     if ((coords[3] < 1e-8) && (coords[3] > -1e-8))
1187         glVertex3fv(coords);
1188     else {
1189         GLfloat w = 1.0 / coords[3];
1190         
1191         glVertex4f(coords[0] * w,
1192                    coords[1] * w,
1193                    coords[2] * w,
1194                    w);
1195     }
1196 }
1197 inline static void handle_normal(D3DVALUE *coords) {
1198     glNormal3fv(coords);
1199 }
1200
1201 inline static void handle_diffuse_base(STATEBLOCK *sb, DWORD *color) {
1202     if (sb->render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] ||
1203         sb->render_state[D3DRENDERSTATE_ALPHABLENDENABLE - 1]) {
1204         glColor4ub((*color >> 16) & 0xFF,
1205                    (*color >>  8) & 0xFF,
1206                    (*color >>  0) & 0xFF,
1207                    (*color >> 24) & 0xFF);
1208     } else {
1209         glColor3ub((*color >> 16) & 0xFF,
1210                    (*color >>  8) & 0xFF,
1211                    (*color >>  0) & 0xFF);    
1212     }
1213 }
1214
1215 inline static void handle_specular_base(STATEBLOCK *sb, DWORD *color) {
1216     glColor4ub((*color >> 16) & 0xFF,
1217                (*color >>  8) & 0xFF,
1218                (*color >>  0) & 0xFF,
1219                (*color >> 24) & 0xFF); /* No idea if the alpha field is really used.. */
1220 }
1221
1222 inline static void handle_diffuse(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1223     if ((lighted == FALSE) &&
1224         sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1225         sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1226         if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1227             glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1228             handle_diffuse_base(sb, color);
1229         }
1230         if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1231             glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1232             handle_diffuse_base(sb, color);
1233         }
1234         if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR1) &&
1235             sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1236             glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1237             handle_diffuse_base(sb, color);
1238         }
1239         if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR1) {
1240             glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1241             handle_diffuse_base(sb, color);
1242         }
1243     } else {
1244         handle_diffuse_base(sb, color);
1245     }    
1246 }
1247
1248 inline static void handle_specular(STATEBLOCK *sb, DWORD *color, BOOLEAN lighted) {
1249     if ((lighted == FALSE) &&
1250         sb->render_state[D3DRENDERSTATE_LIGHTING - 1] &&
1251         sb->render_state[D3DRENDERSTATE_COLORVERTEX - 1]) {
1252         if (sb->render_state[D3DRENDERSTATE_DIFFUSEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1253             glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1254             handle_specular_base(sb, color);
1255         }
1256         if (sb->render_state[D3DRENDERSTATE_AMBIENTMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1257             glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
1258             handle_specular_base(sb, color);
1259         }
1260         if ((sb->render_state[D3DRENDERSTATE_SPECULARMATERIALSOURCE - 1] == D3DMCS_COLOR2) &&
1261             sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1262             glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
1263             handle_specular_base(sb, color);
1264         }
1265         if (sb->render_state[D3DRENDERSTATE_EMISSIVEMATERIALSOURCE - 1] == D3DMCS_COLOR2) {
1266             glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
1267             handle_specular_base(sb, color);
1268         }
1269     }
1270     /* No else here as we do not know how to handle 'specular' on its own in any case.. */
1271 }
1272
1273 inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) {
1274     if (lighted) {
1275         DWORD color = *color_d;
1276         if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1]) {
1277             /* Special case where the specular value is used to do fogging */
1278             BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */
1279             color &= 0xFF000000; /* Only keep the alpha component */
1280             color |= fog_table[((*color_d >>  0) & 0xFF) << 8 | fog_intensity] <<  0;
1281             color |= fog_table[((*color_d >>  8) & 0xFF) << 8 | fog_intensity] <<  8;
1282             color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16;
1283         }
1284         if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1]) {
1285             /* Standard specular value in transformed mode. TODO */
1286         }
1287         handle_diffuse_base(sb, &color);
1288     } else {
1289         if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1]) {
1290             handle_diffuse(sb, color_d, FALSE);
1291             handle_specular(sb, color_s, FALSE);
1292         } else {
1293             /* In that case, only put the diffuse color... */
1294             handle_diffuse_base(sb, color_d);
1295         }
1296     }
1297 }
1298
1299 inline static void handle_texture(D3DVALUE *coords) {
1300     glTexCoord2fv(coords);
1301 }
1302 inline static void handle_textures(const D3DVALUE *coords, int tex_stage) {
1303     if (GL_extensions.glMultiTexCoord2fv) {
1304         GL_extensions.glMultiTexCoord2fv(GL_TEXTURE0_WINE + tex_stage, coords);
1305     } else {
1306         if (tex_stage == 0) glTexCoord2fv(coords);
1307     }
1308 }
1309
1310 static void draw_primitive_strided(IDirect3DDeviceImpl *This,
1311                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1312                                    DWORD d3dvtVertexType,
1313                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1314                                    DWORD dwVertexCount,
1315                                    LPWORD dwIndices,
1316                                    DWORD dwIndexCount,
1317                                    DWORD dwFlags)
1318 {
1319     BOOLEAN vertex_lighted = FALSE;
1320     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
1321     int num_active_stages = 0;
1322     int num_tex_index = ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT);
1323     
1324     /* I put the trace before the various locks... So as to better understand where locks occur :-) */
1325     if (TRACE_ON(ddraw)) {
1326         TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
1327     }
1328
1329     /* This is to prevent 'thread contention' between a thread locking the device and another
1330        doing 3D display on it... */
1331     EnterCriticalSection(&(This->crit));   
1332     
1333     ENTER_GL();
1334     if (glThis->state[WINE_GL_BUFFER_BACK] == SURFACE_MEMORY_DIRTY) {
1335         This->flush_to_framebuffer(This, &(glThis->lock_rect[WINE_GL_BUFFER_BACK]), glThis->lock_surf[WINE_GL_BUFFER_BACK]);
1336     }
1337     glThis->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
1338
1339     if (This->current_zbuffer == NULL) {
1340         /* Search for an attached ZBuffer */
1341         static const DDSCAPS2 zbuf_caps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
1342         LPDIRECTDRAWSURFACE7 zbuf;
1343         HRESULT hr;
1344         
1345         hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->surface, IDirectDrawSurface7),
1346                                                     (DDSCAPS2 *) &zbuf_caps, &zbuf);
1347         if (!FAILED(hr)) {
1348             This->current_zbuffer = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, zbuf);
1349             IDirectDrawSurface7_Release(zbuf);
1350         }
1351     }
1352     if (This->current_zbuffer != NULL) {
1353         if (This->current_zbuffer->get_dirty_status(This->current_zbuffer, NULL)) {
1354             flush_zbuffer_to_GL(This, NULL, This->current_zbuffer);
1355         }
1356     }
1357     
1358     if ( ((d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) ||
1359          ((d3dvtVertexType & D3DFVF_NORMAL) == 0) )
1360         vertex_lighted = TRUE;
1361     
1362     /* Compute the number of active texture stages and set the various texture parameters */
1363     num_active_stages = draw_primitive_handle_textures(This);
1364
1365     /* And restore to handle '0' in the case we use glTexCoord calls */
1366     if (glThis->current_active_tex_unit != GL_TEXTURE0_WINE) {
1367         GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
1368         glThis->current_active_tex_unit = GL_TEXTURE0_WINE;
1369     }
1370
1371     draw_primitive_handle_GL_state(This,
1372                                    (d3dvtVertexType & D3DFVF_POSITION_MASK) != D3DFVF_XYZ,
1373                                    vertex_lighted);
1374
1375     /* First, see if we can use the OpenGL vertex arrays... This is very limited
1376        for now to some 'special' cases where we can do a direct mapping between D3D
1377        types and GL types.
1378
1379        Note: in the future all calls will go through vertex arrays but the arrays
1380              will be generated by this function.
1381
1382        Note2: colours cannot be mapped directly because they are stored as BGRA in memory
1383               (ie not as an array of R, G, B, A as OpenGL does it but as a LWORD 0xAARRGGBB
1384               which, as we are little indian, gives a B, G, R, A storage in memory.
1385     */
1386     if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) && /* Standard XYZ vertices */
1387         ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == 0)) {
1388         int tex_stage;
1389         TRACE(" using GL vertex arrays for performance !\n");
1390         /* First, the vertices (we are sure we have some :-) */
1391         glEnableClientState(GL_VERTEX_ARRAY);
1392         glVertexPointer(3, GL_FLOAT, lpD3DDrawPrimStrideData->position.dwStride, lpD3DDrawPrimStrideData->position.lpvData);
1393         /* Then the normals */
1394         if (d3dvtVertexType & D3DFVF_NORMAL) {
1395             glEnableClientState(GL_NORMAL_ARRAY);
1396             glNormalPointer(GL_FLOAT, lpD3DDrawPrimStrideData->normal.dwStride, lpD3DDrawPrimStrideData->normal.lpvData);
1397         }
1398         /* Then the diffuse colour */
1399         if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1400             glEnableClientState(GL_COLOR_ARRAY);
1401             glColorPointer(3, GL_UNSIGNED_BYTE, lpD3DDrawPrimStrideData->normal.dwStride,
1402                            ((char *) lpD3DDrawPrimStrideData->diffuse.lpvData));
1403         }
1404         /* Then the various textures */
1405         for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1406             int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1407             if (tex_index >= num_tex_index) {
1408                 WARN("Default texture coordinate not handled in the vertex array path !!!\n");
1409                 tex_index = num_tex_index - 1;
1410             }
1411             if (GL_extensions.glClientActiveTexture) {
1412                 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1413             }
1414             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1415             glTexCoordPointer(2, GL_FLOAT, lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride,
1416                               lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData);
1417         }
1418         if (dwIndices != NULL) {
1419             glDrawElements(convert_D3D_ptype_to_GL(d3dptPrimitiveType), dwIndexCount, GL_UNSIGNED_SHORT, dwIndices);
1420         } else {
1421             glDrawArrays(convert_D3D_ptype_to_GL(d3dptPrimitiveType), 0, dwIndexCount);
1422         }
1423         glDisableClientState(GL_VERTEX_ARRAY);
1424         if (d3dvtVertexType & D3DFVF_NORMAL) {
1425             glDisableClientState(GL_NORMAL_ARRAY);
1426         }
1427         if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1428             glDisableClientState(GL_COLOR_ARRAY);
1429         }
1430         for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1431             if (GL_extensions.glClientActiveTexture) {
1432                 GL_extensions.glClientActiveTexture(GL_TEXTURE0_WINE + tex_stage);
1433             }
1434             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1435         }
1436     } else {
1437         glBegin(convert_D3D_ptype_to_GL(d3dptPrimitiveType));
1438         
1439         /* Some fast paths first before the generic case.... */
1440         if ((d3dvtVertexType == D3DFVF_VERTEX) && (num_active_stages <= 1)) {
1441             unsigned int index;
1442             
1443             for (index = 0; index < dwIndexCount; index++) {
1444                 int i = (dwIndices == NULL) ? index : dwIndices[index];
1445                 D3DVALUE *normal = 
1446                     (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);
1447                 D3DVALUE *tex_coord =
1448                     (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1449                 D3DVALUE *position =
1450                     (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1451                 
1452                 handle_normal(normal);
1453                 handle_texture(tex_coord);
1454                 handle_xyz(position);
1455                 
1456                 TRACE_(ddraw_geom)(" %f %f %f / %f %f %f (%f %f)\n",
1457                                    position[0], position[1], position[2],
1458                                    normal[0], normal[1], normal[2],
1459                                    tex_coord[0], tex_coord[1]);
1460             }
1461         } else if ((d3dvtVertexType == D3DFVF_TLVERTEX) && (num_active_stages <= 1)) {
1462             unsigned int index;
1463             
1464             for (index = 0; index < dwIndexCount; index++) {
1465                 int i = (dwIndices == NULL) ? index : dwIndices[index];
1466                 DWORD *color_d = 
1467                     (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1468                 DWORD *color_s = 
1469                     (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1470                 D3DVALUE *tex_coord =
1471                     (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[0].lpvData) + i * lpD3DDrawPrimStrideData->textureCoords[0].dwStride);
1472                 D3DVALUE *position =
1473                     (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1474                 
1475                 handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE);
1476                 handle_texture(tex_coord);
1477                 handle_xyzrhw(position);
1478                 
1479                 TRACE_(ddraw_geom)(" %f %f %f %f / %02lx %02lx %02lx %02lx - %02lx %02lx %02lx %02lx (%f %f)\n",
1480                                    position[0], position[1], position[2], position[3], 
1481                                    (*color_d >> 16) & 0xFF,
1482                                    (*color_d >>  8) & 0xFF,
1483                                    (*color_d >>  0) & 0xFF,
1484                                    (*color_d >> 24) & 0xFF,
1485                                    (*color_s >> 16) & 0xFF,
1486                                    (*color_s >>  8) & 0xFF,
1487                                    (*color_s >>  0) & 0xFF,
1488                                    (*color_s >> 24) & 0xFF,
1489                                    tex_coord[0], tex_coord[1]);
1490             } 
1491         } else if (((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) ||
1492                    ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)) {
1493             /* This is the 'slow path' but that should support all possible vertex formats out there...
1494                Note that people should write a fast path for all vertex formats out there...
1495                */  
1496             unsigned int index;
1497             static const D3DVALUE no_index[] = { 0.0, 0.0, 0.0, 0.0 };
1498             
1499             for (index = 0; index < dwIndexCount; index++) {
1500                 int i = (dwIndices == NULL) ? index : dwIndices[index];
1501                 int tex_stage;
1502                 
1503                 if (d3dvtVertexType & D3DFVF_NORMAL) { 
1504                     D3DVALUE *normal = 
1505                         (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);           
1506                     handle_normal(normal);
1507                 }
1508                 if ((d3dvtVertexType & (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) == (D3DFVF_DIFFUSE|D3DFVF_SPECULAR)) {
1509                     DWORD *color_d = 
1510                         (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1511                     DWORD *color_s = 
1512                         (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1513                     handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted);
1514                 } else {
1515                     if (d3dvtVertexType & D3DFVF_SPECULAR) { 
1516                         DWORD *color_s = 
1517                             (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1518                         handle_specular(&(This->state_block), color_s, vertex_lighted);
1519                     } else if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1520                         DWORD *color_d = 
1521                             (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1522                         handle_diffuse(&(This->state_block), color_d, vertex_lighted);
1523                     }
1524                 }
1525                 
1526                 for (tex_stage = 0; tex_stage < num_active_stages; tex_stage++) {
1527                     int tex_index = This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXCOORDINDEX - 1] & 0x0000FFFF;
1528                     if (tex_index >= num_tex_index) {
1529                         handle_textures((const D3DVALUE *) no_index, tex_stage);
1530                     } else {
1531                         D3DVALUE *tex_coord =
1532                             (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) + 
1533                                           i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1534                         handle_textures(tex_coord, tex_stage);
1535                     }
1536                 }
1537                 
1538                 if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1539                     D3DVALUE *position =
1540                         (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1541                     handle_xyz(position);
1542                 } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1543                     D3DVALUE *position =
1544                         (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1545                     handle_xyzrhw(position);
1546                 }
1547                 
1548                 if (TRACE_ON(ddraw_geom)) {
1549                     unsigned int tex_index;
1550                     
1551                     if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZ) {
1552                         D3DVALUE *position =
1553                             (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1554                         TRACE_(ddraw_geom)(" %f %f %f", position[0], position[1], position[2]);
1555                     } else if ((d3dvtVertexType & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW) {
1556                         D3DVALUE *position =
1557                             (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride);
1558                         TRACE_(ddraw_geom)(" %f %f %f %f", position[0], position[1], position[2], position[3]);
1559                     }
1560                     if (d3dvtVertexType & D3DFVF_NORMAL) { 
1561                         D3DVALUE *normal = 
1562                             (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->normal.lpvData) + i * lpD3DDrawPrimStrideData->normal.dwStride);       
1563                         TRACE_(ddraw_geom)(" / %f %f %f", normal[0], normal[1], normal[2]);
1564                     }
1565                     if (d3dvtVertexType & D3DFVF_DIFFUSE) {
1566                         DWORD *color_d = 
1567                             (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride);
1568                         TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1569                                            (*color_d >> 16) & 0xFF,
1570                                            (*color_d >>  8) & 0xFF,
1571                                            (*color_d >>  0) & 0xFF,
1572                                            (*color_d >> 24) & 0xFF);
1573                     }
1574                     if (d3dvtVertexType & D3DFVF_SPECULAR) { 
1575                         DWORD *color_s = 
1576                             (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride);
1577                         TRACE_(ddraw_geom)(" / %02lx %02lx %02lx %02lx",
1578                                            (*color_s >> 16) & 0xFF,
1579                                            (*color_s >>  8) & 0xFF,
1580                                            (*color_s >>  0) & 0xFF,
1581                                            (*color_s >> 24) & 0xFF);
1582                     }
1583                     for (tex_index = 0; tex_index < ((d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT); tex_index++) {
1584                         D3DVALUE *tex_coord =
1585                             (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->textureCoords[tex_index].lpvData) + 
1586                                           i * lpD3DDrawPrimStrideData->textureCoords[tex_index].dwStride);
1587                         TRACE_(ddraw_geom)(" / %f %f", tex_coord[0], tex_coord[1]);
1588                     }
1589                     TRACE_(ddraw_geom)("\n");
1590                 }
1591             }
1592         } else {
1593             ERR(" matrix weighting not handled yet....\n");
1594         }
1595         
1596         glEnd();
1597     }
1598
1599     /* Whatever the case, disable the color material stuff */
1600     glDisable(GL_COLOR_MATERIAL);
1601
1602     LEAVE_GL();
1603     TRACE("End\n");    
1604
1605     LeaveCriticalSection(&(This->crit));
1606 }
1607
1608 HRESULT WINAPI
1609 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface,
1610                                           D3DPRIMITIVETYPE d3dptPrimitiveType,
1611                                           DWORD d3dvtVertexType,
1612                                           LPVOID lpvVertices,
1613                                           DWORD dwVertexCount,
1614                                           DWORD dwFlags)
1615 {
1616     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1617     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1618
1619     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags);
1620     if (TRACE_ON(ddraw)) {
1621         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1622     }
1623
1624     convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1625     draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, NULL, dwVertexCount, dwFlags);
1626     
1627     return DD_OK;
1628 }
1629
1630 HRESULT WINAPI
1631 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface,
1632                                                  D3DPRIMITIVETYPE d3dptPrimitiveType,
1633                                                  DWORD d3dvtVertexType,
1634                                                  LPVOID lpvVertices,
1635                                                  DWORD dwVertexCount,
1636                                                  LPWORD dwIndices,
1637                                                  DWORD dwIndexCount,
1638                                                  DWORD dwFlags)
1639 {
1640     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1641     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1642
1643     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1644     if (TRACE_ON(ddraw)) {
1645         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1646     }
1647
1648     convert_FVF_to_strided_data(d3dvtVertexType, lpvVertices, &strided, 0);
1649     draw_primitive_strided(This, d3dptPrimitiveType, d3dvtVertexType, &strided, dwVertexCount, dwIndices, dwIndexCount, dwFlags);
1650     
1651     return DD_OK;
1652 }
1653
1654 HRESULT WINAPI
1655 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1656                                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1657                                                    DWORD dwVertexType,
1658                                                    LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1659                                                    DWORD dwVertexCount,
1660                                                    DWORD dwFlags)
1661 {
1662     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1663
1664     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, dwFlags);
1665     if (TRACE_ON(ddraw)) {
1666         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1667     }
1668     draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, NULL, dwVertexCount, dwFlags);
1669
1670     return DD_OK;
1671 }
1672
1673 HRESULT WINAPI
1674 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided(LPDIRECT3DDEVICE7 iface,
1675                                                           D3DPRIMITIVETYPE d3dptPrimitiveType,
1676                                                           DWORD dwVertexType,
1677                                                           LPD3DDRAWPRIMITIVESTRIDEDDATA lpD3DDrawPrimStrideData,
1678                                                           DWORD dwVertexCount,
1679                                                           LPWORD lpIndex,
1680                                                           DWORD dwIndexCount,
1681                                                           DWORD dwFlags)
1682 {
1683     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1684
1685     TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1686     if (TRACE_ON(ddraw)) {
1687         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1688     }
1689
1690     draw_primitive_strided(This, d3dptPrimitiveType, dwVertexType, lpD3DDrawPrimStrideData, dwVertexCount, lpIndex, dwIndexCount, dwFlags);
1691
1692     return DD_OK;
1693 }
1694
1695 HRESULT WINAPI
1696 GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1697                                             D3DPRIMITIVETYPE d3dptPrimitiveType,
1698                                             LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1699                                             DWORD dwStartVertex,
1700                                             DWORD dwNumVertices,
1701                                             DWORD dwFlags)
1702 {
1703     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1704     IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1705     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1706
1707     TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, dwFlags);
1708     if (TRACE_ON(ddraw)) {
1709         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1710     }
1711
1712     if (vb_impl->processed) {
1713         IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1714         IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1715
1716         glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1717         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1718                            &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1719
1720         convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1721         draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1722
1723     } else {
1724         convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1725         draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, NULL, dwNumVertices, dwFlags);
1726     }
1727
1728     return DD_OK;
1729 }
1730
1731 HRESULT WINAPI
1732 GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB(LPDIRECT3DDEVICE7 iface,
1733                                                    D3DPRIMITIVETYPE d3dptPrimitiveType,
1734                                                    LPDIRECT3DVERTEXBUFFER7 lpD3DVertexBuf,
1735                                                    DWORD dwStartVertex,
1736                                                    DWORD dwNumVertices,
1737                                                    LPWORD lpwIndices,
1738                                                    DWORD dwIndexCount,
1739                                                    DWORD dwFlags)
1740 {
1741     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1742     IDirect3DVertexBufferImpl *vb_impl = ICOM_OBJECT(IDirect3DVertexBufferImpl, IDirect3DVertexBuffer7, lpD3DVertexBuf);
1743     D3DDRAWPRIMITIVESTRIDEDDATA strided;
1744     
1745     TRACE("(%p/%p)->(%08x,%p,%08lx,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, lpD3DVertexBuf, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1746     if (TRACE_ON(ddraw)) {
1747         TRACE(" - flags : "); dump_DPFLAGS(dwFlags);
1748     }
1749
1750     if (vb_impl->processed) {
1751         IDirect3DVertexBufferGLImpl *vb_glimp = (IDirect3DVertexBufferGLImpl *) vb_impl;
1752         IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1753
1754         glThis->transform_state = GL_TRANSFORM_VERTEXBUFFER;
1755         This->set_matrices(This, VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED,
1756                            &(vb_glimp->world_mat), &(vb_glimp->view_mat), &(vb_glimp->proj_mat));
1757
1758         convert_FVF_to_strided_data(vb_glimp->dwVertexTypeDesc, vb_glimp->vertices, &strided, dwStartVertex);
1759         draw_primitive_strided(This, d3dptPrimitiveType, vb_glimp->dwVertexTypeDesc, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1760
1761     } else {
1762         convert_FVF_to_strided_data(vb_impl->desc.dwFVF, vb_impl->vertices, &strided, dwStartVertex);
1763         draw_primitive_strided(This, d3dptPrimitiveType, vb_impl->desc.dwFVF, &strided, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
1764     }
1765
1766     return DD_OK;
1767 }
1768
1769 /* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
1770 static BOOLEAN
1771 handle_color_alpha_args(IDirect3DDeviceImpl *This, DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
1772 {
1773     BOOLEAN is_complement = FALSE;
1774     BOOLEAN is_alpha_replicate = FALSE;
1775     BOOLEAN handled = TRUE;
1776     GLenum src;
1777     BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
1778     int num;
1779     
1780     if (is_color) {
1781         if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
1782         else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
1783         else {
1784             handled = FALSE;
1785             num = 0;
1786         }
1787         if (tex_op == D3DTOP_SELECTARG2) {
1788             num = 1 - num;
1789         }
1790     } else {
1791         if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
1792         else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
1793         else {
1794             handled = FALSE;
1795             num = 0;
1796         }
1797         if (tex_op == D3DTOP_SELECTARG2) {
1798             num = 1 - num;
1799         }
1800     }
1801     
1802     if (dwState & D3DTA_COMPLEMENT) {
1803         is_complement = TRUE;
1804     }
1805     if (dwState & D3DTA_ALPHAREPLICATE) {
1806         is_alpha_replicate = TRUE;
1807     }
1808     dwState &= D3DTA_SELECTMASK;
1809     if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
1810         dwState = D3DTA_DIFFUSE;
1811     }
1812
1813     switch (dwState) {
1814         case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
1815         case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_EXT; break;
1816         case D3DTA_TEXTURE: src = GL_TEXTURE; break;
1817         case D3DTA_TFACTOR: {
1818             /* Get the constant value from the current rendering state */
1819             GLfloat color[4];
1820             DWORD col = This->state_block.render_state[D3DRENDERSTATE_TEXTUREFACTOR - 1];
1821             
1822             color[0] = ((col >> 16) & 0xFF) / 255.0f;
1823             color[1] = ((col >>  8) & 0xFF) / 255.0f;
1824             color[2] = ((col >>  0) & 0xFF) / 255.0f;
1825             color[3] = ((col >> 24) & 0xFF) / 255.0f;
1826             glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1827             
1828             src = GL_CONSTANT_EXT;
1829         } break;
1830         default: src = GL_TEXTURE; handled = FALSE; break;
1831     }
1832
1833     if (is_color) {
1834         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT + num, src);
1835         if (is_alpha_replicate) {
1836             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1837         } else {
1838             glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
1839         }
1840     } else {
1841         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT + num, src);
1842         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
1843     }
1844
1845     return handled;
1846 }
1847
1848 HRESULT WINAPI
1849 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
1850                                                  DWORD dwStage,
1851                                                  D3DTEXTURESTAGESTATETYPE d3dTexStageStateType,
1852                                                  DWORD dwState)
1853 {
1854     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
1855     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
1856     const char *type;
1857     DWORD prev_state;
1858     GLenum unit;
1859     
1860     TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
1861
1862     if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
1863         ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
1864         return DD_OK;
1865     }
1866
1867     unit = GL_TEXTURE0_WINE + dwStage;
1868     if (unit != glThis->current_active_tex_unit) {
1869         GL_extensions.glActiveTexture(unit);
1870         glThis->current_active_tex_unit = unit;
1871     }
1872     
1873     switch (d3dTexStageStateType) {
1874 #define GEN_CASE(a) case a: type = #a; break
1875         GEN_CASE(D3DTSS_COLOROP);
1876         GEN_CASE(D3DTSS_COLORARG1);
1877         GEN_CASE(D3DTSS_COLORARG2);
1878         GEN_CASE(D3DTSS_ALPHAOP);
1879         GEN_CASE(D3DTSS_ALPHAARG1);
1880         GEN_CASE(D3DTSS_ALPHAARG2);
1881         GEN_CASE(D3DTSS_BUMPENVMAT00);
1882         GEN_CASE(D3DTSS_BUMPENVMAT01);
1883         GEN_CASE(D3DTSS_BUMPENVMAT10);
1884         GEN_CASE(D3DTSS_BUMPENVMAT11);
1885         GEN_CASE(D3DTSS_TEXCOORDINDEX);
1886         GEN_CASE(D3DTSS_ADDRESS);
1887         GEN_CASE(D3DTSS_ADDRESSU);
1888         GEN_CASE(D3DTSS_ADDRESSV);
1889         GEN_CASE(D3DTSS_BORDERCOLOR);
1890         GEN_CASE(D3DTSS_MAGFILTER);
1891         GEN_CASE(D3DTSS_MINFILTER);
1892         GEN_CASE(D3DTSS_MIPFILTER);
1893         GEN_CASE(D3DTSS_MIPMAPLODBIAS);
1894         GEN_CASE(D3DTSS_MAXMIPLEVEL);
1895         GEN_CASE(D3DTSS_MAXANISOTROPY);
1896         GEN_CASE(D3DTSS_BUMPENVLSCALE);
1897         GEN_CASE(D3DTSS_BUMPENVLOFFSET);
1898         GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
1899 #undef GEN_CASE
1900         default: type = "UNKNOWN";
1901     }
1902
1903     /* Store the values in the state array */
1904     prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
1905     This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
1906     /* Some special cases when one state modifies more than one... */
1907     if (d3dTexStageStateType == D3DTSS_ADDRESS) {
1908         This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
1909         This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
1910     }
1911
1912     ENTER_GL();
1913     
1914     switch (d3dTexStageStateType) {
1915         case D3DTSS_MINFILTER:
1916         case D3DTSS_MIPFILTER:
1917             if (TRACE_ON(ddraw)) {
1918                 if (d3dTexStageStateType == D3DTSS_MINFILTER) {
1919                     switch ((D3DTEXTUREMINFILTER) dwState) {
1920                         case D3DTFN_POINT:  TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
1921                         case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
1922                         default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
1923                     }
1924                 } else {
1925                     switch ((D3DTEXTUREMIPFILTER) dwState) {
1926                         case D3DTFP_NONE:   TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
1927                         case D3DTFP_POINT:  TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
1928                         case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
1929                         default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
1930                     }
1931                 }
1932             }
1933             break;
1934             
1935         case D3DTSS_MAGFILTER:
1936             if (TRACE_ON(ddraw)) {
1937                 switch ((D3DTEXTUREMAGFILTER) dwState) {
1938                     case D3DTFG_POINT:  TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_POINT\n"); break;
1939                     case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFG_LINEAR\n"); break;
1940                     default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
1941                 }
1942             }
1943             break;
1944
1945         case D3DTSS_ADDRESS:
1946         case D3DTSS_ADDRESSU:
1947         case D3DTSS_ADDRESSV: {
1948             switch ((D3DTEXTUREADDRESS) dwState) {
1949                 case D3DTADDRESS_WRAP:   TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); break;
1950                 case D3DTADDRESS_CLAMP:  TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); break;
1951                 case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); break;
1952                 case D3DTADDRESS_MIRROR:
1953                     if (GL_extensions.mirrored_repeat) {
1954                         TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type);
1955                     } else {
1956                         FIXME(" Stage type is : %s => D3DTADDRESS_MIRROR - not supported by GL !\n", type);
1957                     }
1958                     break;
1959                 default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
1960             }
1961         } break;
1962
1963         case D3DTSS_ALPHAOP:
1964         case D3DTSS_COLOROP: {
1965             int scale = 1;
1966             GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_EXT : GL_COMBINE_RGB_EXT;
1967             const char *value;
1968             int handled = 1;
1969             
1970             switch (dwState) {
1971 #define GEN_CASE(a) case a: value = #a; break
1972                 GEN_CASE(D3DTOP_DISABLE);
1973                 GEN_CASE(D3DTOP_SELECTARG1);
1974                 GEN_CASE(D3DTOP_SELECTARG2);
1975                 GEN_CASE(D3DTOP_MODULATE);
1976                 GEN_CASE(D3DTOP_MODULATE2X);
1977                 GEN_CASE(D3DTOP_MODULATE4X);
1978                 GEN_CASE(D3DTOP_ADD);
1979                 GEN_CASE(D3DTOP_ADDSIGNED);
1980                 GEN_CASE(D3DTOP_ADDSIGNED2X);
1981                 GEN_CASE(D3DTOP_SUBTRACT);
1982                 GEN_CASE(D3DTOP_ADDSMOOTH);
1983                 GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
1984                 GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
1985                 GEN_CASE(D3DTOP_BLENDFACTORALPHA);
1986                 GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
1987                 GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
1988                 GEN_CASE(D3DTOP_PREMODULATE);
1989                 GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
1990                 GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
1991                 GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
1992                 GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
1993                 GEN_CASE(D3DTOP_BUMPENVMAP);
1994                 GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
1995                 GEN_CASE(D3DTOP_DOTPRODUCT3);
1996                 GEN_CASE(D3DTOP_FORCE_DWORD);
1997 #undef GEN_CASE
1998                 default: value = "UNKNOWN";
1999             }
2000
2001             if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE)) {
2002                 glDisable(GL_TEXTURE_2D);
2003                 TRACE(" disabling 2D texturing.\n");
2004             } else {
2005                 /* Re-enable texturing only if COLOROP was not already disabled... */
2006                 if ((glThis->current_bound_texture[dwStage] != NULL) &&
2007                     (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2008                     glEnable(GL_TEXTURE_2D);
2009                     TRACE(" enabling 2D texturing.\n");
2010                 }
2011                 
2012                 /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT */
2013                 if ((dwState != D3DTOP_DISABLE) &&
2014                     (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE)) {
2015                     if (glThis->current_tex_env != GL_COMBINE_EXT) {
2016                         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2017                         glThis->current_tex_env = GL_COMBINE_EXT;
2018                     }
2019                 }
2020
2021                 /* Now set up the operand correctly */
2022                 switch (dwState) {
2023                     case D3DTOP_DISABLE:
2024                         /* Contrary to the docs, alpha can be disabled when colorop is enabled
2025                            and it works, so ignore this op */
2026                         TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
2027                         break;
2028
2029                     case D3DTOP_SELECTARG1:
2030                     case D3DTOP_SELECTARG2:
2031                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
2032                         break;
2033                         
2034                     case D3DTOP_MODULATE4X:
2035                         scale = scale * 2;  /* Drop through */
2036                     case D3DTOP_MODULATE2X:
2037                         scale = scale * 2;  /* Drop through */
2038                     case D3DTOP_MODULATE:
2039                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
2040                         break;
2041
2042                     case D3DTOP_ADD:
2043                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
2044                         break;
2045
2046                     case D3DTOP_ADDSIGNED2X:
2047                         scale = scale * 2;  /* Drop through */
2048                     case D3DTOP_ADDSIGNED:
2049                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_EXT);
2050                         break;
2051
2052                         /* For the four blending modes, use the Arg2 parameter */
2053                     case D3DTOP_BLENDDIFFUSEALPHA:
2054                     case D3DTOP_BLENDTEXTUREALPHA:
2055                     case D3DTOP_BLENDFACTORALPHA:
2056                     case D3DTOP_BLENDCURRENTALPHA: {
2057                         GLenum src = GL_PRIMARY_COLOR_EXT; /* Just to prevent a compiler warning.. */
2058
2059                         switch (dwState) {
2060                             case D3DTOP_BLENDDIFFUSEALPHA: src = GL_PRIMARY_COLOR_EXT;
2061                             case D3DTOP_BLENDTEXTUREALPHA: src = GL_TEXTURE;
2062                             case D3DTOP_BLENDFACTORALPHA:  src = GL_CONSTANT_EXT;
2063                             case D3DTOP_BLENDCURRENTALPHA: src = GL_PREVIOUS_EXT;
2064                         }
2065                         
2066                         glTexEnvi(GL_TEXTURE_ENV, parm, GL_INTERPOLATE_EXT);
2067                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, src);
2068                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
2069                         glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_EXT, src);
2070                         glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_EXT, GL_SRC_ALPHA);
2071                     } break;
2072                         
2073                     default:
2074                         handled = FALSE;
2075                         break;
2076                 }
2077             }
2078
2079             if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
2080                 ((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
2081                 /* Switch the arguments if needed... */
2082                 if (d3dTexStageStateType == D3DTSS_COLOROP) {
2083                     handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG1,
2084                                             This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
2085                                             dwState);
2086                     handle_color_alpha_args(This, dwStage, D3DTSS_COLORARG2,
2087                                             This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
2088                                             dwState);
2089                 } else {
2090                     handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG1,
2091                                             This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
2092                                             dwState);
2093                     handle_color_alpha_args(This, dwStage, D3DTSS_ALPHAARG2,
2094                                             This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
2095                                             dwState);
2096                 }
2097             }
2098             
2099             if (handled) {
2100                 if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
2101                     glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
2102                 } else {
2103                     glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, scale);
2104                 }                       
2105                 TRACE(" Stage type is : %s => %s\n", type, value);
2106             } else {
2107                 FIXME(" Unhandled stage type is : %s => %s\n", type, value);
2108             }
2109         } break;
2110
2111         case D3DTSS_COLORARG1:
2112         case D3DTSS_COLORARG2:
2113         case D3DTSS_ALPHAARG1:
2114         case D3DTSS_ALPHAARG2: {
2115             const char *value, *value_comp = "", *value_alpha = "";
2116             BOOLEAN handled;
2117             D3DTEXTUREOP tex_op;
2118             
2119             switch (dwState & D3DTA_SELECTMASK) {
2120 #define GEN_CASE(a) case a: value = #a; break
2121                 GEN_CASE(D3DTA_DIFFUSE);
2122                 GEN_CASE(D3DTA_CURRENT);
2123                 GEN_CASE(D3DTA_TEXTURE);
2124                 GEN_CASE(D3DTA_TFACTOR);
2125                 GEN_CASE(D3DTA_SPECULAR);
2126 #undef GEN_CASE
2127                 default: value = "UNKNOWN";
2128             }
2129             if (dwState & D3DTA_COMPLEMENT) {
2130                 value_comp = " | D3DTA_COMPLEMENT";
2131             }
2132             if (dwState & D3DTA_ALPHAREPLICATE) {
2133                 value_alpha = " | D3DTA_ALPHAREPLICATE";
2134             }
2135
2136             if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
2137                 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
2138             } else {
2139                 tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
2140             }
2141             
2142             handled = handle_color_alpha_args(This, dwStage, d3dTexStageStateType, dwState, tex_op);
2143             
2144             if (handled) {
2145                 TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2146             } else {
2147                 FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
2148             }
2149         } break;
2150
2151         case D3DTSS_MIPMAPLODBIAS: {
2152             D3DVALUE value = *((D3DVALUE *) &dwState);
2153             BOOLEAN handled = TRUE;
2154             
2155             if ((value != 0.0) && (GL_extensions.mipmap_lodbias == FALSE))
2156                 handled = FALSE;
2157
2158             if (handled) {
2159                 TRACE(" Stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2160                 glTexEnvf(GL_TEXTURE_FILTER_CONTROL_WINE, GL_TEXTURE_LOD_BIAS_WINE, value);
2161             } else {
2162                 FIXME(" Unhandled stage type : D3DTSS_MIPMAPLODBIAS => %f\n", value);
2163             }
2164         } break;
2165
2166         case D3DTSS_MAXMIPLEVEL: 
2167             TRACE(" Stage type : D3DTSS_MAXMIPLEVEL => %ld\n", dwState);
2168             break;
2169
2170         case D3DTSS_BORDERCOLOR:
2171             TRACE(" Stage type : D3DTSS_BORDERCOLOR => %02lx %02lx %02lx %02lx (RGBA)\n",
2172                   ((dwState >> 16) & 0xFF),
2173                   ((dwState >>  8) & 0xFF),
2174                   ((dwState >>  0) & 0xFF),
2175                   ((dwState >> 24) & 0xFF));
2176             break;
2177             
2178         case D3DTSS_TEXCOORDINDEX: {
2179             BOOLEAN handled = TRUE;
2180             const char *value;
2181             
2182             switch (dwState & 0xFFFF0000) {
2183 #define GEN_CASE(a) case a: value = #a; break
2184                 GEN_CASE(D3DTSS_TCI_PASSTHRU);
2185                 GEN_CASE(D3DTSS_TCI_CAMERASPACENORMAL);
2186                 GEN_CASE(D3DTSS_TCI_CAMERASPACEPOSITION);
2187                 GEN_CASE(D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
2188 #undef GEN_CASE
2189                 default: value = "UNKNOWN";
2190             }
2191             if ((dwState & 0xFFFF0000) != D3DTSS_TCI_PASSTHRU)
2192                 handled = FALSE;
2193
2194             if (handled) {
2195                 TRACE(" Stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2196             } else {
2197                 FIXME(" Unhandled stage type : D3DTSS_TEXCOORDINDEX => %ld | %s\n", dwState & 0x0000FFFF, value);
2198             }
2199         } break;
2200             
2201         case D3DTSS_TEXTURETRANSFORMFLAGS: {
2202             const char *projected = "", *value;
2203             BOOLEAN handled = TRUE;
2204             switch (dwState & 0xFF) {
2205 #define GEN_CASE(a) case a: value = #a; break
2206                 GEN_CASE(D3DTTFF_DISABLE);
2207                 GEN_CASE(D3DTTFF_COUNT1);
2208                 GEN_CASE(D3DTTFF_COUNT2);
2209                 GEN_CASE(D3DTTFF_COUNT3);
2210                 GEN_CASE(D3DTTFF_COUNT4);
2211 #undef GEN_CASE
2212                 default: value = "UNKNOWN";
2213             }
2214             if (dwState & D3DTTFF_PROJECTED) {
2215                 projected = " | D3DTTFF_PROJECTED";
2216                 handled = FALSE;
2217             }
2218
2219             if ((dwState & 0xFF) != D3DTTFF_DISABLE) {
2220                 This->matrices_updated(This, TEXMAT0_CHANGED << dwStage);
2221             }
2222
2223             if (handled) {
2224                 TRACE(" Stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2225             } else {
2226                 FIXME(" Unhandled stage type : D3DTSS_TEXTURETRANSFORMFLAGS => %s%s\n", value, projected);
2227             }
2228         } break;
2229             
2230         default:
2231             FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
2232             break;
2233     }
2234
2235     LEAVE_GL();
2236     
2237     return DD_OK;
2238 }
2239
2240 static DWORD
2241 draw_primitive_handle_textures(IDirect3DDeviceImpl *This)
2242 {
2243     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2244     DWORD stage;
2245     BOOLEAN enable_colorkey = FALSE;
2246     
2247     for (stage = 0; stage < MAX_TEXTURES; stage++) {
2248         IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
2249         GLenum unit;
2250
2251         /* If this stage is disabled, no need to go further... */
2252         if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] == D3DTOP_DISABLE)
2253             break;
2254         
2255         /* First check if we need to bind any other texture for this stage */
2256         if (This->current_texture[stage] != glThis->current_bound_texture[stage]) {
2257             if (This->current_texture[stage] == NULL) {
2258                 TRACE(" disabling 2D texturing for stage %ld.\n", stage);
2259                 
2260                 unit = GL_TEXTURE0_WINE + stage;
2261                 if (unit != glThis->current_active_tex_unit) {
2262                     GL_extensions.glActiveTexture(unit);
2263                     glThis->current_active_tex_unit = unit;
2264                 }
2265                 glBindTexture(GL_TEXTURE_2D, 0);
2266                 glDisable(GL_TEXTURE_2D);
2267             } else {
2268                 GLenum tex_name = gltex_get_tex_name(surf_ptr);
2269                 
2270                 unit = GL_TEXTURE0_WINE + stage;
2271                 if (unit != glThis->current_active_tex_unit) {
2272                     GL_extensions.glActiveTexture(unit);
2273                     glThis->current_active_tex_unit = unit;
2274                 }
2275
2276                 if (glThis->current_bound_texture[stage] == NULL) {
2277                     if (This->state_block.texture_stage_state[stage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
2278                         TRACE(" enabling 2D texturing and");
2279                         glEnable(GL_TEXTURE_2D);
2280                     }
2281                 }
2282                 TRACE(" activating OpenGL texture id %d for stage %ld.\n", tex_name, stage);
2283                 glBindTexture(GL_TEXTURE_2D, tex_name);
2284             }
2285
2286             glThis->current_bound_texture[stage] = This->current_texture[stage];
2287         } else {
2288             if (glThis->current_bound_texture[stage] == NULL) {
2289                 TRACE(" displaying without texturing activated for stage %ld.\n", stage);
2290             } else {
2291                 TRACE(" using already bound texture id %d for stage %ld.\n",
2292                       ((IDirect3DTextureGLImpl *) (glThis->current_bound_texture[stage])->tex_private)->tex_name, stage);
2293             }
2294         }
2295
2296         /* If no texure valid for this stage, go out of the loop */
2297         if (This->current_texture[stage] == NULL) break;
2298
2299         /* Then check if we need to flush this texture to GL or not (ie did it change) ?.
2300            This will also update the various texture parameters if needed.
2301         */
2302         gltex_upload_texture(surf_ptr, This, stage);
2303
2304         /* And finally check for color-keying (only on first stage) */
2305         if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
2306             if (stage == 0) {
2307                 enable_colorkey = TRUE;
2308             } else {
2309                 static BOOL warn = FALSE;
2310                 if (warn == FALSE) {
2311                     warn = TRUE;
2312                     WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
2313                 }
2314             }
2315         } else {
2316             if (stage == 0) {
2317                 enable_colorkey = FALSE;
2318             }
2319         }
2320     }
2321
2322     /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
2323     if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
2324          (glThis->parent.version == 1)) &&
2325         (enable_colorkey)) {
2326         TRACE(" colorkey activated.\n");
2327         
2328         if (glThis->alpha_test == FALSE) {
2329             glEnable(GL_ALPHA_TEST);
2330             glThis->alpha_test = TRUE;
2331         }
2332         if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
2333             if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1]) {
2334                 static BOOL warn = FALSE;
2335                 if (warn == FALSE) {
2336                     warn = TRUE;
2337                     WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
2338                 }
2339             }
2340             glThis->current_alpha_test_func = GL_NOTEQUAL;
2341             glThis->current_alpha_test_ref = 0.0;
2342             glAlphaFunc(GL_NOTEQUAL, 0.0);
2343         }
2344         /* Some sanity checks should be added here if a game mixes alphatest + color keying...
2345            Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
2346     } else {
2347         if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
2348             glDisable(GL_ALPHA_TEST);
2349             glThis->alpha_test = FALSE;
2350         }
2351         /* Maybe we should restore here the application-given alpha test states ? */
2352     }
2353     
2354     return stage;
2355 }
2356
2357 HRESULT WINAPI
2358 GL_IDirect3DDeviceImpl_7_3T_SetTexture(LPDIRECT3DDEVICE7 iface,
2359                                        DWORD dwStage,
2360                                        LPDIRECTDRAWSURFACE7 lpTexture2)
2361 {
2362     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2363     
2364     TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwStage, lpTexture2);
2365
2366     if (((GL_extensions.max_texture_units == 0) && (dwStage > 0)) ||
2367         ((GL_extensions.max_texture_units != 0) && (dwStage >= GL_extensions.max_texture_units))) {
2368         if (lpTexture2 != NULL) {
2369             WARN(" setting a texture to a non-supported texture stage !\n");
2370         }
2371         return DD_OK;
2372     }
2373
2374     if (This->current_texture[dwStage] != NULL) {
2375         IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[dwStage], IDirectDrawSurface7));
2376     }
2377     
2378     if (lpTexture2 == NULL) {
2379         This->current_texture[dwStage] = NULL;
2380     } else {
2381         IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
2382         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7));
2383         This->current_texture[dwStage] = tex_impl;
2384     }
2385     
2386     return DD_OK;
2387 }
2388
2389 HRESULT WINAPI
2390 GL_IDirect3DDeviceImpl_7_GetCaps(LPDIRECT3DDEVICE7 iface,
2391                                  LPD3DDEVICEDESC7 lpD3DHELDevDesc)
2392 {
2393     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2394     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DHELDevDesc);
2395
2396     fill_opengl_caps_7(lpD3DHELDevDesc);
2397
2398     TRACE(" returning caps : no dump function yet.\n");
2399
2400     return DD_OK;
2401 }
2402
2403 HRESULT WINAPI
2404 GL_IDirect3DDeviceImpl_7_SetMaterial(LPDIRECT3DDEVICE7 iface,
2405                                      LPD3DMATERIAL7 lpMat)
2406 {
2407     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2408     TRACE("(%p/%p)->(%p)\n", This, iface, lpMat);
2409     
2410     if (TRACE_ON(ddraw)) {
2411         TRACE(" material is : \n");
2412         dump_D3DMATERIAL7(lpMat);
2413     }
2414     
2415     This->current_material = *lpMat;
2416
2417     ENTER_GL();
2418     glMaterialfv(GL_FRONT_AND_BACK,
2419                  GL_DIFFUSE,
2420                  (float *) &(This->current_material.u.diffuse));
2421     glMaterialfv(GL_FRONT_AND_BACK,
2422                  GL_AMBIENT,
2423                  (float *) &(This->current_material.u1.ambient));
2424     glMaterialfv(GL_FRONT_AND_BACK,
2425                  GL_SPECULAR,
2426                  (float *) &(This->current_material.u2.specular));
2427     glMaterialfv(GL_FRONT_AND_BACK,
2428                  GL_EMISSION,
2429                  (float *) &(This->current_material.u3.emissive));
2430     glMaterialf(GL_FRONT_AND_BACK,
2431                 GL_SHININESS,
2432                 This->current_material.u4.power); /* Not sure about this... */
2433     LEAVE_GL();
2434
2435     return DD_OK;
2436 }
2437
2438 static LPD3DLIGHT7 get_light(IDirect3DDeviceImpl *This, DWORD dwLightIndex)
2439 {
2440     if (dwLightIndex >= This->num_set_lights)
2441     {
2442         /* Extend, or allocate the light parameters array. */
2443         DWORD newlightnum = dwLightIndex + 1;
2444         LPD3DLIGHT7 newarrayptr = NULL;
2445
2446         if (This->light_parameters)
2447             newarrayptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2448                 This->light_parameters, newlightnum * sizeof(D3DLIGHT7));
2449         else
2450             newarrayptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2451                 newlightnum * sizeof(D3DLIGHT7));
2452
2453         if (!newarrayptr)
2454             return NULL;
2455
2456         This->light_parameters = newarrayptr;
2457         This->num_set_lights = newlightnum;
2458     }
2459
2460     return &This->light_parameters[dwLightIndex];
2461 }
2462
2463 HRESULT WINAPI
2464 GL_IDirect3DDeviceImpl_7_SetLight(LPDIRECT3DDEVICE7 iface,
2465                                   DWORD dwLightIndex,
2466                                   LPD3DLIGHT7 lpLight)
2467 {
2468     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2469     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2470     LPD3DLIGHT7 lpdestlight = get_light( This, dwLightIndex );
2471
2472     TRACE("(%p/%p)->(%08lx,%p)\n", This, iface, dwLightIndex, lpLight);
2473     
2474     if (TRACE_ON(ddraw)) {
2475         TRACE(" setting light : \n");
2476         dump_D3DLIGHT7(lpLight);
2477     }
2478     
2479     /* DirectX7 documentation states that this function can return
2480        DDERR_OUTOFMEMORY, so we do just that in case of an allocation
2481        error (which is the only reason why get_light() can fail). */
2482     if( !lpdestlight )
2483         return DDERR_OUTOFMEMORY;
2484
2485     *lpdestlight = *lpLight;
2486
2487     /* Some checks to print out nice warnings :-) */
2488     switch (lpLight->dltType) {
2489         case D3DLIGHT_DIRECTIONAL:
2490         case D3DLIGHT_POINT:
2491             /* These are handled properly... */
2492             break;
2493             
2494         case D3DLIGHT_SPOT:
2495             if ((lpLight->dvTheta != 0.0) ||
2496                 (lpLight->dvTheta != lpLight->dvPhi)) {
2497                 ERR("dvTheta not fully supported yet !\n");
2498             }
2499             break;
2500
2501         default:
2502             ERR("Light type not handled yet : %08x !\n", lpLight->dltType);
2503     }
2504     
2505     /* This will force the Light setting on next drawing of primitives */
2506     glThis->transform_state = GL_TRANSFORM_NONE;
2507     
2508     return DD_OK;
2509 }
2510
2511 HRESULT WINAPI
2512 GL_IDirect3DDeviceImpl_7_LightEnable(LPDIRECT3DDEVICE7 iface,
2513                                      DWORD dwLightIndex,
2514                                      BOOL bEnable)
2515 {
2516     int lightslot = -1, i;
2517     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2518     LPD3DLIGHT7 lpdestlight = get_light(This, dwLightIndex);
2519
2520     TRACE("(%p/%p)->(%08lx,%d)\n", This, iface, dwLightIndex, bEnable);
2521
2522     /* The DirectX doc isn't as explicit as for SetLight as whether we can
2523        return this from this function, but it doesn't state otherwise. */
2524     if (!lpdestlight)
2525         return DDERR_OUTOFMEMORY;
2526
2527     /* If this light hasn't been set, initialise it with default values. */
2528     if (lpdestlight->dltType == 0)
2529     {
2530         TRACE("setting default light parameters\n");
2531
2532         /* We always use HEAP_ZERO_MEMORY when allocating the light_parameters
2533            array, so we only have to setup anything that shoud not be zero. */
2534         lpdestlight->dltType = D3DLIGHT_DIRECTIONAL;
2535         lpdestlight->dcvDiffuse.u1.r = 1.f;
2536         lpdestlight->dcvDiffuse.u2.g = 1.f;
2537         lpdestlight->dcvDiffuse.u3.b = 1.f;
2538         lpdestlight->dvDirection.u3.z = 1.f;
2539     }
2540
2541     /* Look for this light in the active lights array. */
2542     for (i = 0; i < This->max_active_lights; i++)
2543         if (This->active_lights[i] == dwLightIndex)
2544         {
2545             lightslot = i;
2546             break;
2547         }
2548
2549     /* If we didn't find it, let's find the first available slot, if any. */
2550     if (lightslot == -1)
2551         for (i = 0; i < This->max_active_lights; i++)
2552             if (This->active_lights[i] == ~0)
2553             {
2554                 lightslot = i;
2555                 break;
2556             }
2557
2558     ENTER_GL();
2559     if (bEnable) {
2560         if (lightslot == -1)
2561         {
2562             /* This means that the app is trying to enable more lights than
2563                the maximum possible indicated in the caps.
2564
2565                Windows actually let you do this, and disable one of the
2566                previously enabled lights to let you enable this one.
2567
2568                It's not documented and I'm not sure how windows pick which light
2569                to disable to make room for this one. */
2570             FIXME("Enabling more light than the maximum is not supported yet.");
2571             return D3D_OK;
2572         }
2573
2574         glEnable(GL_LIGHT0 + lightslot);
2575
2576
2577         if (This->active_lights[lightslot] == ~0)
2578         {
2579             /* This light gets active... Need to update its parameters to GL before the next drawing */
2580             IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2581
2582             This->active_lights[lightslot] = dwLightIndex;
2583             glThis->transform_state = GL_TRANSFORM_NONE;
2584         }
2585     } else {
2586         glDisable(GL_LIGHT0 + lightslot);
2587         This->active_lights[lightslot] = ~0;
2588     }
2589
2590     LEAVE_GL();
2591     return DD_OK;
2592 }
2593
2594 HRESULT  WINAPI  
2595 GL_IDirect3DDeviceImpl_7_SetClipPlane(LPDIRECT3DDEVICE7 iface, DWORD dwIndex, CONST D3DVALUE* pPlaneEquation) 
2596 {
2597     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2598     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
2599
2600     TRACE("(%p)->(%ld,%p)\n", This, dwIndex, pPlaneEquation);
2601
2602     if (dwIndex >= This->max_clipping_planes) {
2603         return DDERR_INVALIDPARAMS;
2604     }
2605
2606     TRACE(" clip plane %ld : %f %f %f %f\n", dwIndex, pPlaneEquation[0], pPlaneEquation[1], pPlaneEquation[2], pPlaneEquation[3] );
2607
2608     memcpy(This->clipping_planes[dwIndex].plane, pPlaneEquation, sizeof(D3DVALUE[4]));
2609     
2610     /* This is to force the reset of the transformation matrices on the next drawing.
2611      * This is needed to use the correct matrices for the various clipping planes.
2612      */
2613     glThis->transform_state = GL_TRANSFORM_NONE;
2614     
2615     return D3D_OK;
2616 }
2617
2618 HRESULT WINAPI
2619 GL_IDirect3DDeviceImpl_7_SetViewport(LPDIRECT3DDEVICE7 iface,
2620                                      LPD3DVIEWPORT7 lpData)
2621 {
2622     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
2623     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
2624
2625     if (TRACE_ON(ddraw)) {
2626         TRACE(" viewport is : \n");
2627         TRACE("    - dwX = %ld   dwY = %ld\n",
2628               lpData->dwX, lpData->dwY);
2629         TRACE("    - dwWidth = %ld   dwHeight = %ld\n",
2630               lpData->dwWidth, lpData->dwHeight);
2631         TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
2632               lpData->dvMinZ, lpData->dvMaxZ);
2633     }
2634     ENTER_GL();
2635     
2636     /* Set the viewport */
2637     if ((lpData->dvMinZ != This->active_viewport.dvMinZ) ||
2638         (lpData->dvMaxZ != This->active_viewport.dvMaxZ)) {
2639         glDepthRange(lpData->dvMinZ, lpData->dvMaxZ);
2640     }
2641     if ((lpData->dwX != This->active_viewport.dwX) ||
2642         (lpData->dwY != This->active_viewport.dwY) ||
2643         (lpData->dwWidth != This->active_viewport.dwWidth) ||
2644         (lpData->dwHeight != This->active_viewport.dwHeight)) {
2645         glViewport(lpData->dwX,
2646                    This->surface->surface_desc.dwHeight - (lpData->dwHeight + lpData->dwY),
2647                    lpData->dwWidth, lpData->dwHeight);
2648     }
2649
2650     LEAVE_GL();
2651
2652     This->active_viewport = *lpData;
2653     
2654     return DD_OK;
2655 }
2656
2657 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2658 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice7.fun))
2659 #else
2660 # define XCAST(fun)     (void*)
2661 #endif
2662
2663 static const IDirect3DDevice7Vtbl VTABLE_IDirect3DDevice7 =
2664 {
2665     XCAST(QueryInterface) Main_IDirect3DDeviceImpl_7_3T_2T_1T_QueryInterface,
2666     XCAST(AddRef) Main_IDirect3DDeviceImpl_7_3T_2T_1T_AddRef,
2667     XCAST(Release) GL_IDirect3DDeviceImpl_7_3T_2T_1T_Release,
2668     XCAST(GetCaps) GL_IDirect3DDeviceImpl_7_GetCaps,
2669     XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_7_3T_EnumTextureFormats,
2670     XCAST(BeginScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_BeginScene,
2671     XCAST(EndScene) Main_IDirect3DDeviceImpl_7_3T_2T_1T_EndScene,
2672     XCAST(GetDirect3D) Main_IDirect3DDeviceImpl_7_3T_2T_1T_GetDirect3D,
2673     XCAST(SetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_SetRenderTarget,
2674     XCAST(GetRenderTarget) Main_IDirect3DDeviceImpl_7_3T_2T_GetRenderTarget,
2675     XCAST(Clear) Main_IDirect3DDeviceImpl_7_Clear,
2676     XCAST(SetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_SetTransform,
2677     XCAST(GetTransform) Main_IDirect3DDeviceImpl_7_3T_2T_GetTransform,
2678     XCAST(SetViewport) GL_IDirect3DDeviceImpl_7_SetViewport,
2679     XCAST(MultiplyTransform) Main_IDirect3DDeviceImpl_7_3T_2T_MultiplyTransform,
2680     XCAST(GetViewport) Main_IDirect3DDeviceImpl_7_GetViewport,
2681     XCAST(SetMaterial) GL_IDirect3DDeviceImpl_7_SetMaterial,
2682     XCAST(GetMaterial) Main_IDirect3DDeviceImpl_7_GetMaterial,
2683     XCAST(SetLight) GL_IDirect3DDeviceImpl_7_SetLight,
2684     XCAST(GetLight) Main_IDirect3DDeviceImpl_7_GetLight,
2685     XCAST(SetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_SetRenderState,
2686     XCAST(GetRenderState) GL_IDirect3DDeviceImpl_7_3T_2T_GetRenderState,
2687     XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock,
2688     XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock,
2689     XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad,
2690     XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive,
2691     XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive,
2692     XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus,
2693     XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus,
2694     XCAST(DrawPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided,
2695     XCAST(DrawIndexedPrimitiveStrided) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveStrided,
2696     XCAST(DrawPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitiveVB,
2697     XCAST(DrawIndexedPrimitiveVB) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitiveVB,
2698     XCAST(ComputeSphereVisibility) Main_IDirect3DDeviceImpl_7_3T_ComputeSphereVisibility,
2699     XCAST(GetTexture) Main_IDirect3DDeviceImpl_7_3T_GetTexture,
2700     XCAST(SetTexture) GL_IDirect3DDeviceImpl_7_3T_SetTexture,
2701     XCAST(GetTextureStageState) Main_IDirect3DDeviceImpl_7_3T_GetTextureStageState,
2702     XCAST(SetTextureStageState) GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState,
2703     XCAST(ValidateDevice) Main_IDirect3DDeviceImpl_7_3T_ValidateDevice,
2704     XCAST(ApplyStateBlock) Main_IDirect3DDeviceImpl_7_ApplyStateBlock,
2705     XCAST(CaptureStateBlock) Main_IDirect3DDeviceImpl_7_CaptureStateBlock,
2706     XCAST(DeleteStateBlock) Main_IDirect3DDeviceImpl_7_DeleteStateBlock,
2707     XCAST(CreateStateBlock) Main_IDirect3DDeviceImpl_7_CreateStateBlock,
2708     XCAST(Load) Main_IDirect3DDeviceImpl_7_Load,
2709     XCAST(LightEnable) GL_IDirect3DDeviceImpl_7_LightEnable,
2710     XCAST(GetLightEnable) Main_IDirect3DDeviceImpl_7_GetLightEnable,
2711     XCAST(SetClipPlane) GL_IDirect3DDeviceImpl_7_SetClipPlane,
2712     XCAST(GetClipPlane) Main_IDirect3DDeviceImpl_7_GetClipPlane,
2713     XCAST(GetInfo) Main_IDirect3DDeviceImpl_7_GetInfo,
2714 };
2715
2716 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2717 #undef XCAST
2718 #endif
2719
2720
2721 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2722 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice3.fun))
2723 #else
2724 # define XCAST(fun)     (void*)
2725 #endif
2726
2727 static const IDirect3DDevice3Vtbl VTABLE_IDirect3DDevice3 =
2728 {
2729     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_3_QueryInterface,
2730     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_3_AddRef,
2731     XCAST(Release) Thunk_IDirect3DDeviceImpl_3_Release,
2732     XCAST(GetCaps) GL_IDirect3DDeviceImpl_3_2T_1T_GetCaps,
2733     XCAST(GetStats) Main_IDirect3DDeviceImpl_3_2T_1T_GetStats,
2734     XCAST(AddViewport) Main_IDirect3DDeviceImpl_3_2T_1T_AddViewport,
2735     XCAST(DeleteViewport) Main_IDirect3DDeviceImpl_3_2T_1T_DeleteViewport,
2736     XCAST(NextViewport) Main_IDirect3DDeviceImpl_3_2T_1T_NextViewport,
2737     XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
2738     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_3_BeginScene,
2739     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_3_EndScene,
2740     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
2741     XCAST(SetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_SetCurrentViewport,
2742     XCAST(GetCurrentViewport) Main_IDirect3DDeviceImpl_3_2T_GetCurrentViewport,
2743     XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
2744     XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
2745     XCAST(Begin) Main_IDirect3DDeviceImpl_3_Begin,
2746     XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_3_BeginIndexed,
2747     XCAST(Vertex) Main_IDirect3DDeviceImpl_3_2T_Vertex,
2748     XCAST(Index) Main_IDirect3DDeviceImpl_3_2T_Index,
2749     XCAST(End) Main_IDirect3DDeviceImpl_3_2T_End,
2750     XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_3_GetRenderState,
2751     XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_3_SetRenderState,
2752     XCAST(GetLightState) GL_IDirect3DDeviceImpl_3_2T_GetLightState,
2753     XCAST(SetLightState) GL_IDirect3DDeviceImpl_3_2T_SetLightState,
2754     XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_3_SetTransform,
2755     XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_3_GetTransform,
2756     XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
2757     XCAST(DrawPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
2758     XCAST(DrawIndexedPrimitive) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
2759     XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
2760     XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
2761     XCAST(DrawPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
2762     XCAST(DrawIndexedPrimitiveStrided) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
2763     XCAST(DrawPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
2764     XCAST(DrawIndexedPrimitiveVB) Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
2765     XCAST(ComputeSphereVisibility) Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
2766     XCAST(GetTexture) Thunk_IDirect3DDeviceImpl_3_GetTexture,
2767     XCAST(SetTexture) Thunk_IDirect3DDeviceImpl_3_SetTexture,
2768     XCAST(GetTextureStageState) Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
2769     XCAST(SetTextureStageState) Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
2770     XCAST(ValidateDevice) Thunk_IDirect3DDeviceImpl_3_ValidateDevice,
2771 };
2772
2773 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2774 #undef XCAST
2775 #endif
2776
2777
2778 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2779 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice2.fun))
2780 #else
2781 # define XCAST(fun)     (void*)
2782 #endif
2783
2784 static const IDirect3DDevice2Vtbl VTABLE_IDirect3DDevice2 =
2785 {
2786     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_2_QueryInterface,
2787     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_2_AddRef,
2788     XCAST(Release) Thunk_IDirect3DDeviceImpl_2_Release,
2789     XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_2_GetCaps,
2790     XCAST(SwapTextureHandles) Main_IDirect3DDeviceImpl_2_1T_SwapTextureHandles,
2791     XCAST(GetStats) Thunk_IDirect3DDeviceImpl_2_GetStats,
2792     XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_2_AddViewport,
2793     XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
2794     XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_2_NextViewport,
2795     XCAST(EnumTextureFormats) GL_IDirect3DDeviceImpl_2_1T_EnumTextureFormats,
2796     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_2_BeginScene,
2797     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_2_EndScene,
2798     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
2799     XCAST(SetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
2800     XCAST(GetCurrentViewport) Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
2801     XCAST(SetRenderTarget) Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
2802     XCAST(GetRenderTarget) Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
2803     XCAST(Begin) Main_IDirect3DDeviceImpl_2_Begin,
2804     XCAST(BeginIndexed) Main_IDirect3DDeviceImpl_2_BeginIndexed,
2805     XCAST(Vertex) Thunk_IDirect3DDeviceImpl_2_Vertex,
2806     XCAST(Index) Thunk_IDirect3DDeviceImpl_2_Index,
2807     XCAST(End) Thunk_IDirect3DDeviceImpl_2_End,
2808     XCAST(GetRenderState) Thunk_IDirect3DDeviceImpl_2_GetRenderState,
2809     XCAST(SetRenderState) Thunk_IDirect3DDeviceImpl_2_SetRenderState,
2810     XCAST(GetLightState) Thunk_IDirect3DDeviceImpl_2_GetLightState,
2811     XCAST(SetLightState) Thunk_IDirect3DDeviceImpl_2_SetLightState,
2812     XCAST(SetTransform) Thunk_IDirect3DDeviceImpl_2_SetTransform,
2813     XCAST(GetTransform) Thunk_IDirect3DDeviceImpl_2_GetTransform,
2814     XCAST(MultiplyTransform) Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
2815     XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_2_DrawPrimitive,
2816     XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
2817     XCAST(SetClipStatus) Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
2818     XCAST(GetClipStatus) Thunk_IDirect3DDeviceImpl_2_GetClipStatus,
2819 };
2820
2821 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2822 #undef XCAST
2823 #endif
2824
2825
2826 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2827 # define XCAST(fun)     (typeof(VTABLE_IDirect3DDevice.fun))
2828 #else
2829 # define XCAST(fun)     (void*)
2830 #endif
2831
2832 static const IDirect3DDeviceVtbl VTABLE_IDirect3DDevice =
2833 {
2834     XCAST(QueryInterface) Thunk_IDirect3DDeviceImpl_1_QueryInterface,
2835     XCAST(AddRef) Thunk_IDirect3DDeviceImpl_1_AddRef,
2836     XCAST(Release) Thunk_IDirect3DDeviceImpl_1_Release,
2837     XCAST(Initialize) Main_IDirect3DDeviceImpl_1_Initialize,
2838     XCAST(GetCaps) Thunk_IDirect3DDeviceImpl_1_GetCaps,
2839     XCAST(SwapTextureHandles) Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
2840     XCAST(CreateExecuteBuffer) GL_IDirect3DDeviceImpl_1_CreateExecuteBuffer,
2841     XCAST(GetStats) Thunk_IDirect3DDeviceImpl_1_GetStats,
2842     XCAST(Execute) Main_IDirect3DDeviceImpl_1_Execute,
2843     XCAST(AddViewport) Thunk_IDirect3DDeviceImpl_1_AddViewport,
2844     XCAST(DeleteViewport) Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
2845     XCAST(NextViewport) Thunk_IDirect3DDeviceImpl_1_NextViewport,
2846     XCAST(Pick) Main_IDirect3DDeviceImpl_1_Pick,
2847     XCAST(GetPickRecords) Main_IDirect3DDeviceImpl_1_GetPickRecords,
2848     XCAST(EnumTextureFormats) Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
2849     XCAST(CreateMatrix) Main_IDirect3DDeviceImpl_1_CreateMatrix,
2850     XCAST(SetMatrix) Main_IDirect3DDeviceImpl_1_SetMatrix,
2851     XCAST(GetMatrix) Main_IDirect3DDeviceImpl_1_GetMatrix,
2852     XCAST(DeleteMatrix) Main_IDirect3DDeviceImpl_1_DeleteMatrix,
2853     XCAST(BeginScene) Thunk_IDirect3DDeviceImpl_1_BeginScene,
2854     XCAST(EndScene) Thunk_IDirect3DDeviceImpl_1_EndScene,
2855     XCAST(GetDirect3D) Thunk_IDirect3DDeviceImpl_1_GetDirect3D,
2856 };
2857
2858 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
2859 #undef XCAST
2860 #endif
2861
2862 static HRESULT d3ddevice_clear(IDirect3DDeviceImpl *This,
2863                                WINE_GL_BUFFER_TYPE buffer_type,
2864                                DWORD dwCount,
2865                                LPD3DRECT lpRects,
2866                                DWORD dwFlags,
2867                                DWORD dwColor,
2868                                D3DVALUE dvZ,
2869                                DWORD dwStencil)
2870 {
2871     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
2872     GLbitfield bitfield = 0;
2873     D3DRECT rect;
2874     unsigned int i;
2875     
2876     TRACE("(%p)->(%08lx,%p,%08lx,%08lx,%f,%08lx)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2877     if (TRACE_ON(ddraw)) {
2878         if (dwCount > 0) {
2879             unsigned int i;
2880             TRACE(" rectangles : \n");
2881             for (i = 0; i < dwCount; i++) {
2882                 TRACE("  - %ld x %ld     %ld x %ld\n", lpRects[i].u1.x1, lpRects[i].u2.y1, lpRects[i].u3.x2, lpRects[i].u4.y2);
2883             }
2884         }
2885     }
2886
2887     if (dwCount == 0) {
2888         dwCount = 1;
2889         rect.u1.x1 = 0;
2890         rect.u2.y1 = 0;
2891         rect.u3.x2 = This->surface->surface_desc.dwWidth;
2892         rect.u4.y2 = This->surface->surface_desc.dwHeight;
2893         lpRects = &rect;
2894     }
2895     
2896     /* Clears the screen */
2897     ENTER_GL();
2898
2899     if (dwFlags & D3DCLEAR_TARGET) {
2900         if (glThis->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
2901             /* TODO: optimize here the case where Clear changes all the screen... */
2902             This->flush_to_framebuffer(This, &(glThis->lock_rect[buffer_type]), glThis->lock_surf[buffer_type]);
2903         }
2904         glThis->state[buffer_type] = SURFACE_GL;
2905     }
2906
2907     if (dwFlags & D3DCLEAR_ZBUFFER) {
2908         bitfield |= GL_DEPTH_BUFFER_BIT;
2909         if (glThis->depth_mask == FALSE) {
2910             glDepthMask(GL_TRUE); /* Enables Z writing to be sure to delete also the Z buffer */
2911         }
2912         if (dvZ != glThis->prev_clear_Z) {
2913             glClearDepth(dvZ);
2914             glThis->prev_clear_Z = dvZ;
2915         }
2916         TRACE(" depth value : %f\n", dvZ);
2917     }
2918     if (dwFlags & D3DCLEAR_STENCIL) {
2919         bitfield |= GL_STENCIL_BUFFER_BIT;
2920         if (dwStencil != glThis->prev_clear_stencil) {
2921             glClearStencil(dwStencil);
2922             glThis->prev_clear_stencil = dwStencil;
2923         }
2924         TRACE(" stencil value : %ld\n", dwStencil);
2925     }    
2926     if (dwFlags & D3DCLEAR_TARGET) {
2927         bitfield |= GL_COLOR_BUFFER_BIT;
2928         if (dwColor != glThis->prev_clear_color) {
2929             glClearColor(((dwColor >> 16) & 0xFF) / 255.0,
2930                          ((dwColor >>  8) & 0xFF) / 255.0,
2931                          ((dwColor >>  0) & 0xFF) / 255.0,
2932                          ((dwColor >> 24) & 0xFF) / 255.0);
2933             glThis->prev_clear_color = dwColor;
2934         }
2935         TRACE(" color value (ARGB) : %08lx\n", dwColor);
2936     }
2937
2938     glEnable(GL_SCISSOR_TEST); 
2939     for (i = 0; i < dwCount; i++) {
2940         glScissor(lpRects[i].u1.x1, This->surface->surface_desc.dwHeight - lpRects[i].u4.y2,
2941                   lpRects[i].u3.x2 - lpRects[i].u1.x1, lpRects[i].u4.y2 - lpRects[i].u2.y1);
2942         glClear(bitfield);
2943     }
2944     glDisable(GL_SCISSOR_TEST); 
2945     
2946     if (dwFlags & D3DCLEAR_ZBUFFER) {
2947         if (glThis->depth_mask == FALSE) glDepthMask(GL_FALSE);
2948     }
2949     
2950     LEAVE_GL();
2951     
2952     return DD_OK;
2953 }
2954
2955 static HRESULT d3ddevice_clear_back(IDirect3DDeviceImpl *This,
2956                                     DWORD dwCount,
2957                                     LPD3DRECT lpRects,
2958                                     DWORD dwFlags,
2959                                     DWORD dwColor,
2960                                     D3DVALUE dvZ,
2961                                     DWORD dwStencil)
2962 {
2963     return d3ddevice_clear(This, WINE_GL_BUFFER_BACK, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
2964 }
2965
2966 static HRESULT
2967 setup_rect_and_surface_for_blt(IDirectDrawSurfaceImpl *This,
2968                                WINE_GL_BUFFER_TYPE *buffer_type_p, D3DRECT *rect)
2969 {
2970     IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
2971     WINE_GL_BUFFER_TYPE buffer_type;
2972     
2973     /* First check if we BLT to the backbuffer... */
2974     if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
2975         buffer_type = WINE_GL_BUFFER_BACK;
2976     } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
2977         buffer_type = WINE_GL_BUFFER_FRONT;
2978     } else {
2979         ERR("Only BLT override to front or back-buffer is supported for now !\n");
2980         return DDERR_INVALIDPARAMS;
2981     }
2982             
2983     if ((gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) &&
2984         (rect->u1.x1 >= gl_d3d_dev->lock_rect[buffer_type].left) &&
2985         (rect->u2.y1 >= gl_d3d_dev->lock_rect[buffer_type].top) &&
2986         (rect->u3.x2 <= gl_d3d_dev->lock_rect[buffer_type].right) &&
2987         (rect->u4.y2 <= gl_d3d_dev->lock_rect[buffer_type].bottom)) {
2988         /* If the memory zone is already dirty, use the standard 'in memory' blit operations and not
2989          * GL to do it.
2990          */
2991         return DDERR_INVALIDPARAMS;
2992     }
2993     *buffer_type_p = buffer_type;
2994     
2995     return DD_OK;
2996 }
2997
2998 HRESULT
2999 d3ddevice_blt(IDirectDrawSurfaceImpl *This, LPRECT rdst,
3000               LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
3001               DWORD dwFlags, LPDDBLTFX lpbltfx)
3002 {
3003     WINE_GL_BUFFER_TYPE buffer_type;
3004     D3DRECT rect;
3005
3006     if (rdst) {
3007         rect.u1.x1 = rdst->left;
3008         rect.u2.y1 = rdst->top;
3009         rect.u3.x2 = rdst->right;
3010         rect.u4.y2 = rdst->bottom;
3011     } else {
3012         rect.u1.x1 = 0;
3013         rect.u2.y1 = 0;
3014         rect.u3.x2 = This->surface_desc.dwWidth;
3015         rect.u4.y2 = This->surface_desc.dwHeight;
3016     }
3017     
3018     if (setup_rect_and_surface_for_blt(This, &buffer_type, &rect) != DD_OK) return DDERR_INVALIDPARAMS;
3019
3020     if (dwFlags & DDBLT_COLORFILL) {
3021         /* This is easy to handle for the D3D Device... */
3022         DWORD color;
3023         GLenum prev_draw;
3024         
3025         /* The color as given in the Blt function is in the format of the frame-buffer...
3026          * 'clear' expect it in ARGB format => we need to do some conversion :-)
3027          */
3028         if (This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
3029             if (This->palette) {
3030                 color = ((0xFF000000) |
3031                          (This->palette->palents[lpbltfx->u5.dwFillColor].peRed << 16) |
3032                          (This->palette->palents[lpbltfx->u5.dwFillColor].peGreen << 8) |
3033                          (This->palette->palents[lpbltfx->u5.dwFillColor].peBlue));
3034             } else {
3035                 color = 0xFF000000;
3036             }
3037         } else if ((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) &&
3038                    (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3039                     (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3040             if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3041                 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3042                 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3043                 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3044                 if (lpbltfx->u5.dwFillColor == 0xFFFF) {
3045                     color = 0xFFFFFFFF;
3046                 } else {
3047                     color = ((0xFF000000) |
3048                              ((lpbltfx->u5.dwFillColor & 0xF800) << 8) |
3049                              ((lpbltfx->u5.dwFillColor & 0x07E0) << 5) |
3050                              ((lpbltfx->u5.dwFillColor & 0x001F) << 3));
3051                 }
3052             } else if (((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) ||
3053                         (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24)) &&
3054                        (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3055                        (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3056                        (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3057                 color = 0xFF000000 | lpbltfx->u5.dwFillColor;
3058             } else {
3059                 ERR("Wrong surface type for BLT override (unknown RGB format) !\n");
3060                 return DDERR_INVALIDPARAMS;
3061             }
3062         } else {
3063             ERR("Wrong surface type for BLT override !\n");
3064             return DDERR_INVALIDPARAMS;
3065         }
3066         
3067         TRACE(" executing D3D Device override.\n");
3068         
3069         ENTER_GL();
3070
3071         glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3072         if (buffer_type == WINE_GL_BUFFER_FRONT)
3073             glDrawBuffer(GL_FRONT);
3074         else
3075             glDrawBuffer(GL_BACK);
3076         
3077         d3ddevice_clear(This->d3ddevice, buffer_type, 1, &rect, D3DCLEAR_TARGET, color, 0.0, 0x00000000);
3078         
3079         if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3080             ((buffer_type == WINE_GL_BUFFER_BACK)  && (prev_draw == GL_FRONT)))
3081             glDrawBuffer(prev_draw);
3082         
3083         LEAVE_GL();
3084         
3085         return DD_OK;
3086     } else if ((dwFlags & (~(DDBLT_KEYSRC|DDBLT_WAIT|DDBLT_ASYNC))) == 0) {
3087         /* Normal blit without any special case... */
3088         if (src != NULL) {
3089             /* And which has a SRC surface */
3090             IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3091             
3092             if ((src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) &&
3093                 (src_impl->d3ddevice == This->d3ddevice) &&
3094                 ((dwFlags & DDBLT_KEYSRC) == 0)) {
3095                 /* Both are 3D devices and using the same GL device and the Blt is without color-keying */
3096                 D3DRECT src_rect;
3097                 int width, height;
3098                 GLenum prev_draw;
3099                 WINE_GL_BUFFER_TYPE src_buffer_type;
3100                 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3101                 BOOLEAN initial;
3102                 DWORD opt_bitmap;
3103                 int x, y;
3104         
3105                 if (rsrc) {
3106                     src_rect.u1.x1 = rsrc->left;
3107                     src_rect.u2.y1 = rsrc->top;
3108                     src_rect.u3.x2 = rsrc->right;
3109                     src_rect.u4.y2 = rsrc->bottom;
3110                 } else {
3111                     src_rect.u1.x1 = 0;
3112                     src_rect.u2.y1 = 0;
3113                     src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3114                     src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3115                 }
3116
3117                 width = src_rect.u3.x2 - src_rect.u1.x1;
3118                 height = src_rect.u4.y2 - src_rect.u2.y1;
3119
3120                 if ((width != (rect.u3.x2 - rect.u1.x1)) ||
3121                     (height != (rect.u4.y2 - rect.u2.y1))) {
3122                     FIXME(" buffer to buffer copy not supported with stretching yet !\n");
3123                     return DDERR_INVALIDPARAMS;
3124                 }
3125
3126                 /* First check if we BLT from the backbuffer... */
3127                 if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) != 0) {
3128                     src_buffer_type = WINE_GL_BUFFER_BACK;
3129                 } else if ((src_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3130                     src_buffer_type = WINE_GL_BUFFER_FRONT;
3131                 } else {
3132                     ERR("Unexpected case in direct buffer to buffer copy !\n");
3133                     return DDERR_INVALIDPARAMS;
3134                 }
3135                 
3136                 TRACE(" using direct buffer to buffer copy.\n");
3137
3138                 ENTER_GL();
3139
3140                 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, FALSE, &initial);
3141                 
3142                 if (upload_surface_to_tex_memory_init(This, 0, &gl_d3d_dev->current_internal_format,
3143                                                       initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3144                     ERR(" unsupported pixel format at direct buffer to buffer copy.\n");
3145                     LEAVE_GL();
3146                     return DDERR_INVALIDPARAMS;
3147                 }
3148                 
3149                 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3150                 if (buffer_type == WINE_GL_BUFFER_FRONT)
3151                     glDrawBuffer(GL_FRONT);
3152                 else
3153                     glDrawBuffer(GL_BACK);
3154
3155                 if (src_buffer_type == WINE_GL_BUFFER_FRONT)
3156                     glReadBuffer(GL_FRONT);
3157                 else
3158                     glReadBuffer(GL_BACK);
3159
3160                 /* Now the serious stuff happens. Basically, we copy from the source buffer to the texture memory.
3161                    And directly re-draws this on the destination buffer. */
3162                 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3163                     int get_height;
3164                     
3165                     if ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwHeight)
3166                         get_height = src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y);
3167                     else
3168                         get_height = UNLOCK_TEX_SIZE;
3169                     
3170                     for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3171                         int get_width;
3172                         
3173                         if ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE) > src_impl->surface_desc.dwWidth)
3174                             get_width = src_impl->surface_desc.dwWidth - (src_rect.u1.x1 + x);
3175                         else
3176                             get_width = UNLOCK_TEX_SIZE;
3177                         
3178                         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3179                                             0, UNLOCK_TEX_SIZE - get_height,
3180                                             src_rect.u1.x1 + x, src_impl->surface_desc.dwHeight - (src_rect.u2.y1 + y + get_height),
3181                                             get_width, get_height);
3182                         
3183                         glBegin(GL_QUADS);
3184                         glTexCoord2f(0.0, 0.0);
3185                         glVertex3d(rect.u1.x1 + x,
3186                                    rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3187                                    0.5);
3188                         glTexCoord2f(1.0, 0.0);
3189                         glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3190                                    rect.u2.y1 + y + UNLOCK_TEX_SIZE,
3191                                    0.5);
3192                         glTexCoord2f(1.0, 1.0);
3193                         glVertex3d(rect.u1.x1 + x + UNLOCK_TEX_SIZE,
3194                                    rect.u2.y1 + y,
3195                                    0.5);
3196                         glTexCoord2f(0.0, 1.0);
3197                         glVertex3d(rect.u1.x1 + x,
3198                                    rect.u2.y1 + y,
3199                                    0.5);
3200                         glEnd();
3201                     }
3202                 }
3203                 
3204                 upload_surface_to_tex_memory_release();
3205                 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, FALSE);
3206                 
3207                 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3208                     ((buffer_type == WINE_GL_BUFFER_BACK)  && (prev_draw == GL_FRONT)))
3209                     glDrawBuffer(prev_draw);
3210                 
3211                 LEAVE_GL();
3212
3213                 return DD_OK;
3214             } else {
3215                 /* This is the normal 'with source' Blit. Use the texture engine to do the Blt for us
3216                    (this prevents calling glReadPixels) */
3217                 D3DRECT src_rect;
3218                 int width, height;
3219                 GLenum prev_draw;
3220                 IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3221                 BOOLEAN initial;
3222                 DWORD opt_bitmap;
3223                 int x, y;
3224                 double x_stretch, y_stretch;
3225                 
3226                 if (rsrc) {
3227                     src_rect.u1.x1 = rsrc->left;
3228                     src_rect.u2.y1 = rsrc->top;
3229                     src_rect.u3.x2 = rsrc->right;
3230                     src_rect.u4.y2 = rsrc->bottom;
3231                 } else {
3232                     src_rect.u1.x1 = 0;
3233                     src_rect.u2.y1 = 0;
3234                     src_rect.u3.x2 = src_impl->surface_desc.dwWidth;
3235                     src_rect.u4.y2 = src_impl->surface_desc.dwHeight;
3236                 }
3237
3238                 width = src_rect.u3.x2 - src_rect.u1.x1;
3239                 height = src_rect.u4.y2 - src_rect.u2.y1;
3240
3241                 x_stretch = (double) (rect.u3.x2 - rect.u1.x1) / (double) width;
3242                 y_stretch = (double) (rect.u4.y2 - rect.u2.y1) / (double) height;
3243
3244                 TRACE(" using memory to buffer Blt override.\n");
3245
3246                 ENTER_GL();
3247
3248                 opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, (LPCRECT) &rect, ((dwFlags & DDBLT_KEYSRC) != 0), &initial);
3249                 
3250                 if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3251                                                       initial, ((dwFlags & DDBLT_KEYSRC) != 0), UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3252                     ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3253                     LEAVE_GL();
3254                     return DDERR_INVALIDPARAMS;
3255                 }
3256                 
3257                 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3258                 if (buffer_type == WINE_GL_BUFFER_FRONT)
3259                     glDrawBuffer(GL_FRONT);
3260                 else
3261                     glDrawBuffer(GL_BACK);
3262
3263                 /* Now the serious stuff happens. This is basically the same code as for the memory
3264                    flush to frame buffer ... with stretching and different rectangles added :-) */
3265                 for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3266                     RECT flush_rect;
3267
3268                     flush_rect.top    = src_rect.u2.y1 + y;
3269                     flush_rect.bottom = ((src_rect.u2.y1 + y + UNLOCK_TEX_SIZE > src_rect.u4.y2) ?
3270                                          src_rect.u4.y2 :
3271                                          (src_rect.u2.y1 + y + UNLOCK_TEX_SIZE));
3272                     
3273                     for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3274                         flush_rect.left  = src_rect.u1.x1 + x;
3275                         flush_rect.right = ((src_rect.u1.x1 + x + UNLOCK_TEX_SIZE > src_rect.u3.x2) ?
3276                                             src_rect.u3.x2 :
3277                                             (src_rect.u1.x1 + x + UNLOCK_TEX_SIZE));
3278                         
3279                         upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3280                         
3281                         glBegin(GL_QUADS);
3282                         glTexCoord2f(0.0, 0.0);
3283                         glVertex3d(rect.u1.x1 + (x * x_stretch),
3284                                    rect.u2.y1 + (y * y_stretch),
3285                                    0.5);
3286                         glTexCoord2f(1.0, 0.0);
3287                         glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3288                                    rect.u2.y1 + (y * y_stretch),
3289                                    0.5);
3290                         glTexCoord2f(1.0, 1.0);
3291                         glVertex3d(rect.u1.x1 + ((x + UNLOCK_TEX_SIZE) * x_stretch),
3292                                    rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3293                                    0.5);
3294                         glTexCoord2f(0.0, 1.0);
3295                         glVertex3d(rect.u1.x1 + (x * x_stretch),
3296                                    rect.u2.y1 + ((y + UNLOCK_TEX_SIZE) * y_stretch),
3297                                    0.5);
3298                         glEnd();
3299                     }
3300                 }
3301                 
3302                 upload_surface_to_tex_memory_release();
3303                 d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, ((dwFlags & DDBLT_KEYSRC) != 0));
3304                 
3305                 if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3306                     ((buffer_type == WINE_GL_BUFFER_BACK)  && (prev_draw == GL_FRONT)))
3307                     glDrawBuffer(prev_draw);
3308                 
3309                 LEAVE_GL();
3310
3311                 return DD_OK;           
3312             }
3313         }
3314     }
3315     return DDERR_INVALIDPARAMS;
3316 }
3317
3318 HRESULT
3319 d3ddevice_bltfast(IDirectDrawSurfaceImpl *This, DWORD dstx,
3320                   DWORD dsty, LPDIRECTDRAWSURFACE7 src,
3321                   LPRECT rsrc, DWORD trans)
3322 {
3323     RECT rsrc2;
3324     RECT rdst;
3325     IDirectDrawSurfaceImpl *src_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, src);
3326     IDirect3DDeviceGLImpl *gl_d3d_dev = (IDirect3DDeviceGLImpl *) This->d3ddevice;
3327     WINE_GL_BUFFER_TYPE buffer_type;
3328     GLenum prev_draw;
3329     DWORD opt_bitmap;
3330     BOOLEAN initial;
3331     int width, height, x, y;
3332     
3333     /* Cannot support DSTCOLORKEY blitting... */
3334     if ((trans & DDBLTFAST_DESTCOLORKEY) != 0) return DDERR_INVALIDPARAMS;
3335
3336     if (rsrc == NULL) {
3337         WARN("rsrc is NULL - getting the whole surface !!\n");
3338         rsrc = &rsrc2;
3339         rsrc->left = rsrc->top = 0;
3340         rsrc->right = src_impl->surface_desc.dwWidth;
3341         rsrc->bottom = src_impl->surface_desc.dwHeight;
3342     } else {
3343         rsrc2 = *rsrc;
3344         rsrc = &rsrc2;
3345     }
3346
3347     rdst.left = dstx;
3348     rdst.top = dsty;
3349     rdst.right = dstx + (rsrc->right - rsrc->left);
3350     if (rdst.right > This->surface_desc.dwWidth) {
3351         rsrc->right -= (This->surface_desc.dwWidth - rdst.right);
3352         rdst.right = This->surface_desc.dwWidth;
3353     }
3354     rdst.bottom = dsty + (rsrc->bottom - rsrc->top);
3355     if (rdst.bottom > This->surface_desc.dwHeight) {
3356         rsrc->bottom -= (This->surface_desc.dwHeight - rdst.bottom);
3357         rdst.bottom = This->surface_desc.dwHeight;
3358     }
3359
3360     width = rsrc->right - rsrc->left;
3361     height = rsrc->bottom - rsrc->top;
3362     
3363     if (setup_rect_and_surface_for_blt(This, &buffer_type, (D3DRECT *) &rdst) != DD_OK) return DDERR_INVALIDPARAMS;
3364
3365     TRACE(" using BltFast memory to frame buffer override.\n");
3366     
3367     ENTER_GL();
3368     
3369     opt_bitmap = d3ddevice_set_state_for_flush(This->d3ddevice, &rdst, (trans & DDBLTFAST_SRCCOLORKEY) != 0, &initial);
3370     
3371     if (upload_surface_to_tex_memory_init(src_impl, 0, &gl_d3d_dev->current_internal_format,
3372                                           initial, (trans & DDBLTFAST_SRCCOLORKEY) != 0,
3373                                           UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3374         ERR(" unsupported pixel format at memory to buffer Blt override.\n");
3375         LEAVE_GL();
3376         return DDERR_INVALIDPARAMS;
3377     }
3378     
3379     glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3380     if (buffer_type == WINE_GL_BUFFER_FRONT)
3381         glDrawBuffer(GL_FRONT);
3382     else
3383         glDrawBuffer(GL_BACK);
3384     
3385     /* Now the serious stuff happens. This is basically the same code that for the memory
3386        flush to frame buffer but with different rectangles for source and destination :-) */
3387     for (y = 0; y < height; y += UNLOCK_TEX_SIZE) {
3388         RECT flush_rect;
3389         
3390         flush_rect.top    = rsrc->top + y;
3391         flush_rect.bottom = ((rsrc->top + y + UNLOCK_TEX_SIZE > rsrc->bottom) ?
3392                              rsrc->bottom :
3393                              (rsrc->top + y + UNLOCK_TEX_SIZE));
3394         
3395         for (x = 0; x < width; x += UNLOCK_TEX_SIZE) {
3396             flush_rect.left  = rsrc->left + x;
3397             flush_rect.right = ((rsrc->left + x + UNLOCK_TEX_SIZE > rsrc->right) ?
3398                                 rsrc->right :
3399                                 (rsrc->left + x + UNLOCK_TEX_SIZE));
3400             
3401             upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3402             
3403             glBegin(GL_QUADS);
3404             glTexCoord2f(0.0, 0.0);
3405             glVertex3d(rdst.left + x,
3406                        rdst.top + y,
3407                        0.5);
3408             glTexCoord2f(1.0, 0.0);
3409             glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3410                        rdst.top + y,
3411                        0.5);
3412             glTexCoord2f(1.0, 1.0);
3413             glVertex3d(rdst.left + (x + UNLOCK_TEX_SIZE),
3414                        rdst.top + (y + UNLOCK_TEX_SIZE),
3415                        0.5);
3416             glTexCoord2f(0.0, 1.0);
3417             glVertex3d(rdst.left + x,
3418                        rdst.top + (y + UNLOCK_TEX_SIZE),
3419                        0.5);
3420             glEnd();
3421         }
3422     }
3423     
3424     upload_surface_to_tex_memory_release();
3425     d3ddevice_restore_state_after_flush(This->d3ddevice, opt_bitmap, (trans & DDBLTFAST_SRCCOLORKEY) != 0);
3426     
3427     if (((buffer_type == WINE_GL_BUFFER_FRONT) && (prev_draw == GL_BACK)) ||
3428         ((buffer_type == WINE_GL_BUFFER_BACK)  && (prev_draw == GL_FRONT)))
3429         glDrawBuffer(prev_draw);
3430     
3431     LEAVE_GL();
3432     
3433     return DD_OK;
3434 }
3435
3436 void
3437 d3ddevice_set_ortho(IDirect3DDeviceImpl *This)
3438 {
3439     GLfloat height, width;
3440     GLfloat trans_mat[16];
3441
3442     TRACE("(%p)\n", This);
3443     
3444     width = This->surface->surface_desc.dwWidth;
3445     height = This->surface->surface_desc.dwHeight;
3446     
3447     /* The X axis is straighforward.. For the Y axis, we need to convert 'D3D' screen coordinates
3448      * to OpenGL screen coordinates (ie the upper left corner is not the same).
3449      */
3450     trans_mat[ 0] = 2.0 / width;  trans_mat[ 4] = 0.0;           trans_mat[ 8] = 0.0;    trans_mat[12] = -1.0;
3451     trans_mat[ 1] = 0.0;          trans_mat[ 5] = -2.0 / height; trans_mat[ 9] = 0.0;    trans_mat[13] =  1.0;
3452 #if 0
3453     /* It has been checked that in Messiah, which mixes XYZ and XYZRHZ vertex format in the same scene,
3454      * that the Z coordinate needs to be given to GL unchanged.
3455      */
3456     trans_mat[ 2] = 0.0;          trans_mat[ 6] = 0.0;           trans_mat[10] = 2.0;    trans_mat[14] = -1.0;
3457 #endif
3458     trans_mat[ 2] = 0.0;          trans_mat[ 6] = 0.0;           trans_mat[10] = 1.0;    trans_mat[14] =  0.0;
3459     trans_mat[ 3] = 0.0;          trans_mat[ 7] = 0.0;           trans_mat[11] = 0.0;    trans_mat[15] =  1.0;
3460     
3461     ENTER_GL();
3462     glMatrixMode(GL_MODELVIEW);
3463     glLoadIdentity();
3464     /* See the OpenGL Red Book for an explanation of the following translation (in the OpenGL
3465        Correctness Tips section).
3466        
3467        Basically, from what I understood, if the game does not filter the font texture,
3468        as the 'real' pixel will lie at the middle of the two texels, OpenGL may choose the wrong
3469        one and we will have strange artifacts (as the rounding and stuff may give different results
3470        for different pixels, ie sometimes take the left pixel, sometimes the right).
3471     */
3472     glTranslatef(0.375, 0.375, 0);
3473     glMatrixMode(GL_PROJECTION);
3474     glLoadMatrixf(trans_mat);
3475     LEAVE_GL();
3476 }
3477
3478 void
3479 d3ddevice_set_matrices(IDirect3DDeviceImpl *This, DWORD matrices,
3480                        D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat)
3481 {
3482     TRACE("(%p,%08lx,%p,%p,%p)\n", This, matrices, world_mat, view_mat, proj_mat);
3483     
3484     ENTER_GL();
3485     if ((matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED)) != 0) {
3486         glMatrixMode(GL_MODELVIEW);
3487         glLoadMatrixf((float *) view_mat);
3488
3489         /* Now also re-loads all the Lights and Clipping Planes using the new matrices */
3490         if (This->state_block.render_state[D3DRENDERSTATE_CLIPPING - 1] != FALSE) {
3491             GLint i;
3492             DWORD runner;
3493             for (i = 0, runner = 0x00000001; i < This->max_clipping_planes; i++, runner <<= 1) {
3494                 if (runner & This->state_block.render_state[D3DRENDERSTATE_CLIPPLANEENABLE - 1]) {
3495                     GLdouble plane[4];
3496
3497                     plane[0] = This->clipping_planes[i].plane[0];
3498                     plane[1] = This->clipping_planes[i].plane[1];
3499                     plane[2] = This->clipping_planes[i].plane[2];
3500                     plane[3] = This->clipping_planes[i].plane[3];
3501                     
3502                     glClipPlane( GL_CLIP_PLANE0 + i, (const GLdouble*) (&plane) );
3503                 }
3504             }
3505         }
3506         if (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] != FALSE) {
3507             GLint i;
3508
3509             for (i = 0; i < This->max_active_lights; i++ )
3510             {
3511                 DWORD dwLightIndex = This->active_lights[i];
3512                 if (dwLightIndex != ~0)
3513                 {
3514                     LPD3DLIGHT7 pLight = &This->light_parameters[dwLightIndex];
3515                     switch (pLight->dltType)
3516                     {
3517                         case D3DLIGHT_DIRECTIONAL: {
3518                             float direction[4];
3519                             float cut_off = 180.0;
3520                             
3521                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &pLight->dcvAmbient);
3522                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &pLight->dcvDiffuse);
3523                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3524                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3525                             
3526                             direction[0] = pLight->dvDirection.u1.x;
3527                             direction[1] = pLight->dvDirection.u2.y;
3528                             direction[2] = pLight->dvDirection.u3.z;
3529                             direction[3] = 0.0;
3530                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) direction);
3531                         } break;
3532
3533                         case D3DLIGHT_POINT: {
3534                             float position[4];
3535                             float cut_off = 180.0;
3536                             
3537                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &pLight->dcvAmbient);
3538                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &pLight->dcvDiffuse);
3539                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3540                             position[0] = pLight->dvPosition.u1.x;
3541                             position[1] = pLight->dvPosition.u2.y;
3542                             position[2] = pLight->dvPosition.u3.z;
3543                             position[3] = 1.0;
3544                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3545                             glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3546                             glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3547                             glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3548                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3549                         } break;
3550
3551                         case D3DLIGHT_SPOT: {
3552                             float direction[4];
3553                             float position[4];
3554                             float cut_off = 90.0 * (This->light_parameters[i].dvPhi / M_PI);
3555                             
3556                             glLightfv(GL_LIGHT0 + i, GL_AMBIENT,  (float *) &pLight->dcvAmbient);
3557                             glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,  (float *) &pLight->dcvDiffuse);
3558                             glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (float *) &pLight->dcvSpecular);
3559                             
3560                             direction[0] = pLight->dvDirection.u1.x;
3561                             direction[1] = pLight->dvDirection.u2.y;
3562                             direction[2] = pLight->dvDirection.u3.z;
3563                             direction[3] = 0.0;
3564                             glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, (float *) direction);
3565                             position[0] = pLight->dvPosition.u1.x;
3566                             position[1] = pLight->dvPosition.u2.y;
3567                             position[2] = pLight->dvPosition.u3.z;
3568                             position[3] = 1.0;
3569                             glLightfv(GL_LIGHT0 + i, GL_POSITION, (float *) position);
3570                             glLightfv(GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &pLight->dvAttenuation0);
3571                             glLightfv(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &pLight->dvAttenuation1);
3572                             glLightfv(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &pLight->dvAttenuation2);
3573                             glLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &cut_off);
3574                             glLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &pLight->dvFalloff);
3575                         } break;
3576
3577                         default:
3578                             /* No warning here as it's already done at light setting */
3579                             break;
3580                     }
3581                 }
3582             }
3583         }
3584         
3585         glMultMatrixf((float *) world_mat);
3586     }
3587     if ((matrices & PROJMAT_CHANGED) != 0) {
3588         glMatrixMode(GL_PROJECTION);
3589         glLoadMatrixf((float *) proj_mat);
3590     }
3591     LEAVE_GL();
3592 }
3593
3594 void
3595 d3ddevice_matrices_updated(IDirect3DDeviceImpl *This, DWORD matrices)
3596 {
3597     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
3598     DWORD tex_mat, tex_stage;
3599
3600     TRACE("(%p,%08lx)\n", This, matrices);
3601     
3602     if (matrices & (VIEWMAT_CHANGED|WORLDMAT_CHANGED|PROJMAT_CHANGED)) {
3603         if (glThis->transform_state == GL_TRANSFORM_NORMAL) {
3604             /* This will force an update of the transform state at the next drawing. */
3605             glThis->transform_state = GL_TRANSFORM_NONE;
3606         }
3607     }
3608     if (matrices & (TEXMAT0_CHANGED|TEXMAT1_CHANGED|TEXMAT2_CHANGED|TEXMAT3_CHANGED|
3609                     TEXMAT4_CHANGED|TEXMAT5_CHANGED|TEXMAT6_CHANGED|TEXMAT7_CHANGED))
3610     {
3611         ENTER_GL();
3612         for (tex_mat = TEXMAT0_CHANGED, tex_stage = 0; tex_mat <= TEXMAT7_CHANGED; tex_mat <<= 1, tex_stage++) {
3613             GLenum unit = GL_TEXTURE0_WINE + tex_stage;
3614             if (matrices & tex_mat) {
3615                 if (This->state_block.texture_stage_state[tex_stage][D3DTSS_TEXTURETRANSFORMFLAGS - 1] != D3DTTFF_DISABLE) {
3616                     int is_identity = (memcmp(This->tex_mat[tex_stage], id_mat, 16 * sizeof(D3DVALUE)) != 0);
3617
3618                     if (This->tex_mat_is_identity[tex_stage] != is_identity) {
3619                         if (glThis->current_active_tex_unit != unit) {
3620                             GL_extensions.glActiveTexture(unit);
3621                             glThis->current_active_tex_unit = unit;
3622                         }
3623                         glMatrixMode(GL_TEXTURE);
3624                         glLoadMatrixf((float *) This->tex_mat[tex_stage]);
3625                     }
3626                     This->tex_mat_is_identity[tex_stage] = is_identity;
3627                 } else {
3628                     if (This->tex_mat_is_identity[tex_stage] == FALSE) {
3629                         if (glThis->current_active_tex_unit != unit) {
3630                             GL_extensions.glActiveTexture(unit);
3631                             glThis->current_active_tex_unit = unit;
3632                         }
3633                         glMatrixMode(GL_TEXTURE);
3634                         glLoadIdentity();
3635                         This->tex_mat_is_identity[tex_stage] = TRUE;
3636                     }
3637                 }
3638             }
3639         }
3640         LEAVE_GL();
3641     }
3642 }
3643
3644 /* TODO for both these functions :
3645     - change / restore OpenGL parameters for pictures transfers in case they are ever modified
3646       by other OpenGL code in D3D
3647     - handle the case where no 'Begin / EndScene' was done between two locks
3648     - handle the rectangles in the unlock too
3649     - handle pitch correctly...
3650 */
3651 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
3652 {
3653     IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3654     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3655     WINE_GL_BUFFER_TYPE buffer_type;
3656     RECT loc_rect;
3657     
3658     if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3659         buffer_type = WINE_GL_BUFFER_FRONT;
3660         if ((gl_d3d_dev->state[WINE_GL_BUFFER_FRONT] != SURFACE_GL) &&
3661             (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] != This)) {
3662             ERR("Change of front buffer.. Expect graphic corruptions !\n");
3663         }
3664         gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT] = This;
3665     } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3666         buffer_type = WINE_GL_BUFFER_BACK;
3667         if ((gl_d3d_dev->state[WINE_GL_BUFFER_BACK] != SURFACE_GL) &&
3668             (gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] != This)) {
3669             ERR("Change of back buffer.. Expect graphic corruptions !\n");
3670         }
3671         gl_d3d_dev->lock_surf[WINE_GL_BUFFER_BACK] = This;
3672     } else {
3673         ERR("Wrong surface type for locking !\n");
3674         return;
3675     }
3676
3677     if (pRect == NULL) {
3678         loc_rect.top = 0;
3679         loc_rect.left = 0;
3680         loc_rect.bottom = This->surface_desc.dwHeight;
3681         loc_rect.right = This->surface_desc.dwWidth;
3682         pRect = &loc_rect;
3683     }
3684     
3685     /* Try to acquire the device critical section */
3686     EnterCriticalSection(&(d3d_dev->crit));
3687     
3688     if (gl_d3d_dev->lock_rect_valid[buffer_type]) {
3689         ERR("Two consecutive locks on %s buffer... Expect problems !\n",
3690             (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3691     }
3692     gl_d3d_dev->lock_rect_valid[buffer_type] = TRUE;
3693     
3694     if (gl_d3d_dev->state[buffer_type] != SURFACE_GL) {
3695         /* Check if the new rectangle is in the previous one or not.
3696            If it is not, flush first the previous locks on screen.
3697         */
3698         if ((pRect->top    < gl_d3d_dev->lock_rect[buffer_type].top) ||
3699             (pRect->left   < gl_d3d_dev->lock_rect[buffer_type].left) ||
3700             (pRect->right  > gl_d3d_dev->lock_rect[buffer_type].right) ||
3701             (pRect->bottom > gl_d3d_dev->lock_rect[buffer_type].bottom)) {
3702             if (gl_d3d_dev->state[buffer_type] == SURFACE_MEMORY_DIRTY) {
3703                 TRACE(" flushing back to %s buffer as new rect : (%ldx%ld) - (%ldx%ld) not included in old rect : (%ldx%ld) - (%ldx%ld)\n",
3704                       (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3705                       pRect->left, pRect->top, pRect->right, pRect->bottom,
3706                       gl_d3d_dev->lock_rect[buffer_type].left, gl_d3d_dev->lock_rect[buffer_type].top,
3707                       gl_d3d_dev->lock_rect[buffer_type].right, gl_d3d_dev->lock_rect[buffer_type].bottom);
3708                 d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[buffer_type]), gl_d3d_dev->lock_surf[buffer_type]);
3709             }
3710             gl_d3d_dev->state[buffer_type] = SURFACE_GL;
3711             gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3712         }
3713         /* In the other case, do not upgrade the locking rectangle as it's no need... */
3714     } else {
3715         gl_d3d_dev->lock_rect[buffer_type] = *pRect;
3716     }
3717     
3718     if (gl_d3d_dev->state[buffer_type] == SURFACE_GL) {
3719         /* If the surface is already in memory, no need to do anything here... */
3720         GLenum buffer_format;
3721         GLenum buffer_color;
3722         int y;
3723         char *dst;
3724
3725         TRACE(" copying %s buffer to main memory with rectangle (%ldx%ld) - (%ldx%ld).\n", (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"),
3726               pRect->left, pRect->top, pRect->right, pRect->bottom);
3727         
3728         /* Note that here we cannot do 'optmizations' about the WriteOnly flag... Indeed, a game
3729            may only write to the device... But when we will blit it back to the screen, we need
3730            also to blit correctly the parts the application did not overwrite... */
3731
3732         if (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_RGB) != 0) &&
3733             (((This->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) == 0) ||
3734              (This->surface_desc.u4.ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000))) {
3735             if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) &&
3736                 (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xF800) &&
3737                 (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x07E0) &&
3738                 (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x001F)) {
3739                 buffer_format = GL_UNSIGNED_SHORT_5_6_5;
3740                 buffer_color = GL_RGB;
3741             } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 24) &&
3742                        (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0xFF0000) &&
3743                        (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x00FF00) &&
3744                        (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x0000FF)) {
3745                 buffer_format = GL_UNSIGNED_BYTE;
3746                 buffer_color = GL_RGB;
3747             } else if ((This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 32) &&
3748                        (This->surface_desc.u4.ddpfPixelFormat.u2.dwRBitMask == 0x00FF0000) &&
3749                        (This->surface_desc.u4.ddpfPixelFormat.u3.dwGBitMask == 0x0000FF00) &&
3750                        (This->surface_desc.u4.ddpfPixelFormat.u4.dwBBitMask == 0x000000FF)) {
3751                 buffer_format = GL_UNSIGNED_INT_8_8_8_8_REV;
3752                 buffer_color = GL_BGRA;
3753             } else {
3754                 ERR(" unsupported pixel format at device locking.\n");
3755                 return;
3756             }
3757         } else {
3758             ERR(" unsupported pixel format at device locking - alpha on frame buffer.\n");
3759             return;
3760         }
3761
3762         ENTER_GL();
3763         
3764         if (buffer_type == WINE_GL_BUFFER_FRONT)
3765             /* Application wants to lock the front buffer */
3766             glReadBuffer(GL_FRONT);
3767         else 
3768             /* Application wants to lock the back buffer */
3769             glReadBuffer(GL_BACK);
3770
3771         dst = ((char *)This->surface_desc.lpSurface) +
3772           (pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
3773
3774         if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
3775             /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
3776              * could not be bothered considering the rare cases where it may be useful :-)
3777              */
3778             for (y = (This->surface_desc.dwHeight - pRect->top - 1);
3779                  y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
3780                  y--) {
3781                 glReadPixels(pRect->left, y,
3782                              pRect->right - pRect->left, 1,
3783                              buffer_color, buffer_format, dst);
3784                 dst += This->surface_desc.u1.lPitch;
3785             }
3786         } else {
3787             /* Faster path for surface copy. Note that I can use static variables here as I am
3788              * protected by the OpenGL critical section so this function won't be called by
3789              * two threads at the same time.
3790              */
3791             static char *buffer = NULL;
3792             static int buffer_width = 0;
3793             char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
3794             int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
3795             
3796             glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
3797                          pRect->right - pRect->left, pRect->bottom - pRect->top,
3798                          buffer_color, buffer_format, dst);
3799
3800             if (current_width > buffer_width) {
3801                 if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
3802                 buffer_width = current_width;
3803                 buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
3804             }
3805             for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
3806                 memcpy(buffer, dst, current_width);
3807                 memcpy(dst, dst2, current_width);
3808                 memcpy(dst2, buffer, current_width);
3809                 dst  += This->surface_desc.u1.lPitch;
3810                 dst2 -= This->surface_desc.u1.lPitch;
3811             }
3812         }
3813
3814         gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;
3815         
3816 #if 0
3817         /* I keep this code here as it's very useful to debug :-) */
3818         {
3819             static int flush_count = 0;
3820             char buf[128];
3821             FILE *f;
3822             
3823             if ((++flush_count % 50) == 0) {
3824                 sprintf(buf, "lock_%06d.pnm", flush_count);
3825                 f = fopen(buf, "wb");
3826                 DDRAW_dump_surface_to_disk(This, f);
3827             }
3828         }
3829 #endif
3830         
3831         LEAVE_GL();
3832     }
3833 }
3834
3835 static void d3ddevice_flush_to_frame_buffer(IDirect3DDeviceImpl *d3d_dev, LPCRECT pRect, IDirectDrawSurfaceImpl *surf) {
3836     RECT loc_rect;
3837     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3838     int x, y;
3839     BOOLEAN initial;
3840     DWORD opt_bitmap;
3841     
3842     /* Note : no need here to lock the 'device critical section' as we are already protected by
3843        the GL critical section. */
3844
3845     if (pRect == NULL) {
3846         loc_rect.top = 0;
3847         loc_rect.left = 0;
3848         loc_rect.bottom = d3d_dev->surface->surface_desc.dwHeight;
3849         loc_rect.right = d3d_dev->surface->surface_desc.dwWidth;
3850         pRect = &loc_rect;
3851     }
3852     
3853     TRACE(" flushing memory back to screen memory (%ld,%ld) x (%ld,%ld).\n", pRect->top, pRect->left, pRect->right, pRect->bottom);
3854
3855     opt_bitmap = d3ddevice_set_state_for_flush(d3d_dev, pRect, FALSE, &initial);
3856     
3857     if (upload_surface_to_tex_memory_init(surf, 0, &gl_d3d_dev->current_internal_format,
3858                                           initial, FALSE, UNLOCK_TEX_SIZE, UNLOCK_TEX_SIZE) != DD_OK) {
3859         ERR(" unsupported pixel format at frame buffer flush.\n");
3860         return;
3861     }
3862         
3863     for (y = pRect->top; y < pRect->bottom; y += UNLOCK_TEX_SIZE) {
3864         RECT flush_rect;
3865         
3866         flush_rect.top = y;
3867         flush_rect.bottom = (y + UNLOCK_TEX_SIZE > pRect->bottom) ? pRect->bottom : (y + UNLOCK_TEX_SIZE);
3868
3869         for (x = pRect->left; x < pRect->right; x += UNLOCK_TEX_SIZE) {
3870             /* First, upload the texture... */
3871             flush_rect.left = x;
3872             flush_rect.right = (x + UNLOCK_TEX_SIZE > pRect->right)  ? pRect->right  : (x + UNLOCK_TEX_SIZE);
3873
3874             upload_surface_to_tex_memory(&flush_rect, 0, 0, &(gl_d3d_dev->surface_ptr));
3875
3876             glBegin(GL_QUADS);
3877             glTexCoord2f(0.0, 0.0);
3878             glVertex3d(x, y, 0.5);
3879             glTexCoord2f(1.0, 0.0);
3880             glVertex3d(x + UNLOCK_TEX_SIZE, y, 0.5);
3881             glTexCoord2f(1.0, 1.0);
3882             glVertex3d(x + UNLOCK_TEX_SIZE, y + UNLOCK_TEX_SIZE, 0.5);
3883             glTexCoord2f(0.0, 1.0);
3884             glVertex3d(x, y + UNLOCK_TEX_SIZE, 0.5);
3885             glEnd();
3886         }
3887     }
3888     
3889     upload_surface_to_tex_memory_release();
3890     d3ddevice_restore_state_after_flush(d3d_dev, opt_bitmap, FALSE);
3891     
3892 #if 0
3893     /* I keep this code here as it's very useful to debug :-) */
3894     {
3895         static int flush_count = 0;
3896         char buf[128];
3897         FILE *f;
3898
3899         if ((++flush_count % 50) == 0) {
3900             sprintf(buf, "flush_%06d.pnm", flush_count);
3901             f = fopen(buf, "wb");
3902             DDRAW_dump_surface_to_disk(surf, f);
3903         }
3904     }
3905 #endif
3906 }
3907
3908 static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect)
3909 {
3910     WINE_GL_BUFFER_TYPE buffer_type;
3911     IDirect3DDeviceImpl *d3d_dev = This->d3ddevice;
3912     IDirect3DDeviceGLImpl* gl_d3d_dev = (IDirect3DDeviceGLImpl*) d3d_dev;
3913   
3914     if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
3915         buffer_type = WINE_GL_BUFFER_FRONT;
3916     } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) {
3917         buffer_type = WINE_GL_BUFFER_BACK;
3918     } else {
3919         ERR("Wrong surface type for locking !\n");
3920         return;
3921     }
3922
3923     if (gl_d3d_dev->lock_rect_valid[buffer_type] == FALSE) {
3924         ERR("Unlock without prior lock on %s buffer... Expect problems !\n",
3925             (buffer_type == WINE_GL_BUFFER_BACK ? "back" : "front"));
3926     }
3927     gl_d3d_dev->lock_rect_valid[buffer_type] = FALSE;
3928     
3929     /* First, check if we need to do anything. For the backbuffer, flushing is done at the next 3D activity. */
3930     if ((This->lastlocktype & DDLOCK_READONLY) == 0) {
3931         if (buffer_type == WINE_GL_BUFFER_FRONT) {
3932             GLenum prev_draw;
3933
3934             TRACE(" flushing front buffer immediately on screen.\n");
3935             
3936             ENTER_GL();
3937             glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
3938             glDrawBuffer(GL_FRONT);
3939             /* Note: we do not use the application provided lock rectangle but our own stored at
3940                      lock time. This is because in old D3D versions, the 'lock' parameter did not
3941                      exist.
3942             */
3943             d3d_dev->flush_to_framebuffer(d3d_dev, &(gl_d3d_dev->lock_rect[WINE_GL_BUFFER_FRONT]), gl_d3d_dev->lock_surf[WINE_GL_BUFFER_FRONT]);
3944             glDrawBuffer(prev_draw);
3945             LEAVE_GL();
3946         } else {
3947             gl_d3d_dev->state[WINE_GL_BUFFER_BACK] = SURFACE_MEMORY_DIRTY;
3948         }
3949     }
3950
3951     /* And 'frees' the device critical section */
3952     LeaveCriticalSection(&(d3d_dev->crit));
3953 }
3954
3955 static void
3956 apply_texture_state(IDirect3DDeviceImpl *This)
3957 {
3958     int stage, state;
3959     
3960     /* Initialize texture stages states */
3961     for (stage = 0; stage < MAX_TEXTURES; stage++) {
3962        for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
3963            if (This->state_block.set_flags.texture_stage_state[stage][state]) {
3964                IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
3965                                                      stage, state + 1, This->state_block.texture_stage_state[stage][state]);
3966            }
3967        }
3968     }
3969 }     
3970
3971 HRESULT
3972 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, int version)
3973 {
3974     IDirect3DDeviceImpl *object;
3975     IDirect3DDeviceGLImpl *gl_object;
3976     IDirectDrawSurfaceImpl *surf;
3977     HDC device_context;
3978     XVisualInfo *vis;
3979     int num;
3980     int tex_num;
3981     XVisualInfo template;
3982     GLenum buffer = GL_FRONT;
3983     int light;
3984     
3985     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl));
3986     if (object == NULL) return DDERR_OUTOFMEMORY;
3987
3988     gl_object = (IDirect3DDeviceGLImpl *) object;
3989     
3990     object->ref = 1;
3991     object->d3d = d3d;
3992     object->surface = surface;
3993     object->set_context = set_context;
3994     object->clear = d3ddevice_clear_back;
3995     object->set_matrices = d3ddevice_set_matrices;
3996     object->matrices_updated = d3ddevice_matrices_updated;
3997     object->flush_to_framebuffer = d3ddevice_flush_to_frame_buffer;
3998     object->version = version;
3999     
4000     TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
4001
4002     InitializeCriticalSection(&(object->crit));
4003
4004     TRACE(" device critical section : %p\n", &(object->crit));
4005
4006     device_context = GetDC(surface->ddraw_owner->window);
4007     gl_object->display = get_display(device_context);
4008     gl_object->drawable = get_drawable(device_context);
4009     ReleaseDC(surface->ddraw_owner->window,device_context);
4010
4011     ENTER_GL();
4012     template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
4013     vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num);
4014     if (vis == NULL) {
4015         HeapFree(GetProcessHeap(), 0, object);
4016         ERR("No visual found !\n");
4017         LEAVE_GL();
4018         return DDERR_INVALIDPARAMS;
4019     } else {
4020         TRACE(" visual found\n");
4021     }
4022
4023     gl_object->gl_context = glXCreateContext(gl_object->display, vis,
4024                                              NULL, GL_TRUE);
4025
4026     if (gl_object->gl_context == NULL) {
4027         HeapFree(GetProcessHeap(), 0, object);
4028         ERR("Error in context creation !\n");
4029         LEAVE_GL();
4030         return DDERR_INVALIDPARAMS;
4031     } else {
4032         TRACE(" context created (%p)\n", gl_object->gl_context);
4033     }
4034     
4035     /* Look for the front buffer and override its surface's Flip method (if in double buffering) */
4036     for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4037         if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) {
4038             surf->aux_ctx  = (LPVOID) object;
4039             surf->aux_data = (LPVOID) gl_object->drawable;
4040             surf->aux_flip = opengl_flip;
4041             buffer =  GL_BACK;
4042             break;
4043         }
4044     }
4045     /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */
4046     if (surf == NULL) {
4047         TRACE(" no double buffering : drawing on the front buffer\n");
4048         buffer = GL_FRONT;
4049     }
4050     
4051     for (surf = surface; surf != NULL; surf = surf->surface_owner) {
4052         IDirectDrawSurfaceImpl *surf2;
4053         for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
4054         for (; surf2 != NULL; surf2 = surf2->next_attached) {
4055             TRACE(" checking surface %p :", surf2);
4056             if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
4057                 ((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
4058                 /* Override the Lock / Unlock function for all these surfaces */
4059                 surf2->lock_update_prev = surf2->lock_update;
4060                 surf2->lock_update = d3ddevice_lock_update;
4061                 surf2->unlock_update_prev = surf2->unlock_update;
4062                 surf2->unlock_update = d3ddevice_unlock_update;
4063                 /* And install also the blt / bltfast overrides */
4064                 surf2->aux_blt = d3ddevice_blt;
4065                 surf2->aux_bltfast = d3ddevice_bltfast;
4066                 
4067                 TRACE(" overriding direct surface access.\n");
4068             } else {
4069                 TRACE(" no override.\n");
4070             }
4071             surf2->d3ddevice = object;
4072         }
4073     }
4074
4075     /* Set the various light parameters */
4076     object->num_set_lights = 0;
4077     object->max_active_lights = opengl_device_caps.dwMaxActiveLights;
4078     object->light_parameters = NULL;
4079     object->active_lights = HeapAlloc(GetProcessHeap(), 0,
4080         object->max_active_lights * sizeof(BOOLEAN));
4081     /* Fill the active light array with ~0, which is used to indicate an
4082        invalid light index. We don't use 0, because it's a valid light index. */
4083     for (light=0; light < object->max_active_lights; light++)
4084         object->active_lights[light] = ~0;
4085
4086     
4087     /* Allocate memory for the matrices */
4088     object->world_mat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4089     object->view_mat  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4090     object->proj_mat  = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4091     memcpy(object->world_mat, id_mat, 16 * sizeof(float));
4092     memcpy(object->view_mat , id_mat, 16 * sizeof(float));
4093     memcpy(object->proj_mat , id_mat, 16 * sizeof(float));
4094     for (tex_num = 0; tex_num < MAX_TEXTURES; tex_num++) {
4095         object->tex_mat[tex_num] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 16 * sizeof(float));
4096         memcpy(object->tex_mat[tex_num], id_mat, 16 * sizeof(float));
4097         object->tex_mat_is_identity[tex_num] = TRUE;
4098     }
4099     
4100     /* Initialisation */
4101     TRACE(" setting current context\n");
4102     object->set_context(object);
4103     TRACE(" current context set\n");
4104
4105     /* allocate the clipping planes */
4106     object->max_clipping_planes = opengl_device_caps.wMaxUserClipPlanes;
4107     object->clipping_planes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->max_clipping_planes * sizeof(d3d7clippingplane));
4108
4109     glHint(GL_FOG_HINT,GL_NICEST);
4110
4111     /* Initialize the various GL contexts to be in sync with what we store locally */
4112     glClearDepth(0.0);
4113     glClearStencil(0);
4114     glClearColor(0.0, 0.0, 0.0, 0.0);
4115     glDepthMask(GL_TRUE);
4116     gl_object->depth_mask = TRUE;
4117     glEnable(GL_DEPTH_TEST);
4118     gl_object->depth_test = TRUE;
4119     glDisable(GL_ALPHA_TEST);
4120     glDisable(GL_STENCIL_TEST);
4121     glDisable(GL_CULL_FACE);
4122     glDisable(GL_LIGHTING);
4123     glDisable(GL_BLEND);
4124     glDisable(GL_FOG);
4125     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4126     gl_object->current_tex_env = GL_REPLACE;
4127     gl_object->current_active_tex_unit = GL_TEXTURE0_WINE;
4128     if (GL_extensions.glActiveTexture != NULL) {
4129         GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
4130     }
4131     gl_object->current_alpha_test_ref = 0.0;
4132     gl_object->current_alpha_test_func = GL_ALWAYS;
4133     glAlphaFunc(GL_ALWAYS, 0.0);
4134     
4135     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4136     glDrawBuffer(buffer);
4137     glReadBuffer(buffer);
4138     /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */
4139     LEAVE_GL();
4140
4141     gl_object->state[WINE_GL_BUFFER_BACK] = SURFACE_GL;
4142     gl_object->state[WINE_GL_BUFFER_FRONT] = SURFACE_GL;
4143     
4144     /* fill_device_capabilities(d3d->ddraw); */    
4145     
4146     ICOM_INIT_INTERFACE(object, IDirect3DDevice,  VTABLE_IDirect3DDevice);
4147     ICOM_INIT_INTERFACE(object, IDirect3DDevice2, VTABLE_IDirect3DDevice2);
4148     ICOM_INIT_INTERFACE(object, IDirect3DDevice3, VTABLE_IDirect3DDevice3);
4149     ICOM_INIT_INTERFACE(object, IDirect3DDevice7, VTABLE_IDirect3DDevice7);
4150
4151     *obj = object;
4152
4153     TRACE(" creating implementation at %p.\n", *obj);
4154
4155     /* And finally warn D3D that this device is now present */
4156     object->d3d->d3d_added_device(object->d3d, object);
4157
4158     InitDefaultStateBlock(&object->state_block, object->version);
4159     /* Apply default render state and texture stage state values */
4160     apply_render_state(object, &object->state_block);
4161     apply_texture_state(object);
4162
4163     /* And fill the fog table with the default fog value */
4164     build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);
4165     
4166     return DD_OK;
4167 }
4168
4169 static void fill_opengl_primcaps(D3DPRIMCAPS *pc)
4170 {
4171     pc->dwSize = sizeof(*pc);
4172     pc->dwMiscCaps = D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLCCW | D3DPMISCCAPS_CULLCW |
4173       D3DPMISCCAPS_LINEPATTERNREP | D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ;
4174     pc->dwRasterCaps = D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_FOGTABLE |
4175       D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
4176           D3DPRASTERCAPS_ZFOG;
4177     if (GL_extensions.mipmap_lodbias) {
4178         pc->dwRasterCaps |= D3DPRASTERCAPS_MIPMAPLODBIAS;
4179     }
4180     pc->dwZCmpCaps = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4181       D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4182     pc->dwSrcBlendCaps  = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_DESTCOLOR | D3DPBLENDCAPS_INVDESTCOLOR |
4183       D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4184         D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4185     pc->dwDestBlendCaps = D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR | D3DPBLENDCAPS_INVSRCCOLOR |
4186       D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_SRCALPHASAT |
4187         D3DPBLENDCAPS_BOTHSRCALPHA | D3DPBLENDCAPS_BOTHINVSRCALPHA;
4188     pc->dwAlphaCmpCaps  = D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_EQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_GREATEREQUAL |
4189       D3DPCMPCAPS_LESS | D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_NEVER | D3DPCMPCAPS_NOTEQUAL;
4190     pc->dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDRGB |
4191       D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDRGB;
4192     pc->dwTextureCaps = D3DPTEXTURECAPS_ALPHA | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_PERSPECTIVE |
4193       D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_TRANSPARENCY;
4194     pc->dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST |
4195       D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_MIPNEAREST | D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_MAGFLINEAR |
4196           D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MIPFLINEAR |
4197               D3DPTFILTERCAPS_MIPFPOINT;
4198     pc->dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL | D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4199       D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA | D3DPTBLENDCAPS_MODULATEMASK;
4200     pc->dwTextureAddressCaps = D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_CLAMP | D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_INDEPENDENTUV;
4201     if (GL_extensions.mirrored_repeat) {
4202         pc->dwTextureAddressCaps |= D3DPTADDRESSCAPS_MIRROR;
4203     }
4204     pc->dwStippleWidth = 32;
4205     pc->dwStippleHeight = 32;
4206 }
4207
4208 static void fill_caps(void)
4209 {
4210     GLint max_clip_planes;
4211     GLint depth_bits;
4212     
4213     /* Fill first all the fields with default values which will be overriden later on with
4214        correct ones from the GL code
4215     */
4216     opengl_device_caps.dwDevCaps = D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_EXECUTESYSTEMMEMORY |
4217       D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
4218       D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY |
4219       /* D3D 7 capabilities */
4220       D3DDEVCAPS_DRAWPRIMITIVES2 /*| D3DDEVCAPS_HWTRANSFORMANDLIGHT*/ | D3DDEVCAPS_HWRASTERIZATION | D3DDEVCAPS_DRAWPRIMITIVES2EX;
4221     fill_opengl_primcaps(&(opengl_device_caps.dpcLineCaps));
4222     fill_opengl_primcaps(&(opengl_device_caps.dpcTriCaps));
4223     opengl_device_caps.dwDeviceRenderBitDepth  = DDBD_16|DDBD_24|DDBD_32;
4224     opengl_device_caps.dwMinTextureWidth  = 1;
4225     opengl_device_caps.dwMinTextureHeight = 1;
4226     opengl_device_caps.dwMaxTextureWidth  = 1024;
4227     opengl_device_caps.dwMaxTextureHeight = 1024;
4228     opengl_device_caps.dwMaxTextureRepeat = 16;
4229     opengl_device_caps.dwMaxTextureAspectRatio = 1024;
4230     opengl_device_caps.dwMaxAnisotropy = 0;
4231     opengl_device_caps.dvGuardBandLeft = 0.0;
4232     opengl_device_caps.dvGuardBandRight = 0.0;
4233     opengl_device_caps.dvGuardBandTop = 0.0;
4234     opengl_device_caps.dvGuardBandBottom = 0.0;
4235     opengl_device_caps.dvExtentsAdjust = 0.0;
4236     opengl_device_caps.dwStencilCaps = D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_INVERT | D3DSTENCILCAPS_KEEP |
4237       D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_ZERO;
4238     opengl_device_caps.dwTextureOpCaps = D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 | D3DTEXOPCAPS_MODULATE4X |
4239         D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED2X | D3DTEXOPCAPS_ADDSIGNED |
4240             D3DTEXOPCAPS_BLENDDIFFUSEALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHA | D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDCURRENTALPHA;
4241     if (GL_extensions.max_texture_units != 0) {
4242         opengl_device_caps.wMaxTextureBlendStages = GL_extensions.max_texture_units;
4243         opengl_device_caps.wMaxSimultaneousTextures = GL_extensions.max_texture_units;
4244         opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | GL_extensions.max_texture_units;
4245     } else {
4246         opengl_device_caps.wMaxTextureBlendStages = 1;
4247         opengl_device_caps.wMaxSimultaneousTextures = 1;
4248         opengl_device_caps.dwFVFCaps = D3DFVFCAPS_DONOTSTRIPELEMENTS | 1;
4249     }
4250     opengl_device_caps.dwMaxActiveLights = 16;
4251     opengl_device_caps.dvMaxVertexW = 100000000.0; /* No idea exactly what to put here... */
4252     opengl_device_caps.deviceGUID = IID_IDirect3DTnLHalDevice;
4253     opengl_device_caps.wMaxUserClipPlanes = 1;
4254     opengl_device_caps.wMaxVertexBlendMatrices = 0;
4255     opengl_device_caps.dwVertexProcessingCaps = D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
4256         D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER;
4257     opengl_device_caps.dwReserved1 = 0;
4258     opengl_device_caps.dwReserved2 = 0;
4259     opengl_device_caps.dwReserved3 = 0;
4260     opengl_device_caps.dwReserved4 = 0;
4261
4262     /* And now some GL overrides :-) */
4263     glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *) &opengl_device_caps.dwMaxTextureWidth);
4264     opengl_device_caps.dwMaxTextureHeight = opengl_device_caps.dwMaxTextureWidth;
4265     opengl_device_caps.dwMaxTextureAspectRatio = opengl_device_caps.dwMaxTextureWidth;
4266     TRACE(": max texture size = %ld\n", opengl_device_caps.dwMaxTextureWidth);
4267     
4268     glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &opengl_device_caps.dwMaxActiveLights);
4269     TRACE(": max active lights = %ld\n", opengl_device_caps.dwMaxActiveLights);
4270
4271     glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
4272     opengl_device_caps.wMaxUserClipPlanes = max_clip_planes;
4273     TRACE(": max clipping planes = %d\n", opengl_device_caps.wMaxUserClipPlanes);
4274
4275     glGetIntegerv(GL_DEPTH_BITS, &depth_bits);
4276     TRACE(": Z bits = %d\n", depth_bits);
4277     switch (depth_bits) {
4278         case 16: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16; break;
4279         case 24: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24; break;
4280         case 32:
4281         default: opengl_device_caps.dwDeviceZBufferBitDepth = DDBD_16|DDBD_24|DDBD_32; break;
4282     }
4283 }
4284
4285 BOOL
4286 d3ddevice_init_at_startup(void *gl_handle)
4287 {
4288     XVisualInfo template;
4289     XVisualInfo *vis;
4290     HDC device_context;
4291     Display *display;
4292     Visual *visual;
4293     Drawable drawable = (Drawable) GetPropA(GetDesktopWindow(), "__wine_x11_whole_window");
4294     XWindowAttributes win_attr;
4295     GLXContext gl_context;
4296     int num;
4297     const char *glExtensions;
4298     const char *glVersion;
4299     const char *glXExtensions = NULL;
4300     const void *(*pglXGetProcAddressARB)(const GLubyte *) = NULL;
4301     int major, minor, patch, num_parsed;
4302     
4303     TRACE("Initializing GL...\n");
4304
4305     if (!drawable)
4306     {
4307         WARN("x11drv not loaded - D3D support disabled!\n");
4308         return FALSE;
4309     }
4310     
4311     /* Get a default rendering context to have the 'caps' function query some info from GL */    
4312     device_context = GetDC(0);
4313     display = get_display(device_context);
4314     ReleaseDC(0, device_context);
4315
4316     ENTER_GL();
4317     if (XGetWindowAttributes(display, drawable, &win_attr)) {
4318         visual = win_attr.visual;
4319     } else {
4320         visual = DefaultVisual(display, DefaultScreen(display));
4321     }
4322     template.visualid = XVisualIDFromVisual(visual);
4323     vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
4324     if (vis == NULL) {
4325         LEAVE_GL();
4326         WARN("Error creating visual info for capabilities initialization - D3D support disabled !\n");
4327         return FALSE;
4328     }
4329     gl_context = glXCreateContext(display, vis, NULL, GL_TRUE);
4330
4331     if (gl_context == NULL) {
4332         LEAVE_GL();
4333         WARN("Error creating default context for capabilities initialization - D3D support disabled !\n");
4334         return FALSE;
4335     }
4336     if (glXMakeCurrent(display, drawable, gl_context) == False) {
4337         glXDestroyContext(display, gl_context);
4338         LEAVE_GL();
4339         WARN("Error setting default context as current for capabilities initialization - D3D support disabled !\n");
4340         return FALSE;   
4341     }
4342     
4343     /* Then, query all extensions */
4344     glXExtensions = glXQueryExtensionsString(display, DefaultScreen(display)); /* Note: not used right now but will for PBuffers */
4345     glExtensions = (const char *) glGetString(GL_EXTENSIONS);
4346     glVersion = (const char *) glGetString(GL_VERSION);
4347     if (gl_handle != NULL) {
4348         pglXGetProcAddressARB = wine_dlsym(gl_handle, "glXGetProcAddressARB", NULL, 0);
4349     }
4350     
4351     /* Parse the GL version string */
4352     num_parsed = sscanf(glVersion, "%d.%d.%d", &major, &minor, &patch);
4353     if (num_parsed == 1) {
4354         minor = 0;
4355         patch = 0;
4356     } else if (num_parsed == 2) {
4357         patch = 0;
4358     }
4359     TRACE("GL version %d.%d.%d\n", major, minor, patch);
4360
4361     /* And starts to fill the extension context properly */
4362     memset(&GL_extensions, 0, sizeof(GL_extensions));
4363     TRACE("GL supports following extensions used by Wine :\n");
4364     
4365     /* Mirrored Repeat extension :
4366         - GL_ARB_texture_mirrored_repeat
4367         - GL_IBM_texture_mirrored_repeat
4368         - GL >= 1.4
4369     */
4370     if ((strstr(glExtensions, "GL_ARB_texture_mirrored_repeat")) ||
4371         (strstr(glExtensions, "GL_IBM_texture_mirrored_repeat")) ||
4372         (major > 1) ||
4373         ((major == 1) && (minor >= 4))) {
4374         TRACE(" - mirrored repeat\n");
4375         GL_extensions.mirrored_repeat = TRUE;
4376     }
4377
4378     /* Texture LOD Bias :
4379         - GL_EXT_texture_lod_bias
4380     */
4381     if (strstr(glExtensions, "GL_EXT_texture_lod_bias")) {
4382         TRACE(" - texture lod bias\n");
4383         GL_extensions.mipmap_lodbias = TRUE;
4384     }
4385
4386     /* For all subsequent extensions, we need glXGetProcAddress */
4387     if (pglXGetProcAddressARB != NULL) {
4388         /* Multi-texturing :
4389             - GL_ARB_multitexture
4390             - GL >= 1.2.1
4391         */
4392         if ((strstr(glExtensions, "GL_ARB_multitexture")) ||
4393             (major > 1) ||
4394             ((major == 1) && (minor > 2)) ||
4395             ((major == 1) && (minor == 2) && (patch >= 1))) {
4396             glGetIntegerv(GL_MAX_TEXTURE_UNITS_WINE, &(GL_extensions.max_texture_units));
4397             TRACE(" - multi-texturing (%d stages)\n", GL_extensions.max_texture_units);
4398             /* We query the ARB version to be the most portable we can... */
4399             GL_extensions.glActiveTexture = pglXGetProcAddressARB("glActiveTextureARB");
4400             GL_extensions.glMultiTexCoord2fv = pglXGetProcAddressARB("glMultiTexCoord2fv");
4401             GL_extensions.glClientActiveTexture = pglXGetProcAddressARB("glClientActiveTextureARB");
4402         }
4403
4404         if (strstr(glExtensions, "GL_EXT_texture_compression_s3tc")) {
4405             TRACE(" - S3TC compression supported\n");
4406             GL_extensions.s3tc_compressed_texture = TRUE;
4407             GL_extensions.glCompressedTexImage2D = pglXGetProcAddressARB("glCompressedTexImage2D");
4408             GL_extensions.glCompressedTexSubImage2D = pglXGetProcAddressARB("glCompressedTexSubImage2D");
4409         }
4410     }
4411     
4412     /* Fill the D3D capabilities according to what GL tells us... */
4413     fill_caps();
4414
4415     /* And frees this now-useless context */
4416     glXMakeCurrent(display, None, NULL);
4417     glXDestroyContext(display, gl_context);
4418     LEAVE_GL();
4419     
4420     return TRUE;
4421 }