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