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