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