wined3d: Use the texture sampling function in a few more instructions (GLSL).
[wine] / dlls / wined3d / drawprim.c
1 /*
2  * WINED3D draw functions
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  * Copyright 2006 Henri Verbeet
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
29 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
30 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
31
32 #include <stdio.h>
33
34 #if 0 /* TODO */
35 extern IWineD3DVertexShaderImpl*            VertexShaders[64];
36 extern IWineD3DVertexDeclarationImpl*       VertexShaderDeclarations[64];
37 extern IWineD3DPixelShaderImpl*             PixelShaders[64];
38
39 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
40 #endif
41
42 /* Issues the glBegin call for gl given the primitive type and count */
43 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
44                     DWORD            NumPrimitives,
45                     GLenum          *primType)
46 {
47     DWORD   NumVertexes = NumPrimitives;
48
49     switch (PrimitiveType) {
50     case WINED3DPT_POINTLIST:
51         TRACE("POINTS\n");
52         *primType   = GL_POINTS;
53         NumVertexes = NumPrimitives;
54         break;
55
56     case WINED3DPT_LINELIST:
57         TRACE("LINES\n");
58         *primType   = GL_LINES;
59         NumVertexes = NumPrimitives * 2;
60         break;
61
62     case WINED3DPT_LINESTRIP:
63         TRACE("LINE_STRIP\n");
64         *primType   = GL_LINE_STRIP;
65         NumVertexes = NumPrimitives + 1;
66         break;
67
68     case WINED3DPT_TRIANGLELIST:
69         TRACE("TRIANGLES\n");
70         *primType   = GL_TRIANGLES;
71         NumVertexes = NumPrimitives * 3;
72         break;
73
74     case WINED3DPT_TRIANGLESTRIP:
75         TRACE("TRIANGLE_STRIP\n");
76         *primType   = GL_TRIANGLE_STRIP;
77         NumVertexes = NumPrimitives + 2;
78         break;
79
80     case WINED3DPT_TRIANGLEFAN:
81         TRACE("TRIANGLE_FAN\n");
82         *primType   = GL_TRIANGLE_FAN;
83         NumVertexes = NumPrimitives + 2;
84         break;
85
86     default:
87         FIXME("Unhandled primitive\n");
88         *primType    = GL_POINTS;
89         break;
90     }
91     return NumVertexes;
92 }
93
94 /* Ensure the appropriate material states are set up - only change
95    state if really required                                        */
96 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
97
98     BOOL requires_material_reset = FALSE;
99     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
100
101     if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
102         /* If we have not set up the material color tracking, do it now as required */
103         glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
104         checkGLcall("glDisable GL_COLOR_MATERIAL");
105         TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
106         glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
107         checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
108         glEnable(GL_COLOR_MATERIAL);
109         checkGLcall("glEnable GL_COLOR_MATERIAL");
110         This->tracking_color = IS_TRACKING;
111         requires_material_reset = TRUE; /* Restore material settings as will be used */
112
113     } else if ((This->tracking_color == IS_TRACKING && !isDiffuseSupplied) ||
114                (This->tracking_color == NEEDS_TRACKING && !isDiffuseSupplied)) {
115         /* If we are tracking the current color but one isn't supplied, don't! */
116         glDisable(GL_COLOR_MATERIAL);
117         checkGLcall("glDisable GL_COLOR_MATERIAL");
118         This->tracking_color = NEEDS_TRACKING;
119         requires_material_reset = TRUE; /* Restore material settings as will be used */
120
121     } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
122         /* No need to reset material colors since no change to gl_color_material */
123         requires_material_reset = FALSE;
124
125     } else if (This->tracking_color == NEEDS_DISABLE) {
126         glDisable(GL_COLOR_MATERIAL);
127         checkGLcall("glDisable GL_COLOR_MATERIAL");
128         This->tracking_color = DISABLED_TRACKING;
129         requires_material_reset = TRUE; /* Restore material settings as will be used */
130     }
131
132     /* Reset the material colors which may have been tracking the color*/
133     if (requires_material_reset) {
134         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
135         checkGLcall("glMaterialfv");
136         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
137         checkGLcall("glMaterialfv");
138         if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
139            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
140            checkGLcall("glMaterialfv");
141         } else {
142            float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
143            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
144            checkGLcall("glMaterialfv");
145         }
146         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
147         checkGLcall("glMaterialfv");
148     }
149
150 }
151
152 static GLfloat invymat[16] = {
153         1.0f, 0.0f, 0.0f, 0.0f,
154         0.0f, -1.0f, 0.0f, 0.0f,
155         0.0f, 0.0f, 1.0f, 0.0f,
156         0.0f, 0.0f, 0.0f, 1.0f};
157
158 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
159     /* If the last draw was transformed as well, no need to reapply all the matrixes */
160     if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
161
162         double X, Y, height, width, minZ, maxZ;
163         This->last_was_rhw = TRUE;
164         This->viewport_changed = FALSE;
165
166         /* Transformed already into viewport coordinates, so we do not need transform
167             matrices. Reset all matrices to identity and leave the default matrix in world
168             mode.                                                                         */
169         glMatrixMode(GL_MODELVIEW);
170         checkGLcall("glMatrixMode(GL_MODELVIEW)");
171         glLoadIdentity();
172         checkGLcall("glLoadIdentity");
173
174         glMatrixMode(GL_PROJECTION);
175         checkGLcall("glMatrixMode(GL_PROJECTION)");
176         glLoadIdentity();
177         checkGLcall("glLoadIdentity");
178
179         /* Set up the viewport to be full viewport */
180         X      = This->stateBlock->viewport.X;
181         Y      = This->stateBlock->viewport.Y;
182         height = This->stateBlock->viewport.Height;
183         width  = This->stateBlock->viewport.Width;
184         minZ   = This->stateBlock->viewport.MinZ;
185         maxZ   = This->stateBlock->viewport.MaxZ;
186         if(!This->untransformed) {
187             TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
188             glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
189         } else {
190             TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
191             glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
192         }
193         checkGLcall("glOrtho");
194
195         /* Window Coord 0 is the middle of the first pixel, so translate by half
196             a pixel (See comment above glTranslate below)                         */
197         glTranslatef(0.375, 0.375, 0);
198         checkGLcall("glTranslatef(0.375, 0.375, 0)");
199         /* D3D texture coordinates are flipped compared to OpenGL ones, so
200          * render everything upside down when rendering offscreen. */
201         if (This->render_offscreen) {
202             glMultMatrixf(invymat);
203             checkGLcall("glMultMatrixf(invymat)");
204         }
205
206         /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
207         if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) {
208             if(GL_SUPPORT(EXT_FOG_COORD)) {
209                 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
210                 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
211                 glFogi(GL_FOG_MODE, GL_LINEAR);
212                 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
213                 /* The dx fog range in this case is fixed to 0 - 255,
214                  * but in GL it still depends on the fog start and end (according to the ext)
215                  * Use this to turn around the fog as it's needed. That prevents some
216                  * calculations during drawing :-)
217                  */
218                 glFogf(GL_FOG_START, (float) 0xff);
219                 checkGLcall("glFogfv GL_FOG_END");
220                 glFogf(GL_FOG_END, 0.0);
221                 checkGLcall("glFogfv GL_FOG_START");
222             } else {
223                 /* Disable GL fog, handle this in software in drawStridedSlow */
224                 glDisable(GL_FOG);
225                 checkGLcall("glDisable(GL_FOG)");
226             }
227         }
228     }
229 }
230 /* Setup views - Transformed & lit if RHW, else untransformed.
231        Only unlit if Normals are supplied
232     Returns: Whether to restore lighting afterwards           */
233 static void primitiveInitState(
234     IWineD3DDevice *iface,
235     WineDirect3DVertexStridedData* strided,
236     BOOL useVS,
237     BOOL* lighting_changed,
238     BOOL* lighting_original) {
239
240     BOOL fixed_vtx_transformed =
241        (strided->u.s.position.lpData != NULL || strided->u.s.position.VBO != 0 ||
242         strided->u.s.position2.lpData != NULL || strided->u.s.position2.VBO != 0) && 
243         strided->u.s.position_transformed;
244
245     BOOL fixed_vtx_lit = 
246         strided->u.s.normal.lpData == NULL && strided->u.s.normal.VBO == 0 &&
247         strided->u.s.normal2.lpData == NULL && strided->u.s.normal2.VBO == 0;
248
249     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
250
251     *lighting_changed = FALSE;
252
253     /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
254        set by the appropriate render state. Note Vertex Shader output is already lit */
255     if (fixed_vtx_lit || useVS) {
256         *lighting_changed = TRUE;
257         *lighting_original = glIsEnabled(GL_LIGHTING);
258         glDisable(GL_LIGHTING);
259         checkGLcall("glDisable(GL_LIGHTING);");
260         TRACE("Disabled lighting, old state = %d\n", *lighting_original);
261     }
262
263     if (!useVS && fixed_vtx_transformed) {
264         d3ddevice_set_ortho(This);
265
266     } else {
267
268         /* Untransformed, so relies on the view and projection matrices */
269         This->untransformed = TRUE;
270
271         if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
272             /* Only reapply when have to */
273             This->modelview_valid = TRUE;
274             glMatrixMode(GL_MODELVIEW);
275             checkGLcall("glMatrixMode");
276
277             /* In the general case, the view matrix is the identity matrix */
278             if (This->view_ident) {
279                 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
280                 checkGLcall("glLoadMatrixf");
281             } else {
282                 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
283                 checkGLcall("glLoadMatrixf");
284                 glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]);
285                 checkGLcall("glMultMatrixf");
286             }
287         }
288
289         if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
290             /* Only reapply when have to */
291             This->proj_valid = TRUE;
292             glMatrixMode(GL_PROJECTION);
293             checkGLcall("glMatrixMode");
294
295             /* The rule is that the window coordinate 0 does not correspond to the
296                beginning of the first pixel, but the center of the first pixel.
297                As a consequence if you want to correctly draw one line exactly from
298                the left to the right end of the viewport (with all matrices set to
299                be identity), the x coords of both ends of the line would be not
300                -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
301                instead.                                                               */
302             glLoadIdentity();
303
304             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
305             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
306
307             /* D3D texture coordinates are flipped compared to OpenGL ones, so
308              * render everything upside down when rendering offscreen. */
309             if (This->render_offscreen) {
310                 glMultMatrixf(invymat);
311                 checkGLcall("glMultMatrixf(invymat)");
312             }
313             glMultMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_PROJECTION].u.m[0][0]);
314             checkGLcall("glLoadMatrixf");
315         }
316
317         /* Vertex Shader output is already transformed, so set up identity matrices */
318         if (useVS) {
319             This->posFixup[1] = This->render_offscreen ? -1.0 : 1.0;
320             This->posFixup[2] = 0.9 / This->stateBlock->viewport.Width;
321             This->posFixup[3] = -0.9 / This->stateBlock->viewport.Height;
322         }
323         This->last_was_rhw = FALSE;
324
325         /* Setup fogging */
326         if (useVS && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->usesFog) {
327             /* In D3D vertex shader return the 'final' fog value, while in OpenGL it is the 'input' fog value.
328              * The code below 'disables' the OpenGL postprocessing by setting the formula to '1'. */
329             glFogi(GL_FOG_MODE, GL_LINEAR);
330             glFogf(GL_FOG_START, 1.0f);
331             glFogf(GL_FOG_END, 0.0f);
332
333         } else if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] 
334                   && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) {
335             
336             if(GL_SUPPORT(EXT_FOG_COORD)) {
337                 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
338                 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT)\n");
339                 /* Reapply the fog range */
340                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
341                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
342                 /* Restore the fog mode */
343                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
344             } else {
345                 /* Enable GL_FOG again because we disabled it above */
346                 glEnable(GL_FOG);
347                 checkGLcall("glEnable(GL_FOG)");
348             }
349         }
350     }
351 }
352
353 static BOOL fixed_get_input(
354     BYTE usage, BYTE usage_idx,
355     unsigned int* regnum) {
356
357     *regnum = -1;
358
359     /* Those positions must have the order in the
360      * named part of the strided data */
361
362     if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
363         *regnum = 0;
364     else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
365         *regnum = 1;
366     else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
367         *regnum = 2;
368     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
369         *regnum = 3;
370     else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
371         *regnum = 4;
372     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
373         *regnum = 5;
374     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
375         *regnum = 6;
376     else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
377         *regnum = 7 + usage_idx;
378     else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
379         *regnum = 7 + WINED3DDP_MAXTEXCOORD;
380     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
381         *regnum = 8 + WINED3DDP_MAXTEXCOORD;
382     else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
383         *regnum = 9 + WINED3DDP_MAXTEXCOORD;
384     else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
385         *regnum = 10 + WINED3DDP_MAXTEXCOORD;
386     else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
387         *regnum = 11 + WINED3DDP_MAXTEXCOORD;
388     else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
389         *regnum = 12 + WINED3DDP_MAXTEXCOORD;
390     else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
391         *regnum = 13 + WINED3DDP_MAXTEXCOORD;
392     else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
393         *regnum = 14 + WINED3DDP_MAXTEXCOORD;
394
395     if (*regnum < 0) {
396         FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
397             debug_d3ddeclusage(usage), usage_idx);
398         return FALSE;
399     }
400     return TRUE;
401 }
402
403 void primitiveDeclarationConvertToStridedData(
404      IWineD3DDevice *iface,
405      BOOL useVertexShaderFunction,
406      WineDirect3DVertexStridedData *strided,
407      LONG BaseVertexIndex, 
408      BOOL *fixup) {
409
410      /* We need to deal with frequency data!*/
411
412     BYTE  *data    = NULL;
413     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
414     IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
415     int i;
416     WINED3DVERTEXELEMENT *element;
417     DWORD stride;
418     int reg;
419
420     /* Locate the vertex declaration */
421     if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
422         TRACE("Using vertex declaration from shader\n");
423         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
424     } else {
425         TRACE("Using vertex declaration\n");
426         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
427     }
428
429     /* Translate the declaration into strided data */
430     for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
431         GLint streamVBO = 0;
432         BOOL stride_used;
433         unsigned int idx;
434
435         element = vertexDeclaration->pDeclarationWine + i;
436         TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
437             element,  i + 1, vertexDeclaration->declarationWNumElements - 1);
438
439         if (This->stateBlock->streamSource[element->Stream] == NULL)
440             continue;
441
442         if (This->stateBlock->streamIsUP) {
443             TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
444             streamVBO = 0;
445             data    = (BYTE *)This->stateBlock->streamSource[element->Stream];
446             if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
447         } else {
448             TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
449             IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
450             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
451             if(fixup) {
452                 if( streamVBO != 0) *fixup = TRUE;
453                 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
454             }
455         }
456         stride  = This->stateBlock->streamStride[element->Stream];
457         data += (BaseVertexIndex * stride);
458         data += element->Offset;
459         reg = element->Reg;
460
461         TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
462
463         if (useVertexShaderFunction)
464             stride_used = vshader_get_input(This->stateBlock->vertexShader,
465                 element->Usage, element->UsageIndex, &idx);
466         else
467             stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
468
469         if (stride_used) {
470            TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
471                  "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
472                  useVertexShaderFunction? "shader": "fixed function", idx,
473                  debug_d3ddeclusage(element->Usage), element->UsageIndex,
474                  element->Stream, element->Offset, stride, streamVBO);
475
476            strided->u.input[idx].lpData = data;
477            strided->u.input[idx].dwType = element->Type;
478            strided->u.input[idx].dwStride = stride;
479            strided->u.input[idx].VBO = streamVBO;
480            if (!useVertexShaderFunction) {
481                if (element->Usage == D3DDECLUSAGE_POSITION)
482                    strided->u.s.position_transformed = FALSE;
483                else if (element->Usage == D3DDECLUSAGE_POSITIONT)
484                    strided->u.s.position_transformed = TRUE;
485            }
486         }
487     };
488 }
489
490 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
491     int           numBlends;
492     int           numTextures;
493     int           textureNo;
494     int           coordIdxInfo = 0x00;    /* Information on number of coords supplied */
495     int           numCoords[8];           /* Holding place for WINED3DFVF_TEXTUREFORMATx  */
496
497     /* Either 3 or 4 floats depending on the FVF */
498     /* FIXME: Can blending data be in a different stream to the position data?
499           and if so using the fixed pipeline how do we handle it               */
500     if (thisFVF & WINED3DFVF_POSITION_MASK) {
501         strided->u.s.position.lpData    = data;
502         strided->u.s.position.dwType    = WINED3DDECLTYPE_FLOAT3;
503         strided->u.s.position.dwStride  = stride;
504         strided->u.s.position.VBO       = streamVBO;
505         data += 3 * sizeof(float);
506         if (thisFVF & WINED3DFVF_XYZRHW) {
507             strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
508             strided->u.s.position_transformed = TRUE;
509             data += sizeof(float);
510         } else
511             strided->u.s.position_transformed = FALSE;
512     }
513
514     /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
515     /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
516     numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
517     if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
518
519     if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
520         TRACE("Setting blend Weights to %p\n", data);
521         strided->u.s.blendWeights.lpData    = data;
522         strided->u.s.blendWeights.dwType    = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
523         strided->u.s.blendWeights.dwStride  = stride;
524         strided->u.s.blendWeights.VBO       = streamVBO;
525         data += numBlends * sizeof(FLOAT);
526
527         if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
528             strided->u.s.blendMatrixIndices.lpData = data;
529             strided->u.s.blendMatrixIndices.dwType  = WINED3DDECLTYPE_UBYTE4;
530             strided->u.s.blendMatrixIndices.dwStride= stride;
531             strided->u.s.blendMatrixIndices.VBO     = streamVBO;
532             data += sizeof(DWORD);
533         }
534     }
535
536     /* Normal is always 3 floats */
537     if (thisFVF & WINED3DFVF_NORMAL) {
538         strided->u.s.normal.lpData    = data;
539         strided->u.s.normal.dwType    = WINED3DDECLTYPE_FLOAT3;
540         strided->u.s.normal.dwStride  = stride;
541         strided->u.s.normal.VBO     = streamVBO;
542         data += 3 * sizeof(FLOAT);
543     }
544
545     /* Pointsize is a single float */
546     if (thisFVF & WINED3DFVF_PSIZE) {
547         strided->u.s.pSize.lpData    = data;
548         strided->u.s.pSize.dwType    = WINED3DDECLTYPE_FLOAT1;
549         strided->u.s.pSize.dwStride  = stride;
550         strided->u.s.pSize.VBO       = streamVBO;
551         data += sizeof(FLOAT);
552     }
553
554     /* Diffuse is 4 unsigned bytes */
555     if (thisFVF & WINED3DFVF_DIFFUSE) {
556         strided->u.s.diffuse.lpData    = data;
557         strided->u.s.diffuse.dwType    = WINED3DDECLTYPE_SHORT4;
558         strided->u.s.diffuse.dwStride  = stride;
559         strided->u.s.diffuse.VBO       = streamVBO;
560         data += sizeof(DWORD);
561     }
562
563     /* Specular is 4 unsigned bytes */
564     if (thisFVF & WINED3DFVF_SPECULAR) {
565         strided->u.s.specular.lpData    = data;
566         strided->u.s.specular.dwType    = WINED3DDECLTYPE_SHORT4;
567         strided->u.s.specular.dwStride  = stride;
568         strided->u.s.specular.VBO       = streamVBO;
569         data += sizeof(DWORD);
570     }
571
572     /* Texture coords */
573     numTextures   = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
574     coordIdxInfo  = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
575
576     /* numTextures indicates the number of texture coordinates supplied */
577     /* However, the first set may not be for stage 0 texture - it all   */
578     /*   depends on WINED3DTSS_TEXCOORDINDEX.                           */
579     /* The number of bytes for each coordinate set is based off         */
580     /*   WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits              */
581
582     /* So, for each supplied texture extract the coords */
583     for (textureNo = 0; textureNo < numTextures; ++textureNo) {
584
585         strided->u.s.texCoords[textureNo].lpData    = data;
586         strided->u.s.texCoords[textureNo].dwType    = WINED3DDECLTYPE_FLOAT1;
587         strided->u.s.texCoords[textureNo].dwStride  = stride;
588         strided->u.s.texCoords[textureNo].VBO       = streamVBO;
589         numCoords[textureNo] = coordIdxInfo & 0x03;
590
591         /* Always one set */
592         data += sizeof(float);
593         if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
594             strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
595             data += sizeof(float);
596             if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
597                 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
598                 data += sizeof(float);
599                 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
600                     strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
601                     data += sizeof(float);
602                 }
603             }
604         }
605         coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
606     }
607 }
608
609 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
610
611     short         LoopThroughTo = 0;
612     short         nStream;
613     GLint         streamVBO = 0;
614
615     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
616
617     /* OK, Now to setup the data locations
618        For the non-created vertex shaders, the VertexShader var holds the real
619           FVF and only stream 0 matters
620        For the created vertex shaders, there is an FVF per stream              */
621     if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
622         LoopThroughTo = MAX_STREAMS;
623     } else {
624         LoopThroughTo = 1;
625     }
626
627     /* Work through stream by stream */
628     for (nStream=0; nStream<LoopThroughTo; ++nStream) {
629         DWORD  stride  = This->stateBlock->streamStride[nStream];
630         BYTE  *data    = NULL;
631         DWORD  thisFVF = 0;
632
633         /* Skip empty streams */
634         if (This->stateBlock->streamSource[nStream] == NULL) continue;
635
636         /* Retrieve appropriate FVF */
637         if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
638             thisFVF = This->stateBlock->fvf;
639             /* Handle memory passed directly as well as vertex buffers */
640             if (This->stateBlock->streamIsUP) {
641                 streamVBO = 0;
642                 data    = (BYTE *)This->stateBlock->streamSource[nStream];
643             } else {
644                 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
645                 /* GetMemory binds the VBO */
646                 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
647                 if(fixup) {
648                     if(streamVBO != 0 ) *fixup = TRUE;
649                 }
650             }
651         } else {
652 #if 0 /* TODO: Vertex shader support */
653             thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
654             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
655 #endif
656         }
657         VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
658         if (thisFVF == 0) continue;
659
660         /* Now convert the stream into pointers */
661
662         /* Shuffle to the beginning of the vertexes to render and index from there */
663         data = data + (BaseVertexIndex * stride);
664
665         primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
666     }
667 }
668
669 #if 0 /* TODO: Software Shaders */
670 /* Draw a single vertex using this information */
671 static void draw_vertex(IWineD3DDevice *iface,                         /* interface    */
672                  BOOL isXYZ,    float x, float y, float z, float rhw,  /* xyzn position*/
673                  BOOL isNormal, float nx, float ny, float nz,          /* normal       */
674                  BOOL isDiffuse, float *dRGBA,                         /* 1st   colors */
675                  BOOL isSpecular, float *sRGB,                         /* 2ndry colors */
676                  BOOL isPtSize, float ptSize,                       /* pointSize    */
677                  WINED3DVECTOR_4 *texcoords, int *numcoords)        /* texture info */
678 {
679     unsigned int textureNo;
680     float s, t, r, q;
681     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
682
683     /* Diffuse -------------------------------- */
684     if (isDiffuse) {
685         glColor4fv(dRGBA);
686         VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
687     }
688
689     /* Specular Colour ------------------------------------------*/
690     if (isSpecular) {
691         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
692           GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
693           VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
694         } else {
695           VTRACE(("Specular color extensions not supplied\n"));
696         }
697     }
698
699     /* Normal -------------------------------- */
700     if (isNormal) {
701         VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
702         glNormal3f(nx, ny, nz);
703     }
704
705     /* Point Size ----------------------------------------------*/
706     if (isPtSize) {
707
708         /* no such functionality in the fixed function GL pipeline */
709         FIXME("Cannot change ptSize here in openGl\n");
710     }
711
712     /* Texture coords --------------------------- */
713     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
714
715         if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
716             FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
717             continue ;
718         }
719
720         /* Query tex coords */
721         if (This->stateBlock->textures[textureNo] != NULL) {
722
723             int    coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
724             if (coordIdx >= MAX_TEXTURES) {
725                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
726                 continue;
727             } else if (numcoords[coordIdx] == 0) {
728                 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
729                 continue;
730             } else {
731
732                 /* Initialize vars */
733                 s = 0.0f;
734                 t = 0.0f;
735                 r = 0.0f;
736                 q = 0.0f;
737
738                 switch (numcoords[coordIdx]) {
739                 case 4: q = texcoords[coordIdx].w; /* drop through */
740                 case 3: r = texcoords[coordIdx].z; /* drop through */
741                 case 2: t = texcoords[coordIdx].y; /* drop through */
742                 case 1: s = texcoords[coordIdx].x;
743                 }
744
745                 switch (numcoords[coordIdx]) {   /* Supply the provided texture coords */
746                 case WINED3DTTFF_COUNT1:
747                     VTRACE(("tex:%d, s=%f\n", textureNo, s));
748                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
749                         GLMULTITEXCOORD1F(textureNo, s);
750                     } else {
751                         glTexCoord1f(s);
752                     }
753                     break;
754                 case WINED3DTTFF_COUNT2:
755                     VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
756                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
757                         GLMULTITEXCOORD2F(textureNo, s, t);
758                     } else {
759                         glTexCoord2f(s, t);
760                     }
761                     break;
762                 case WINED3DTTFF_COUNT3:
763                     VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
764                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
765                         GLMULTITEXCOORD3F(textureNo, s, t, r);
766                     } else {
767                         glTexCoord3f(s, t, r);
768                     }
769                     break;
770                 case WINED3DTTFF_COUNT4:
771                     VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
772                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
773                         GLMULTITEXCOORD4F(textureNo, s, t, r, q);
774                     } else {
775                         glTexCoord4f(s, t, r, q);
776                     }
777                     break;
778                 default:
779                     FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
780                 }
781             }
782         }
783     } /* End of textures */
784
785     /* Position -------------------------------- */
786     if (isXYZ) {
787         if (1.0f == rhw || rhw < 0.00001f) {
788             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
789             glVertex3f(x, y, z);
790         } else {
791             /* Cannot optimize by dividing through by rhw as rhw is required
792                later for perspective in the GL pipeline for vertex shaders   */
793             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
794             glVertex4f(x,y,z,rhw);
795         }
796     }
797 }
798 #endif /* TODO: Software shaders */
799
800 /* This should match any arrays loaded in loadNumberedArrays. */
801 /* TODO: Only load / unload arrays if we have to. */
802 static void unloadNumberedArrays(IWineD3DDevice *iface) {
803     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804
805     /* disable any attribs (this is the same for both GLSL and ARB modes) */
806     GLint maxAttribs;
807     int i;
808
809     /* Leave all the attribs disabled */
810     glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
811     /* MESA does not support it right not */
812     if (glGetError() != GL_NO_ERROR)
813         maxAttribs = 16;
814     for (i = 0; i < maxAttribs; ++i) {
815         GL_EXTCALL(glDisableVertexAttribArrayARB(i));
816         checkGLcall("glDisableVertexAttribArrayARB(reg);");
817     }
818 }
819
820 /* TODO: Only load / unload arrays if we have to. */
821 static void loadNumberedArrays(
822     IWineD3DDevice *iface,
823     IWineD3DVertexShader *shader,
824     WineDirect3DVertexStridedData *strided) {
825
826     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
827     GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
828     int i;
829
830     for (i = 0; i < MAX_ATTRIBS; i++) {
831
832         if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
833             continue;
834
835         TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
836
837         if(curVBO != strided->u.input[i].VBO) {
838             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
839             checkGLcall("glBindBufferARB");
840             curVBO = strided->u.input[i].VBO;
841         }
842         GL_EXTCALL(glVertexAttribPointerARB(i,
843                         WINED3D_ATR_SIZE(strided->u.input[i].dwType),
844                         WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
845                         WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
846                         strided->u.input[i].dwStride,
847                         strided->u.input[i].lpData));
848         GL_EXTCALL(glEnableVertexAttribArrayARB(i));
849    }
850 }
851
852 /* This should match any arrays loaded in loadVertexData. */
853 /* TODO: Only load / unload arrays if we have to. */
854 static void unloadVertexData(IWineD3DDevice *iface) {
855     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
856     int texture_idx;
857
858     glDisableClientState(GL_VERTEX_ARRAY);
859     glDisableClientState(GL_NORMAL_ARRAY);
860     glDisableClientState(GL_COLOR_ARRAY);
861     if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
862         glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
863     }
864     for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
865         GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
866         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
867     }
868 }
869
870 /* TODO: Only load / unload arrays if we have to. */
871 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
872     unsigned int textureNo   = 0;
873     unsigned int texture_idx = 0;
874     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
875     GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
876
877     TRACE("Using fast vertex array code\n");
878     /* Blend Data ---------------------------------------------- */
879     if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
880         (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
881
882
883         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
884
885 #if 1
886             glEnableClientState(GL_WEIGHT_ARRAY_ARB);
887             checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
888 #endif
889
890             TRACE("Blend %d %p %d\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
891                 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
892             /* FIXME("TODO\n");*/
893             /* Note dwType == float3 or float4 == 2 or 3 */
894
895 #if 0
896             /* with this on, the normals appear to be being modified,
897                but the vertices aren't being translated as they should be
898                Maybe the world matrix aren't being setup properly? */
899             glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
900 #endif
901
902
903             VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %d, %p)\n",
904                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
905                 sd->u.s.blendWeights.dwStride,
906                 sd->u.s.blendWeights.lpData));
907
908             if(curVBO != sd->u.s.blendWeights.VBO) {
909                 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
910                 checkGLcall("glBindBufferARB");
911                 curVBO = sd->u.s.blendWeights.VBO;
912             }
913
914             GL_EXTCALL(glWeightPointerARB)(
915                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
916                 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
917                 sd->u.s.blendWeights.dwStride,
918                 sd->u.s.blendWeights.lpData);
919
920             checkGLcall("glWeightPointerARB");
921
922             if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
923                 static BOOL showfixme = TRUE;
924                 if(showfixme){
925                     FIXME("blendMatrixIndices support\n");
926                     showfixme = FALSE;
927                 }
928             }
929
930         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
931             /* FIXME("TODO\n");*/
932 #if 0
933
934             GL_EXTCALL(glVertexWeightPointerEXT)(
935                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
936                 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
937                 sd->u.s.blendWeights.dwStride,
938                 sd->u.s.blendWeights.lpData);
939             checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
940             glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
941             checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
942 #endif
943
944         } else {
945             /* TODO: support blends in fixupVertices */
946             FIXME("unsupported blending in openGl\n");
947         }
948     } else {
949         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
950 #if 0    /* TODO: Vertex blending */
951             glDisable(GL_VERTEX_BLEND_ARB);
952 #endif
953             TRACE("ARB_VERTEX_BLEND\n");
954         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
955             TRACE(" EXT_VERTEX_WEIGHTING\n");
956             glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
957             checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
958
959         }
960     }
961
962 #if 0 /* FOG  ----------------------------------------------*/
963     if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
964         /* TODO: fog*/
965     if (GL_SUPPORT(EXT_FOG_COORD) {
966              glEnableClientState(GL_FOG_COORDINATE_EXT);
967             (GL_EXTCALL)(FogCoordPointerEXT)(
968                 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
969                 sd->u.s.fog.dwStride,
970                 sd->u.s.fog.lpData);
971         } else {
972             /* don't bother falling back to 'slow' as we don't support software FOG yet. */
973             /* FIXME: fixme once */
974             TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
975         }
976     } else {
977         if (GL_SUPPRT(EXT_FOR_COORD) {
978              /* make sure fog is disabled */
979              glDisableClientState(GL_FOG_COORDINATE_EXT);
980         }
981     }
982 #endif
983
984 #if 0 /* tangents  ----------------------------------------------*/
985     if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
986         sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
987         /* TODO: tangents*/
988         if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
989             if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
990                 glEnable(GL_TANGENT_ARRAY_EXT);
991                 (GL_EXTCALL)(TangentPointerEXT)(
992                     WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
993                     sd->u.s.tangent.dwStride,
994                     sd->u.s.tangent.lpData);
995             } else {
996                     glDisable(GL_TANGENT_ARRAY_EXT);
997             }
998             if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
999                     glEnable(GL_BINORMAL_ARRAY_EXT);
1000                     (GL_EXTCALL)(BinormalPointerEXT)(
1001                         WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
1002                         sd->u.s.binormal.dwStride,
1003                         sd->u.s.binormal.lpData);
1004             } else{
1005                     glDisable(GL_BINORMAL_ARRAY_EXT);
1006             }
1007
1008         } else {
1009             /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
1010             /* FIXME: fixme once */
1011             TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
1012         }
1013     } else {
1014         if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
1015              /* make sure fog is disabled */
1016              glDisable(GL_TANGENT_ARRAY_EXT);
1017              glDisable(GL_BINORMAL_ARRAY_EXT);
1018         }
1019     }
1020 #endif
1021
1022     /* Point Size ----------------------------------------------*/
1023     if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
1024
1025         /* no such functionality in the fixed function GL pipeline */
1026         TRACE("Cannot change ptSize here in openGl\n");
1027         /* TODO: Implement this function in using shaders if they are available */
1028
1029     }
1030
1031     /* Vertex Pointers -----------------------------------------*/
1032     if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
1033         /* Note dwType == float3 or float4 == 2 or 3 */
1034         VTRACE(("glVertexPointer(%d, GL_FLOAT, %d, %p)\n",
1035                 sd->u.s.position.dwStride,
1036                 sd->u.s.position.dwType + 1,
1037                 sd->u.s.position.lpData));
1038
1039         if(curVBO != sd->u.s.position.VBO) {
1040             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1041             checkGLcall("glBindBufferARB");
1042             curVBO = sd->u.s.position.VBO;
1043         }
1044
1045         /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1046            handling for rhw mode should not impact screen position whereas in GL it does.
1047            This may  result in very slightly distored textures in rhw mode, but
1048            a very minimal different. There's always the other option of
1049            fixing the view matrix to prevent w from having any effect
1050
1051            This only applies to user pointer sources, in VBOs the vertices are fixed up
1052          */
1053         if(sd->u.s.position.VBO == 0) {
1054             glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1055                 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1056                 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1057         } else {
1058             glVertexPointer(
1059                 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1060                 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1061                 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1062         }
1063         checkGLcall("glVertexPointer(...)");
1064         glEnableClientState(GL_VERTEX_ARRAY);
1065         checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1066
1067     } else {
1068         glDisableClientState(GL_VERTEX_ARRAY);
1069         checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1070     }
1071
1072     /* Normals -------------------------------------------------*/
1073     if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1074         /* Note dwType == float3 or float4 == 2 or 3 */
1075         VTRACE(("glNormalPointer(GL_FLOAT, %d, %p)\n",
1076                 sd->u.s.normal.dwStride,
1077                 sd->u.s.normal.lpData));
1078         if(curVBO != sd->u.s.normal.VBO) {
1079             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1080             checkGLcall("glBindBufferARB");
1081             curVBO = sd->u.s.normal.VBO;
1082         }
1083         glNormalPointer(
1084             WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1085             sd->u.s.normal.dwStride,
1086             sd->u.s.normal.lpData);
1087         checkGLcall("glNormalPointer(...)");
1088         glEnableClientState(GL_NORMAL_ARRAY);
1089         checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1090
1091     } else {
1092         glDisableClientState(GL_NORMAL_ARRAY);
1093         checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1094         glNormal3f(0, 0, 1);
1095         checkGLcall("glNormal3f(0, 0, 1)");
1096     }
1097
1098     /* Diffuse Colour --------------------------------------------*/
1099     /*  WARNING: Data here MUST be in RGBA format, so cannot      */
1100     /*     go directly into fast mode from app pgm, because       */
1101     /*     directx requires data in BGRA format.                  */
1102     /* currently fixupVertices swizels the format, but this isn't */
1103     /* very practical when using VBOS                             */
1104     /* NOTE: Unless we write a vertex shader to swizel the colour */
1105     /* , or the user doesn't care and wants the speed advantage   */
1106
1107     if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1108         /* Note dwType == float3 or float4 == 2 or 3 */
1109         VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1110                 sd->u.s.diffuse.dwStride,
1111                 sd->u.s.diffuse.lpData));
1112
1113         if(curVBO != sd->u.s.diffuse.VBO) {
1114             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1115             checkGLcall("glBindBufferARB");
1116             curVBO = sd->u.s.diffuse.VBO;
1117         }
1118         glColorPointer(4, GL_UNSIGNED_BYTE,
1119                        sd->u.s.diffuse.dwStride,
1120                        sd->u.s.diffuse.lpData);
1121         checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1122         glEnableClientState(GL_COLOR_ARRAY);
1123         checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1124
1125     } else {
1126         glDisableClientState(GL_COLOR_ARRAY);
1127         checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1128         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1129         checkGLcall("glColor4f(1, 1, 1, 1)");
1130     }
1131
1132     /* Specular Colour ------------------------------------------*/
1133     if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1134         TRACE("setting specular colour\n");
1135         /* Note dwType == float3 or float4 == 2 or 3 */
1136         VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1137                 sd->u.s.specular.dwStride,
1138                 sd->u.s.specular.lpData));
1139         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1140             if(curVBO != sd->u.s.specular.VBO) {
1141                 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1142                 checkGLcall("glBindBufferARB");
1143                 curVBO = sd->u.s.specular.VBO;
1144             }
1145             GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1146                                                    sd->u.s.specular.dwStride,
1147                                                    sd->u.s.specular.lpData);
1148             vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1149             glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1150             vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1151         } else {
1152
1153         /* Missing specular color is not critical, no warnings */
1154         VTRACE(("Specular colour is not supported in this GL implementation\n"));
1155         }
1156
1157     } else {
1158         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1159
1160             glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1161             checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1162             GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1163             checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1164         } else {
1165
1166             /* Missing specular color is not critical, no warnings */
1167             VTRACE(("Specular colour is not supported in this GL implementation\n"));
1168         }
1169     }
1170
1171     /* Texture coords -------------------------------------------*/
1172
1173     for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1174         /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1175         /* Abort if we don't support the extension. */
1176         if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1177             FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1178             continue;
1179         }
1180
1181         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1182             /* Select the correct texture stage */
1183             GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1184         }
1185
1186         if (This->stateBlock->textures[textureNo] != NULL) {
1187             int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1188
1189             if (coordIdx >= MAX_TEXTURES) {
1190                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1191                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1192                 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1193
1194             } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1195                 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1196                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1197                 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1198
1199             } else {
1200                 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1201                       textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1202                 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1203                     GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1204                     checkGLcall("glBindBufferARB");
1205                     curVBO = sd->u.s.texCoords[coordIdx].VBO;
1206                 }
1207                 /* The coords to supply depend completely on the fvf / vertex shader */
1208                 glTexCoordPointer(
1209                     WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1210                     WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1211                     sd->u.s.texCoords[coordIdx].dwStride,
1212                     sd->u.s.texCoords[coordIdx].lpData);
1213                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1214             }
1215         } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1216             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1217             GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1218         }
1219         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1220     }
1221     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1222         for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1223             GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1224             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1225             GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1226         }
1227     }
1228 }
1229
1230 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1231                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1232     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1233
1234     if (idxData != NULL /* This crashes sometimes!*/) {
1235         TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1236         idxData = idxData == (void *)-1 ? NULL : idxData;
1237 #if 1
1238 #if 0
1239         glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1240         glEnableClientState(GL_INDEX_ARRAY);
1241 #endif
1242         glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1243                      (const char *)idxData+(idxSize * startIdx));
1244 #else /* using drawRangeElements may be faster */
1245
1246         glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1247                       idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1248                       (const char *)idxData+(idxSize * startIdx));
1249 #endif
1250         checkGLcall("glDrawRangeElements");
1251
1252     } else {
1253
1254         /* Note first is now zero as we shuffled along earlier */
1255         TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1256         glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1257         checkGLcall("glDrawArrays");
1258
1259     }
1260
1261     return;
1262 }
1263
1264 /*
1265  * Actually draw using the supplied information.
1266  * Slower GL version which extracts info about each vertex in turn
1267  */
1268         
1269 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1270                      UINT NumVertexes, GLenum glPrimType,
1271                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1272
1273     unsigned int               textureNo    = 0;
1274     unsigned int               texture_idx  = 0;
1275     const short               *pIdxBufS     = NULL;
1276     const long                *pIdxBufL     = NULL;
1277     LONG                       SkipnStrides = 0;
1278     LONG                       vx_index;
1279     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1280     float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */
1281     float rhw = 0.0f;                      /* rhw                        */
1282     float ptSize = 0.0f;                   /* Point size                 */
1283     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
1284     DWORD specularColor = 0;               /* Specular Color             */
1285     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1286
1287     TRACE("Using slow vertex array code\n");
1288
1289     /* Variable Initialization */
1290     if (idxData != NULL) {
1291         if (idxSize == 2) pIdxBufS = (const short *) idxData;
1292         else pIdxBufL = (const long *) idxData;
1293     }
1294
1295     /* Start drawing in GL */
1296     VTRACE(("glBegin(%x)\n", glPrimType));
1297     glBegin(glPrimType);
1298
1299     /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1300      * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1301      */
1302
1303     /* For each primitive */
1304     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1305
1306         /* Initialize diffuse color */
1307         diffuseColor = 0xFFFFFFFF;
1308
1309         /* For indexed data, we need to go a few more strides in */
1310         if (idxData != NULL) {
1311
1312             /* Indexed so work out the number of strides to skip */
1313             if (idxSize == 2) {
1314                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1315                 SkipnStrides = pIdxBufS[startIdx + vx_index];
1316             } else {
1317                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1318                 SkipnStrides = pIdxBufL[startIdx + vx_index];
1319             }
1320         }
1321
1322         /* Position Information ------------------ */
1323         if (sd->u.s.position.lpData != NULL) {
1324
1325             float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1326             x = ptrToCoords[0];
1327             y = ptrToCoords[1];
1328             z = ptrToCoords[2];
1329             rhw = 1.0;
1330             VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1331
1332             /* RHW follows, only if transformed, ie 4 floats were provided */
1333             if (sd->u.s.position_transformed) {
1334                 rhw = ptrToCoords[3];
1335                 VTRACE(("rhw=%f\n", rhw));
1336             }
1337         }
1338
1339         /* Blending data -------------------------- */
1340         if (sd->u.s.blendWeights.lpData != NULL) {
1341             /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1342             FIXME("Blending not supported yet\n");
1343
1344             if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1345                 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1346             }
1347         }
1348
1349         /* Vertex Normal Data (untransformed only)- */
1350         if (sd->u.s.normal.lpData != NULL) {
1351
1352             float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1353             nx = ptrToCoords[0];
1354             ny = ptrToCoords[1];
1355             nz = ptrToCoords[2];
1356             VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1357         }
1358
1359         /* Point Size ----------------------------- */
1360         if (sd->u.s.pSize.lpData != NULL) {
1361
1362             float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1363             ptSize = ptrToCoords[0];
1364             VTRACE(("ptSize=%f\n", ptSize));
1365             FIXME("No support for ptSize yet\n");
1366         }
1367
1368         /* Diffuse -------------------------------- */
1369         if (sd->u.s.diffuse.lpData != NULL) {
1370
1371             DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1372             diffuseColor = ptrToCoords[0];
1373             VTRACE(("diffuseColor=%lx\n", diffuseColor));
1374         }
1375
1376         /* Specular  -------------------------------- */
1377         if (sd->u.s.specular.lpData != NULL) {
1378
1379             DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1380             specularColor = ptrToCoords[0];
1381             VTRACE(("specularColor=%lx\n", specularColor));
1382         }
1383
1384         /* Texture coords --------------------------- */
1385         for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1386
1387             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1388                 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1389                 continue ;
1390             }
1391
1392             /* Query tex coords */
1393             if (This->stateBlock->textures[textureNo] != NULL) {
1394
1395                 int    coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1396                 float *ptrToCoords = NULL;
1397                 float  s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1398
1399                 if (coordIdx > 7) {
1400                     VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1401                     ++texture_idx;
1402                     continue;
1403                 } else if (coordIdx < 0) {
1404                     FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1405                     ++texture_idx;
1406                     continue;
1407                 }
1408
1409                 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1410                 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1411                     TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1412                     ++texture_idx;
1413                     continue;
1414                 } else {
1415
1416                     int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
1417
1418                     /* The coords to supply depend completely on the fvf / vertex shader */
1419                     switch (coordsToUse) {
1420                     case 4: q = ptrToCoords[3]; /* drop through */
1421                     case 3: r = ptrToCoords[2]; /* drop through */
1422                     case 2: t = ptrToCoords[1]; /* drop through */
1423                     case 1: s = ptrToCoords[0];
1424                     }
1425
1426                     /* Projected is more 'fun' - Move the last coord to the 'q'
1427                           parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
1428                     if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
1429                         (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
1430
1431                         if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
1432                             switch (coordsToUse) {
1433                             case 0:  /* Drop Through */
1434                             case 1:
1435                                 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
1436                                 break;
1437                             case 2:
1438                                 q = t;
1439                                 t = 0.0;
1440                                 coordsToUse = 4;
1441                                 break;
1442                             case 3:
1443                                 q = r;
1444                                 r = 0.0;
1445                                 coordsToUse = 4;
1446                                 break;
1447                             case 4:  /* Nop here */
1448                                 break;
1449                             default:
1450                                 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
1451                                       This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
1452                             }
1453                         }
1454                     }
1455
1456                     switch (coordsToUse) {   /* Supply the provided texture coords */
1457                     case WINED3DTTFF_COUNT1:
1458                         VTRACE(("tex:%d, s=%f\n", textureNo, s));
1459                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1460                             GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1461                         } else {
1462                             glTexCoord1f(s);
1463                         }
1464                         break;
1465                     case WINED3DTTFF_COUNT2:
1466                         VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1467                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1468                             GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1469                         } else {
1470                             glTexCoord2f(s, t);
1471                         }
1472                         break;
1473                     case WINED3DTTFF_COUNT3:
1474                         VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1475                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1476                             GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1477                         } else {
1478                             glTexCoord3f(s, t, r);
1479                         }
1480                         break;
1481                     case WINED3DTTFF_COUNT4:
1482                         VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1483                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1484                             GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1485                         } else {
1486                             glTexCoord4f(s, t, r, q);
1487                         }
1488                         break;
1489                     default:
1490                         FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1491                     }
1492                 }
1493             }
1494             if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1495         } /* End of textures */
1496
1497         /* Diffuse -------------------------------- */
1498         if (sd->u.s.diffuse.lpData != NULL) {
1499           glColor4ub(D3DCOLOR_B_R(diffuseColor),
1500                      D3DCOLOR_B_G(diffuseColor),
1501                      D3DCOLOR_B_B(diffuseColor),
1502                      D3DCOLOR_B_A(diffuseColor));
1503             VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n", 
1504                     D3DCOLOR_B_R(diffuseColor),
1505                     D3DCOLOR_B_G(diffuseColor),
1506                     D3DCOLOR_B_B(diffuseColor),
1507                     D3DCOLOR_B_A(diffuseColor)));
1508         } else {
1509             if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1510         }
1511
1512         /* Specular ------------------------------- */
1513         if (sd->u.s.specular.lpData != NULL) {
1514             /* special case where the fog density is stored in the diffuse alpha channel */
1515             if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1516               (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
1517               This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
1518                 if(GL_SUPPORT(EXT_FOG_COORD)) {
1519                     GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1520                 } else {
1521                     static BOOL warned = FALSE;
1522                     if(!warned) {
1523                         /* TODO: Use the fog table code from old ddraw */
1524                         FIXME("Implement fog for transformed vertices in software\n");
1525                         warned = TRUE;
1526                     }
1527                 }
1528             }
1529
1530             VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", 
1531                     D3DCOLOR_B_R(specularColor), 
1532                     D3DCOLOR_B_G(specularColor), 
1533                     D3DCOLOR_B_B(specularColor)));
1534             if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1535                 GL_EXTCALL(glSecondaryColor3ubEXT)(
1536                            D3DCOLOR_B_R(specularColor),
1537                            D3DCOLOR_B_G(specularColor),
1538                            D3DCOLOR_B_B(specularColor));
1539             } else {
1540                 /* Do not worry if specular colour missing and disable request */
1541                 VTRACE(("Specular color extensions not supplied\n"));
1542             }
1543         } else {
1544             if (vx_index == 0) {
1545                 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1546                     GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1547                 } else {
1548                     /* Do not worry if specular colour missing and disable request */
1549                     VTRACE(("Specular color extensions not supplied\n"));
1550                 }
1551             }
1552         }
1553
1554         /* Normal -------------------------------- */
1555         if (sd->u.s.normal.lpData != NULL) {
1556             VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1557             glNormal3f(nx, ny, nz);
1558         } else {
1559             if (vx_index == 0) glNormal3f(0, 0, 1);
1560         }
1561
1562         /* Position -------------------------------- */
1563         if (sd->u.s.position.lpData != NULL) {
1564             if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1565                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1566                 glVertex3f(x, y, z);
1567             } else {
1568                 GLfloat w = 1.0 / rhw;
1569                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1570                 glVertex4f(x*w, y*w, z*w, w);
1571             }
1572         }
1573
1574         /* For non indexed mode, step onto next parts */
1575         if (idxData == NULL) {
1576             ++SkipnStrides;
1577         }
1578     }
1579
1580     glEnd();
1581     checkGLcall("glEnd and previous calls");
1582 }
1583
1584 #if 0 /* TODO: Software/Hardware vertex blending support */
1585 /*
1586  * Draw with emulated vertex shaders
1587  * Note: strided data is uninitialized, as we need to pass the vertex
1588  *     shader directly as ordering irs yet
1589  */
1590 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1591                      int PrimitiveType, ULONG NumPrimitives,
1592                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1593
1594     unsigned int               textureNo    = 0;
1595     GLenum                     glPrimType   = GL_POINTS;
1596     int                        NumVertexes  = NumPrimitives;
1597     const short               *pIdxBufS     = NULL;
1598     const long                *pIdxBufL     = NULL;
1599     LONG                       SkipnStrides = 0;
1600     LONG                       vx_index;
1601     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1602     float rhw = 0.0f;                      /* rhw                        */
1603     float ptSize = 0.0f;                   /* Point size                 */
1604     D3DVECTOR_4 texcoords[8];              /* Texture Coords             */
1605     int   numcoords[8];                    /* Number of coords           */
1606     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1607
1608     IDirect3DVertexShaderImpl* vertexShader = NULL;
1609
1610     TRACE("Using slow software vertex shader code\n");
1611
1612     /* Variable Initialization */
1613     if (idxData != NULL) {
1614         if (idxSize == 2) pIdxBufS = (const short *) idxData;
1615         else pIdxBufL = (const long *) idxData;
1616     }
1617
1618     /* Ok, Work out which primitive is requested and how many vertexes that will be */
1619     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1620
1621     /* Retrieve the VS information */
1622     vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1623
1624     /* Start drawing in GL */
1625     VTRACE(("glBegin(%x)\n", glPrimType));
1626     glBegin(glPrimType);
1627
1628     /* For each primitive */
1629     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1630
1631         /* For indexed data, we need to go a few more strides in */
1632         if (idxData != NULL) {
1633
1634             /* Indexed so work out the number of strides to skip */
1635             if (idxSize == 2) {
1636                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1637                 SkipnStrides = pIdxBufS[startIdx+vx_index];
1638             } else {
1639                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1640                 SkipnStrides = pIdxBufL[startIdx+vx_index];
1641             }
1642         }
1643
1644         /* Fill the vertex shader input */
1645         IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1646
1647         /* Initialize the output fields to the same defaults as it would normally have */
1648         memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1649         vertexShader->output.oD[0].x = 1.0;
1650         vertexShader->output.oD[0].y = 1.0;
1651         vertexShader->output.oD[0].z = 1.0;
1652         vertexShader->output.oD[0].w = 1.0;
1653
1654         /* Now execute the vertex shader */
1655         IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1656
1657         /*
1658         TRACE_VECTOR(vertexShader->output.oPos);
1659         TRACE_VECTOR(vertexShader->output.oD[0]);
1660         TRACE_VECTOR(vertexShader->output.oD[1]);
1661         TRACE_VECTOR(vertexShader->output.oT[0]);
1662         TRACE_VECTOR(vertexShader->output.oT[1]);
1663         TRACE_VECTOR(vertexShader->input.V[0]);
1664         TRACE_VECTOR(vertexShader->data->C[0]);
1665         TRACE_VECTOR(vertexShader->data->C[1]);
1666         TRACE_VECTOR(vertexShader->data->C[2]);
1667         TRACE_VECTOR(vertexShader->data->C[3]);
1668         TRACE_VECTOR(vertexShader->data->C[4]);
1669         TRACE_VECTOR(vertexShader->data->C[5]);
1670         TRACE_VECTOR(vertexShader->data->C[6]);
1671         TRACE_VECTOR(vertexShader->data->C[7]);
1672         */
1673
1674         /* Extract out the output */
1675         /* FIXME: Fog coords? */
1676         x = vertexShader->output.oPos.x;
1677         y = vertexShader->output.oPos.y;
1678         z = vertexShader->output.oPos.z;
1679         rhw = vertexShader->output.oPos.w;
1680         ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1681
1682         /** Update textures coords using vertexShader->output.oT[0->7] */
1683         memset(texcoords, 0x00, sizeof(texcoords));
1684         memset(numcoords, 0x00, sizeof(numcoords));
1685         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1686             if (This->stateBlock->textures[textureNo] != NULL) {
1687                texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1688                texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1689                texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1690                texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1691                if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1692                    numcoords[textureNo]    = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1693                } else {
1694                    switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1695                    case WINED3DRTYPE_TEXTURE:       numcoords[textureNo] = 2; break;
1696                    case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1697                    default:                         numcoords[textureNo] = 4;
1698                    }
1699                }
1700             } else {
1701                 numcoords[textureNo] = 0;
1702             }
1703         }
1704
1705         /* Draw using this information */
1706         draw_vertex(iface,
1707                     TRUE, x, y, z, rhw,
1708                     TRUE, 0.0f, 0.0f, 1.0f,
1709                     TRUE, (float*) &vertexShader->output.oD[0],
1710                     TRUE, (float*) &vertexShader->output.oD[1],
1711                     FALSE, ptSize,         /* FIXME: Change back when supported */
1712                     texcoords, numcoords);
1713
1714         /* For non indexed mode, step onto next parts */
1715         if (idxData == NULL) {
1716            ++SkipnStrides;
1717         }
1718
1719     } /* for each vertex */
1720
1721     glEnd();
1722     checkGLcall("glEnd and previous calls");
1723 }
1724
1725 #endif
1726
1727 inline static void drawPrimitiveDrawStrided(
1728     IWineD3DDevice *iface,
1729     BOOL useVertexShaderFunction,
1730     BOOL usePixelShaderFunction,
1731     WineDirect3DVertexStridedData *dataLocations,
1732     UINT numberOfvertices,
1733     UINT numberOfIndicies,
1734     GLenum glPrimType,
1735     const void *idxData,
1736     short idxSize,
1737     int minIndex,
1738     long StartIdx,
1739     BOOL fixup) {
1740
1741     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1742     BOOL useDrawStridedSlow;
1743
1744     int startStride = idxData == NULL ? 0 : 
1745                       idxData == (void *) -1 ? 0 :
1746                       (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1747     int endStride = startStride;
1748     TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1749         startStride, endStride, numberOfIndicies, numberOfvertices);
1750
1751 /* Generate some fixme's if unsupported functionality is being used */
1752 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1753     /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1754     if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1755         FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1756     }
1757     if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1758         FIXME("Tweening is only valid with vertex shaders\n");
1759     }
1760     if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1761         FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1762     }
1763     if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1764         FIXME("Extended attributes are only valid with vertex shaders\n");
1765     }
1766 #undef BUFFER_OR_DATA
1767
1768     /* Fixed pipeline, no fixups required - load arrays */
1769     if (!useVertexShaderFunction &&
1770        ((dataLocations->u.s.pSize.lpData == NULL &&
1771          dataLocations->u.s.diffuse.lpData == NULL &&
1772          dataLocations->u.s.specular.lpData == NULL) ||
1773          fixup) ) {
1774
1775         /* Load the vertex data using named arrays */
1776         TRACE("(%p) Loading vertex data\n", This);
1777         loadVertexData(iface, dataLocations);
1778         useDrawStridedSlow = FALSE;
1779
1780     /* Shader pipeline - load attribute arrays */
1781     } else if(useVertexShaderFunction) {
1782
1783         loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1784         useDrawStridedSlow = FALSE;
1785
1786         /* We compile the shader here because we need the vertex declaration
1787          * in order to determine if we need to do any swizzling for D3DCOLOR
1788          * registers. If the shader is already compiled this call will do nothing. */
1789         IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1790     /* Draw vertex by vertex */
1791     } else { 
1792         TRACE("Not loading vertex data\n");
1793         useDrawStridedSlow = TRUE;
1794     }
1795
1796     if(usePixelShaderFunction) {
1797         /* We compile the shader here because it depends on the texture stage state
1798          * setup of the bound textures. If the shader is already compiled and the texture stage
1799          * state setup matches the program this function will do nothing
1800          */
1801         IWineD3DPixelShader_CompileShader(This->stateBlock->pixelShader);
1802     }
1803
1804     /* Make any shaders active */
1805     This->shader_backend->shader_select(iface, usePixelShaderFunction, useVertexShaderFunction);
1806
1807     /* Load any global constants/uniforms that may have been set by the application */
1808     This->shader_backend->shader_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1809
1810     /* Draw vertex-by-vertex */
1811     if (useDrawStridedSlow)
1812         drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex,  StartIdx);
1813     else
1814         drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1815
1816     /* Cleanup any shaders */
1817     This->shader_backend->shader_cleanup(usePixelShaderFunction, useVertexShaderFunction);
1818
1819     /* Unload vertex data */
1820     if (useVertexShaderFunction) {
1821         unloadNumberedArrays(iface);
1822     } else {
1823         unloadVertexData(iface);
1824     }
1825 }
1826
1827 inline void drawPrimitiveTraceDataLocations(
1828     WineDirect3DVertexStridedData *dataLocations) {
1829
1830     /* Dump out what parts we have supplied */
1831     TRACE("Strided Data:\n");
1832     TRACE_STRIDED((dataLocations), position);
1833     TRACE_STRIDED((dataLocations), blendWeights);
1834     TRACE_STRIDED((dataLocations), blendMatrixIndices);
1835     TRACE_STRIDED((dataLocations), normal);
1836     TRACE_STRIDED((dataLocations), pSize);
1837     TRACE_STRIDED((dataLocations), diffuse);
1838     TRACE_STRIDED((dataLocations), specular);
1839     TRACE_STRIDED((dataLocations), texCoords[0]);
1840     TRACE_STRIDED((dataLocations), texCoords[1]);
1841     TRACE_STRIDED((dataLocations), texCoords[2]);
1842     TRACE_STRIDED((dataLocations), texCoords[3]);
1843     TRACE_STRIDED((dataLocations), texCoords[4]);
1844     TRACE_STRIDED((dataLocations), texCoords[5]);
1845     TRACE_STRIDED((dataLocations), texCoords[6]);
1846     TRACE_STRIDED((dataLocations), texCoords[7]);
1847     TRACE_STRIDED((dataLocations), position2);
1848     TRACE_STRIDED((dataLocations), normal2);
1849     TRACE_STRIDED((dataLocations), tangent);
1850     TRACE_STRIDED((dataLocations), binormal);
1851     TRACE_STRIDED((dataLocations), tessFactor);
1852     TRACE_STRIDED((dataLocations), fog);
1853     TRACE_STRIDED((dataLocations), depth);
1854     TRACE_STRIDED((dataLocations), sample);
1855
1856     return;
1857
1858 }
1859
1860 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1861     INT i;
1862
1863     for (i = 0; i < GL_LIMITS(samplers); ++i) {
1864         /* Pixel shader support should imply multitexture support. */
1865         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1866             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1867             checkGLcall("glActiveTextureARB");
1868         } else if (i) {
1869             WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1870         }
1871
1872         if (!This->stateBlock->textures[i]) continue;
1873
1874         /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1875         glDisable(GL_TEXTURE_1D);
1876         This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1877         switch(This->stateBlock->textureDimensions[i]) {
1878             case GL_TEXTURE_2D:
1879                 glDisable(GL_TEXTURE_3D);
1880                 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1881                 break;
1882             case GL_TEXTURE_3D:
1883                 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1884                 glDisable(GL_TEXTURE_2D);
1885                 break;
1886             case GL_TEXTURE_CUBE_MAP_ARB:
1887                 glDisable(GL_TEXTURE_2D);
1888                 glDisable(GL_TEXTURE_3D);
1889                 break;
1890         }
1891         glEnable(This->stateBlock->textureDimensions[i]);
1892
1893         /* Upload texture, apply states */
1894         IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1895         IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1896         IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1897     }
1898 }
1899
1900 /* uploads textures and setup texture states ready for rendering */
1901 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1902     INT current_sampler = 0;
1903     float constant_color[4];
1904     unsigned int i;
1905
1906     /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1907      * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1908      * Register combiners however provide up to 8 combiner stages. In order to
1909      * take advantage of this, we need to be separate D3D texture stages from
1910      * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1911      * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1912      * corresponds to MaxTextureBlendStages in the caps. */
1913
1914     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1915         glEnable(GL_REGISTER_COMBINERS_NV);
1916         D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1917         GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1918     }
1919
1920     for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1921         INT texture_idx = -1;
1922
1923         /* WINED3DTOP_DISABLE disables the current & any higher texture stages */
1924         if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) break;
1925
1926         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1927             texture_idx = current_sampler++;
1928
1929             /* Active the texture unit corresponding to the current texture stage */
1930             if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1931                 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1932                 checkGLcall("glActiveTextureARB");
1933             } else if (i) {
1934                 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1935             }
1936         }
1937
1938         if (This->stateBlock->textures[i]) {
1939             /* Enable the correct target. */
1940             glDisable(GL_TEXTURE_1D);
1941             This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1942             switch(This->stateBlock->textureDimensions[i]) {
1943                 case GL_TEXTURE_2D:
1944                     glDisable(GL_TEXTURE_3D);
1945                     glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1946                     break;
1947                 case GL_TEXTURE_3D:
1948                     glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1949                     glDisable(GL_TEXTURE_2D);
1950                     break;
1951                 case GL_TEXTURE_CUBE_MAP_ARB:
1952                     glDisable(GL_TEXTURE_2D);
1953                     glDisable(GL_TEXTURE_3D);
1954                     break;
1955             }
1956
1957             /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
1958             if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
1959                 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1960             } else {
1961                 glEnable(This->stateBlock->textureDimensions[i]);
1962             }
1963
1964             /* Upload texture, apply states */
1965             IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1966             IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
1967             IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1968         } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1969             /* ARB_texture_env_combine needs a valid texture bound to the
1970              * texture unit, even if it isn't used. Bind a dummy texture. */
1971             glDisable(GL_TEXTURE_2D);
1972             glDisable(GL_TEXTURE_3D);
1973             glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1974             glEnable(GL_TEXTURE_1D);
1975             This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
1976             glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
1977         }
1978
1979         /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
1980           dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
1981         if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1982             set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
1983                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
1984                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
1985                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
1986                     texture_idx);
1987             /* alphaop */
1988             set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
1989                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
1990                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
1991                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
1992                     texture_idx);
1993         } else {
1994             set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
1995                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
1996                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
1997                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
1998             /* alphaop */
1999             set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2000                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2001                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2002                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2003         }
2004     }
2005
2006     /* If we're using register combiners, set the amount of *used* combiners.
2007      * Ie, the number of stages below the first stage to have a color op of
2008      * WINED3DTOP_DISABLE. */
2009     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2010         /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2011         if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2012         else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2013     }
2014
2015     /* Disable the remaining texture units. */
2016     for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2017         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2018         glDisable(GL_TEXTURE_1D);
2019         glDisable(GL_TEXTURE_2D);
2020         glDisable(GL_TEXTURE_3D);
2021         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2022     }
2023 }
2024
2025 static void check_fbo_status(IWineD3DDevice *iface) {
2026     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2027
2028     GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
2029     switch(status) {
2030         case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
2031         default: TRACE("FBO status %#x.\n", status); break;
2032     }
2033 }
2034
2035 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
2036     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2037
2038     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
2039
2040     glDisable(GL_CULL_FACE);
2041     glDisable(GL_BLEND);
2042     glDisable(GL_ALPHA_TEST);
2043     glDisable(GL_STENCIL_TEST);
2044     glEnable(GL_DEPTH_TEST);
2045     glDepthFunc(GL_ALWAYS);
2046
2047     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2048     glBindTexture(GL_TEXTURE_2D, texture);
2049     glEnable(GL_TEXTURE_2D);
2050
2051     This->shader_backend->shader_select_depth_blt(iface);
2052
2053     glBegin(GL_TRIANGLE_STRIP);
2054     glVertex2f(-1.0f, -1.0f);
2055     glVertex2f(1.0f, -1.0f);
2056     glVertex2f(-1.0f, 1.0f);
2057     glVertex2f(1.0f, 1.0f);
2058     glEnd();
2059
2060     glPopAttrib();
2061 }
2062
2063 static void depth_copy(IWineD3DDevice *iface) {
2064     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2065     IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
2066
2067     /* Only copy the depth buffer if there is one. */
2068     if (!depth_stencil) return;
2069
2070     /* TODO: Make this work for modes other than FBO */
2071     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2072
2073     if (This->render_offscreen) {
2074         static GLuint tmp_texture = 0;
2075
2076         TRACE("Copying onscreen depth buffer to offscreen surface\n");
2077
2078         if (!tmp_texture) {
2079             glGenTextures(1, &tmp_texture);
2080         }
2081
2082         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2083          * directly on the FBO texture. That's because we need to flip. */
2084         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
2085         glBindTexture(GL_TEXTURE_2D, tmp_texture);
2086         glCopyTexImage2D(depth_stencil->glDescription.target,
2087                 depth_stencil->glDescription.level,
2088                 depth_stencil->glDescription.glFormatInternal,
2089                 0,
2090                 0,
2091                 depth_stencil->currentDesc.Width,
2092                 depth_stencil->currentDesc.Height,
2093                 0);
2094         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2095         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2096         glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
2097
2098         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
2099         checkGLcall("glBindFramebuffer()");
2100         depth_blt(iface, tmp_texture);
2101         checkGLcall("depth_blt");
2102     } else {
2103         TRACE("Copying offscreen surface to onscreen depth buffer\n");
2104
2105         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
2106         checkGLcall("glBindFramebuffer()");
2107         depth_blt(iface, depth_stencil->glDescription.textureName);
2108         checkGLcall("depth_blt");
2109     }
2110 }
2111
2112 /* Routine common to the draw primitive and draw indexed primitive routines */
2113 void drawPrimitive(IWineD3DDevice *iface,
2114                    int PrimitiveType,
2115                    long NumPrimitives,
2116                    /* for Indexed: */
2117                    long  StartVertexIndex,
2118                    UINT  numberOfVertices,
2119                    long  StartIdx,
2120                    short idxSize,
2121                    const void *idxData,
2122                    int   minIndex,
2123                    WineDirect3DVertexStridedData *DrawPrimStrideData) {
2124
2125     IWineD3DDeviceImpl           *This = (IWineD3DDeviceImpl *)iface;
2126     BOOL                          useVertexShaderFunction = FALSE;
2127     BOOL                          usePixelShaderFunction = FALSE;
2128     WineDirect3DVertexStridedData *dataLocations;
2129     IWineD3DSwapChainImpl         *swapchain;
2130     int                           i;
2131     BOOL                          fixup = FALSE;
2132
2133     BOOL lighting_changed, lighting_original = FALSE;
2134
2135     if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2136         check_fbo_status(iface);
2137     }
2138
2139     if (This->depth_copy_state == WINED3D_DCS_COPY) {
2140         depth_copy(iface);
2141     }
2142     This->depth_copy_state = WINED3D_DCS_INITIAL;
2143
2144     /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software - 
2145      * here simply check whether a shader was set, or the user disabled shaders */
2146     if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader && 
2147         ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL) 
2148         useVertexShaderFunction = TRUE;
2149
2150     if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2151         ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) 
2152         usePixelShaderFunction = TRUE;
2153
2154     /* Invalidate the back buffer memory so LockRect will read it the next time */
2155     for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2156         IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2157         if(swapchain) {
2158             if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2159         }
2160     }
2161
2162     /* Ok, we will be updating the screen from here onwards so grab the lock */
2163     ENTER_GL();
2164
2165     if(DrawPrimStrideData) {
2166
2167         /* Note: this is a ddraw fixed-function code path */
2168
2169         TRACE("================ Strided Input ===================\n");
2170         dataLocations = DrawPrimStrideData;
2171         drawPrimitiveTraceDataLocations(dataLocations);
2172         fixup = FALSE;
2173     }
2174
2175     else if (This->stateBlock->vertexDecl || This->stateBlock->vertexShader) {
2176
2177         /* Note: This is a fixed function or shader codepath.
2178          * This means it must handle both types of strided data.
2179          * Shaders must go through here to zero the strided data, even if they
2180          * don't set any declaration at all */
2181
2182         TRACE("================ Vertex Declaration  ===================\n");
2183         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2184         if(!dataLocations) {
2185             ERR("Out of memory!\n");
2186             return;
2187         }
2188
2189         if (This->stateBlock->vertexDecl != NULL ||
2190             ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)            
2191
2192             primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction, 
2193                 dataLocations, StartVertexIndex, &fixup);
2194
2195     } else {
2196
2197         /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2198          * It is reachable through d3d8, but only for fixed-function.
2199          * It will not work properly for shaders. */
2200
2201         TRACE("================ FVF ===================\n");
2202         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2203         if(!dataLocations) {
2204             ERR("Out of memory!\n");
2205             return;
2206         }
2207         primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2208         drawPrimitiveTraceDataLocations(dataLocations);
2209     }
2210
2211     /* Setup transform matrices and sort out */
2212     primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2213
2214     /* Now initialize the materials state */
2215     init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2216
2217     if (usePixelShaderFunction) {
2218         drawPrimitiveUploadTexturesPS(This);
2219     } else {
2220         drawPrimitiveUploadTextures(This);
2221     }
2222
2223     {
2224         GLenum glPrimType;
2225         /* Ok, Work out which primitive is requested and how many vertexes that
2226            will be                                                              */
2227         UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2228         if (numberOfVertices == 0 )
2229             numberOfVertices = calculatedNumberOfindices;
2230
2231         drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2232             dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2233             idxData, idxSize, minIndex, StartIdx, fixup);
2234     }
2235
2236     if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2237
2238     /* If vertex shaders or no normals, restore previous lighting state */
2239     if (lighting_changed) {
2240         if (lighting_original) glEnable(GL_LIGHTING);
2241         else glDisable(GL_LIGHTING);
2242         TRACE("Restored lighting to original state\n");
2243     }
2244
2245     /* Finshed updating the screen, restore lock */
2246     LEAVE_GL();
2247     TRACE("Done all gl drawing\n");
2248
2249     /* Diagnostics */
2250 #ifdef SHOW_FRAME_MAKEUP
2251     {
2252         static long int primCounter = 0;
2253         /* NOTE: set primCounter to the value reported by drawprim 
2254            before you want to to write frame makeup to /tmp */
2255         if (primCounter >= 0) {
2256             WINED3DLOCKED_RECT r;
2257             char buffer[80];
2258             IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2259             sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
2260             TRACE("Saving screenshot %s\n", buffer);
2261             IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2262             IWineD3DSurface_UnlockRect(This->renderTarget);
2263
2264 #ifdef SHOW_TEXTURE_MAKEUP
2265            {
2266             IWineD3DSurface *pSur;
2267             int textureNo;
2268             for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2269                 if (This->stateBlock->textures[textureNo] != NULL) {
2270                     sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2271                     TRACE("Saving texture %s\n", buffer);
2272                     if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2273                             IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2274                             IWineD3DSurface_SaveSnapshot(pSur, buffer);
2275                             IWineD3DSurface_Release(pSur);
2276                     } else  {
2277                         FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2278                     }
2279                 }
2280             }
2281            }
2282 #endif
2283         }
2284         TRACE("drawprim #%d\n", primCounter);
2285         ++primCounter;
2286     }
2287 #endif
2288 }