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