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