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