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