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