wined3d: Do not activate vertex shaders needlessly.
[wine] / dlls / wined3d / drawprim.c
1 /*
2  * WINED3D draw functions
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  * Copyright 2006 Henri Verbeet
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
30
31 #include <stdio.h>
32
33 #if 0 /* TODO */
34 extern IWineD3DVertexShaderImpl*            VertexShaders[64];
35 extern IWineD3DVertexDeclarationImpl*       VertexShaderDeclarations[64];
36 extern IWineD3DPixelShaderImpl*             PixelShaders[64];
37
38 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
39 #endif
40
41 /* Issues the glBegin call for gl given the primitive type and count */
42 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
43                     DWORD            NumPrimitives,
44                     GLenum          *primType)
45 {
46     DWORD   NumVertexes = NumPrimitives;
47
48     switch (PrimitiveType) {
49     case WINED3DPT_POINTLIST:
50         TRACE("POINTS\n");
51         *primType   = GL_POINTS;
52         NumVertexes = NumPrimitives;
53         break;
54
55     case WINED3DPT_LINELIST:
56         TRACE("LINES\n");
57         *primType   = GL_LINES;
58         NumVertexes = NumPrimitives * 2;
59         break;
60
61     case WINED3DPT_LINESTRIP:
62         TRACE("LINE_STRIP\n");
63         *primType   = GL_LINE_STRIP;
64         NumVertexes = NumPrimitives + 1;
65         break;
66
67     case WINED3DPT_TRIANGLELIST:
68         TRACE("TRIANGLES\n");
69         *primType   = GL_TRIANGLES;
70         NumVertexes = NumPrimitives * 3;
71         break;
72
73     case WINED3DPT_TRIANGLESTRIP:
74         TRACE("TRIANGLE_STRIP\n");
75         *primType   = GL_TRIANGLE_STRIP;
76         NumVertexes = NumPrimitives + 2;
77         break;
78
79     case WINED3DPT_TRIANGLEFAN:
80         TRACE("TRIANGLE_FAN\n");
81         *primType   = GL_TRIANGLE_FAN;
82         NumVertexes = NumPrimitives + 2;
83         break;
84
85     default:
86         FIXME("Unhandled primitive\n");
87         *primType    = GL_POINTS;
88         break;
89     }
90     return NumVertexes;
91 }
92
93 /* Ensure the appropriate material states are set up - only change
94    state if really required                                        */
95 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
96
97     BOOL requires_material_reset = FALSE;
98     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
99
100     if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
101         /* If we have not set up the material color tracking, do it now as required */
102         glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
103         checkGLcall("glDisable GL_COLOR_MATERIAL");
104         TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
105         glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
106         checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
107         glEnable(GL_COLOR_MATERIAL);
108         checkGLcall("glEnable GL_COLOR_MATERIAL");
109         This->tracking_color = IS_TRACKING;
110         requires_material_reset = TRUE; /* Restore material settings as will be used */
111
112     } else if ((This->tracking_color == IS_TRACKING && !isDiffuseSupplied) ||
113                (This->tracking_color == NEEDS_TRACKING && !isDiffuseSupplied)) {
114         /* If we are tracking the current color but one isn't supplied, don't! */
115         glDisable(GL_COLOR_MATERIAL);
116         checkGLcall("glDisable GL_COLOR_MATERIAL");
117         This->tracking_color = NEEDS_TRACKING;
118         requires_material_reset = TRUE; /* Restore material settings as will be used */
119
120     } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
121         /* No need to reset material colors since no change to gl_color_material */
122         requires_material_reset = FALSE;
123
124     } else if (This->tracking_color == NEEDS_DISABLE) {
125         glDisable(GL_COLOR_MATERIAL);
126         checkGLcall("glDisable GL_COLOR_MATERIAL");
127         This->tracking_color = DISABLED_TRACKING;
128         requires_material_reset = TRUE; /* Restore material settings as will be used */
129     }
130
131     /* Reset the material colors which may have been tracking the color*/
132     if (requires_material_reset) {
133         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
134         checkGLcall("glMaterialfv");
135         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
136         checkGLcall("glMaterialfv");
137         if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
138            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
139            checkGLcall("glMaterialfv");
140         } else {
141            float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
142            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
143            checkGLcall("glMaterialfv");
144         }
145         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
146         checkGLcall("glMaterialfv");
147     }
148
149 }
150
151 static const 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 static BOOL fixed_get_input(
158     BYTE usage, BYTE usage_idx,
159     unsigned int* regnum) {
160
161     *regnum = -1;
162
163     /* Those positions must have the order in the
164      * named part of the strided data */
165
166     if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
167         *regnum = 0;
168     else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
169         *regnum = 1;
170     else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
171         *regnum = 2;
172     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
173         *regnum = 3;
174     else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
175         *regnum = 4;
176     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
177         *regnum = 5;
178     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
179         *regnum = 6;
180     else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
181         *regnum = 7 + usage_idx;
182     else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
183         *regnum = 7 + WINED3DDP_MAXTEXCOORD;
184     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
185         *regnum = 8 + WINED3DDP_MAXTEXCOORD;
186     else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
187         *regnum = 9 + WINED3DDP_MAXTEXCOORD;
188     else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
189         *regnum = 10 + WINED3DDP_MAXTEXCOORD;
190     else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
191         *regnum = 11 + WINED3DDP_MAXTEXCOORD;
192     else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
193         *regnum = 12 + WINED3DDP_MAXTEXCOORD;
194     else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
195         *regnum = 13 + WINED3DDP_MAXTEXCOORD;
196     else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
197         *regnum = 14 + WINED3DDP_MAXTEXCOORD;
198
199     if (*regnum < 0) {
200         FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
201             debug_d3ddeclusage(usage), usage_idx);
202         return FALSE;
203     }
204     return TRUE;
205 }
206
207 void primitiveDeclarationConvertToStridedData(
208      IWineD3DDevice *iface,
209      BOOL useVertexShaderFunction,
210      WineDirect3DVertexStridedData *strided,
211      BOOL *fixup) {
212
213      /* We need to deal with frequency data!*/
214
215     BYTE  *data    = NULL;
216     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
217     IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
218     int i;
219     WINED3DVERTEXELEMENT *element;
220     DWORD stride;
221     int reg;
222
223     /* Locate the vertex declaration */
224     if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
225         TRACE("Using vertex declaration from shader\n");
226         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
227     } else {
228         TRACE("Using vertex declaration\n");
229         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
230     }
231
232     /* Translate the declaration into strided data */
233     for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
234         GLint streamVBO = 0;
235         BOOL stride_used;
236         unsigned int idx;
237
238         element = vertexDeclaration->pDeclarationWine + i;
239         TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
240             element,  i + 1, vertexDeclaration->declarationWNumElements - 1);
241
242         if (This->stateBlock->streamSource[element->Stream] == NULL)
243             continue;
244
245         if (This->stateBlock->streamIsUP) {
246             TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
247             streamVBO = 0;
248             data    = (BYTE *)This->stateBlock->streamSource[element->Stream];
249             if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
250         } else {
251             TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
252             IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
253             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
254             if(fixup) {
255                 if( streamVBO != 0) *fixup = TRUE;
256                 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
257             }
258         }
259         stride  = This->stateBlock->streamStride[element->Stream];
260         data += element->Offset;
261         reg = element->Reg;
262
263         TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
264
265         if (useVertexShaderFunction)
266             stride_used = vshader_get_input(This->stateBlock->vertexShader,
267                 element->Usage, element->UsageIndex, &idx);
268         else
269             stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
270
271         if (stride_used) {
272            TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
273                  "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
274                  useVertexShaderFunction? "shader": "fixed function", idx,
275                  debug_d3ddeclusage(element->Usage), element->UsageIndex,
276                  element->Stream, element->Offset, stride, streamVBO);
277
278            strided->u.input[idx].lpData = data;
279            strided->u.input[idx].dwType = element->Type;
280            strided->u.input[idx].dwStride = stride;
281            strided->u.input[idx].VBO = streamVBO;
282            if (!useVertexShaderFunction) {
283                if (element->Usage == D3DDECLUSAGE_POSITION)
284                    strided->u.s.position_transformed = FALSE;
285                else if (element->Usage == D3DDECLUSAGE_POSITIONT)
286                    strided->u.s.position_transformed = TRUE;
287            }
288         }
289     };
290 }
291
292 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
293     int           numBlends;
294     int           numTextures;
295     int           textureNo;
296     int           coordIdxInfo = 0x00;    /* Information on number of coords supplied */
297     int           numCoords[8];           /* Holding place for WINED3DFVF_TEXTUREFORMATx  */
298
299     /* Either 3 or 4 floats depending on the FVF */
300     /* FIXME: Can blending data be in a different stream to the position data?
301           and if so using the fixed pipeline how do we handle it               */
302     if (thisFVF & WINED3DFVF_POSITION_MASK) {
303         strided->u.s.position.lpData    = data;
304         strided->u.s.position.dwType    = WINED3DDECLTYPE_FLOAT3;
305         strided->u.s.position.dwStride  = stride;
306         strided->u.s.position.VBO       = streamVBO;
307         data += 3 * sizeof(float);
308         if (thisFVF & WINED3DFVF_XYZRHW) {
309             strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
310             strided->u.s.position_transformed = TRUE;
311             data += sizeof(float);
312         } else
313             strided->u.s.position_transformed = FALSE;
314     }
315
316     /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
317     /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
318     numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
319     if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
320
321     if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
322         TRACE("Setting blend Weights to %p\n", data);
323         strided->u.s.blendWeights.lpData    = data;
324         strided->u.s.blendWeights.dwType    = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
325         strided->u.s.blendWeights.dwStride  = stride;
326         strided->u.s.blendWeights.VBO       = streamVBO;
327         data += numBlends * sizeof(FLOAT);
328
329         if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
330             strided->u.s.blendMatrixIndices.lpData = data;
331             strided->u.s.blendMatrixIndices.dwType  = WINED3DDECLTYPE_UBYTE4;
332             strided->u.s.blendMatrixIndices.dwStride= stride;
333             strided->u.s.blendMatrixIndices.VBO     = streamVBO;
334             data += sizeof(DWORD);
335         }
336     }
337
338     /* Normal is always 3 floats */
339     if (thisFVF & WINED3DFVF_NORMAL) {
340         strided->u.s.normal.lpData    = data;
341         strided->u.s.normal.dwType    = WINED3DDECLTYPE_FLOAT3;
342         strided->u.s.normal.dwStride  = stride;
343         strided->u.s.normal.VBO     = streamVBO;
344         data += 3 * sizeof(FLOAT);
345     }
346
347     /* Pointsize is a single float */
348     if (thisFVF & WINED3DFVF_PSIZE) {
349         strided->u.s.pSize.lpData    = data;
350         strided->u.s.pSize.dwType    = WINED3DDECLTYPE_FLOAT1;
351         strided->u.s.pSize.dwStride  = stride;
352         strided->u.s.pSize.VBO       = streamVBO;
353         data += sizeof(FLOAT);
354     }
355
356     /* Diffuse is 4 unsigned bytes */
357     if (thisFVF & WINED3DFVF_DIFFUSE) {
358         strided->u.s.diffuse.lpData    = data;
359         strided->u.s.diffuse.dwType    = WINED3DDECLTYPE_SHORT4;
360         strided->u.s.diffuse.dwStride  = stride;
361         strided->u.s.diffuse.VBO       = streamVBO;
362         data += sizeof(DWORD);
363     }
364
365     /* Specular is 4 unsigned bytes */
366     if (thisFVF & WINED3DFVF_SPECULAR) {
367         strided->u.s.specular.lpData    = data;
368         strided->u.s.specular.dwType    = WINED3DDECLTYPE_SHORT4;
369         strided->u.s.specular.dwStride  = stride;
370         strided->u.s.specular.VBO       = streamVBO;
371         data += sizeof(DWORD);
372     }
373
374     /* Texture coords */
375     numTextures   = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
376     coordIdxInfo  = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
377
378     /* numTextures indicates the number of texture coordinates supplied */
379     /* However, the first set may not be for stage 0 texture - it all   */
380     /*   depends on WINED3DTSS_TEXCOORDINDEX.                           */
381     /* The number of bytes for each coordinate set is based off         */
382     /*   WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits              */
383
384     /* So, for each supplied texture extract the coords */
385     for (textureNo = 0; textureNo < numTextures; ++textureNo) {
386
387         strided->u.s.texCoords[textureNo].lpData    = data;
388         strided->u.s.texCoords[textureNo].dwType    = WINED3DDECLTYPE_FLOAT1;
389         strided->u.s.texCoords[textureNo].dwStride  = stride;
390         strided->u.s.texCoords[textureNo].VBO       = streamVBO;
391         numCoords[textureNo] = coordIdxInfo & 0x03;
392
393         /* Always one set */
394         data += sizeof(float);
395         if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
396             strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
397             data += sizeof(float);
398             if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
399                 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
400                 data += sizeof(float);
401                 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
402                     strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
403                     data += sizeof(float);
404                 }
405             }
406         }
407         coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
408     }
409 }
410
411 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, BOOL *fixup) {
412
413     short         LoopThroughTo = 0;
414     short         nStream;
415     GLint         streamVBO = 0;
416
417     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
418
419     /* OK, Now to setup the data locations
420        For the non-created vertex shaders, the VertexShader var holds the real
421           FVF and only stream 0 matters
422        For the created vertex shaders, there is an FVF per stream              */
423     if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
424         LoopThroughTo = MAX_STREAMS;
425     } else {
426         LoopThroughTo = 1;
427     }
428
429     /* Work through stream by stream */
430     for (nStream=0; nStream<LoopThroughTo; ++nStream) {
431         DWORD  stride  = This->stateBlock->streamStride[nStream];
432         BYTE  *data    = NULL;
433         DWORD  thisFVF = 0;
434
435         /* Skip empty streams */
436         if (This->stateBlock->streamSource[nStream] == NULL) continue;
437
438         /* Retrieve appropriate FVF */
439         if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
440             thisFVF = This->stateBlock->fvf;
441             /* Handle memory passed directly as well as vertex buffers */
442             if (This->stateBlock->streamIsUP) {
443                 streamVBO = 0;
444                 data    = (BYTE *)This->stateBlock->streamSource[nStream];
445             } else {
446                 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
447                 /* GetMemory binds the VBO */
448                 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
449                 if(fixup) {
450                     if(streamVBO != 0 ) *fixup = TRUE;
451                 }
452             }
453         } else {
454 #if 0 /* TODO: Vertex shader support */
455             thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
456             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
457 #endif
458         }
459         VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
460         if (thisFVF == 0) continue;
461
462         /* Now convert the stream into pointers */
463         primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
464     }
465 }
466
467 #if 0 /* TODO: Software Shaders */
468 /* Draw a single vertex using this information */
469 static void draw_vertex(IWineD3DDevice *iface,                         /* interface    */
470                  BOOL isXYZ,    float x, float y, float z, float rhw,  /* xyzn position*/
471                  BOOL isNormal, float nx, float ny, float nz,          /* normal       */
472                  BOOL isDiffuse, float *dRGBA,                         /* 1st   colors */
473                  BOOL isSpecular, float *sRGB,                         /* 2ndry colors */
474                  BOOL isPtSize, float ptSize,                       /* pointSize    */
475                  WINED3DVECTOR_4 *texcoords, int *numcoords)        /* texture info */
476 {
477     unsigned int textureNo;
478     float s, t, r, q;
479     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
480
481     /* Diffuse -------------------------------- */
482     if (isDiffuse) {
483         glColor4fv(dRGBA);
484         VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
485     }
486
487     /* Specular Colour ------------------------------------------*/
488     if (isSpecular) {
489         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
490           GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
491           VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
492         } else {
493           VTRACE(("Specular color extensions not supplied\n"));
494         }
495     }
496
497     /* Normal -------------------------------- */
498     if (isNormal) {
499         VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
500         glNormal3f(nx, ny, nz);
501     }
502
503     /* Point Size ----------------------------------------------*/
504     if (isPtSize) {
505
506         /* no such functionality in the fixed function GL pipeline */
507         FIXME("Cannot change ptSize here in openGl\n");
508     }
509
510     /* Texture coords --------------------------- */
511     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
512
513         if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
514             FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
515             continue ;
516         }
517
518         /* Query tex coords */
519         if (This->stateBlock->textures[textureNo] != NULL) {
520
521             int    coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
522             if (coordIdx >= MAX_TEXTURES) {
523                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
524                 continue;
525             } else if (numcoords[coordIdx] == 0) {
526                 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
527                 continue;
528             } else {
529
530                 /* Initialize vars */
531                 s = 0.0f;
532                 t = 0.0f;
533                 r = 0.0f;
534                 q = 0.0f;
535
536                 switch (numcoords[coordIdx]) {
537                 case 4: q = texcoords[coordIdx].w; /* drop through */
538                 case 3: r = texcoords[coordIdx].z; /* drop through */
539                 case 2: t = texcoords[coordIdx].y; /* drop through */
540                 case 1: s = texcoords[coordIdx].x;
541                 }
542
543                 switch (numcoords[coordIdx]) {   /* Supply the provided texture coords */
544                 case WINED3DTTFF_COUNT1:
545                     VTRACE(("tex:%d, s=%f\n", textureNo, s));
546                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
547                         GLMULTITEXCOORD1F(textureNo, s);
548                     } else {
549                         glTexCoord1f(s);
550                     }
551                     break;
552                 case WINED3DTTFF_COUNT2:
553                     VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
554                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
555                         GLMULTITEXCOORD2F(textureNo, s, t);
556                     } else {
557                         glTexCoord2f(s, t);
558                     }
559                     break;
560                 case WINED3DTTFF_COUNT3:
561                     VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
562                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
563                         GLMULTITEXCOORD3F(textureNo, s, t, r);
564                     } else {
565                         glTexCoord3f(s, t, r);
566                     }
567                     break;
568                 case WINED3DTTFF_COUNT4:
569                     VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
570                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
571                         GLMULTITEXCOORD4F(textureNo, s, t, r, q);
572                     } else {
573                         glTexCoord4f(s, t, r, q);
574                     }
575                     break;
576                 default:
577                     FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
578                 }
579             }
580         }
581     } /* End of textures */
582
583     /* Position -------------------------------- */
584     if (isXYZ) {
585         if (1.0f == rhw || rhw < 0.00001f) {
586             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
587             glVertex3f(x, y, z);
588         } else {
589             /* Cannot optimize by dividing through by rhw as rhw is required
590                later for perspective in the GL pipeline for vertex shaders   */
591             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
592             glVertex4f(x,y,z,rhw);
593         }
594     }
595 }
596 #endif /* TODO: Software shaders */
597
598 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
599                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
600     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601
602     if (idxData != NULL /* This crashes sometimes!*/) {
603         TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
604         idxData = idxData == (void *)-1 ? NULL : idxData;
605 #if 1
606 #if 0
607         glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
608         glEnableClientState(GL_INDEX_ARRAY);
609 #endif
610         glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
611                      (const char *)idxData+(idxSize * startIdx));
612 #else /* using drawRangeElements may be faster */
613
614         glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
615                       idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
616                       (const char *)idxData+(idxSize * startIdx));
617 #endif
618         checkGLcall("glDrawRangeElements");
619
620     } else {
621
622         /* Note first is now zero as we shuffled along earlier */
623         TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
624         glDrawArrays(glPrimitiveType, startVertex, numberOfVertices);
625         checkGLcall("glDrawArrays");
626
627     }
628
629     return;
630 }
631
632 /*
633  * Actually draw using the supplied information.
634  * Slower GL version which extracts info about each vertex in turn
635  */
636
637 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
638                      UINT NumVertexes, GLenum glPrimType,
639                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
640
641     unsigned int               textureNo    = 0;
642     unsigned int               texture_idx  = 0;
643     const short               *pIdxBufS     = NULL;
644     const long                *pIdxBufL     = NULL;
645     LONG                       vx_index;
646     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
647     float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */
648     float rhw = 0.0f;                      /* rhw                        */
649     float ptSize = 0.0f;                   /* Point size                 */
650     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
651     DWORD specularColor = 0;               /* Specular Color             */
652     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
653     LONG                       SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex;
654
655     TRACE("Using slow vertex array code\n");
656
657     /* Variable Initialization */
658     if (idxData != NULL) {
659         if (idxSize == 2) pIdxBufS = (const short *) idxData;
660         else pIdxBufL = (const long *) idxData;
661     }
662
663     /* Start drawing in GL */
664     VTRACE(("glBegin(%x)\n", glPrimType));
665     glBegin(glPrimType);
666
667     /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
668      * Guess it's not necessary(we crash then anyway) and would only eat CPU time
669      */
670
671     /* For each primitive */
672     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
673
674         /* Initialize diffuse color */
675         diffuseColor = 0xFFFFFFFF;
676
677         /* For indexed data, we need to go a few more strides in */
678         if (idxData != NULL) {
679
680             /* Indexed so work out the number of strides to skip */
681             if (idxSize == 2) {
682                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
683                 SkipnStrides = pIdxBufS[startIdx + vx_index] + This->stateBlock->loadBaseVertexIndex;
684             } else {
685                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
686                 SkipnStrides = pIdxBufL[startIdx + vx_index] + This->stateBlock->loadBaseVertexIndex;
687             }
688         }
689
690         /* Position Information ------------------ */
691         if (sd->u.s.position.lpData != NULL) {
692
693             float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
694             x = ptrToCoords[0];
695             y = ptrToCoords[1];
696             z = ptrToCoords[2];
697             rhw = 1.0;
698             VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
699
700             /* RHW follows, only if transformed, ie 4 floats were provided */
701             if (sd->u.s.position_transformed) {
702                 rhw = ptrToCoords[3];
703                 VTRACE(("rhw=%f\n", rhw));
704             }
705         }
706
707         /* Blending data -------------------------- */
708         if (sd->u.s.blendWeights.lpData != NULL) {
709             /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
710             FIXME("Blending not supported yet\n");
711
712             if (sd->u.s.blendMatrixIndices.lpData != NULL) {
713                 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
714             }
715         }
716
717         /* Vertex Normal Data (untransformed only)- */
718         if (sd->u.s.normal.lpData != NULL) {
719
720             float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
721             nx = ptrToCoords[0];
722             ny = ptrToCoords[1];
723             nz = ptrToCoords[2];
724             VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
725         }
726
727         /* Point Size ----------------------------- */
728         if (sd->u.s.pSize.lpData != NULL) {
729
730             float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
731             ptSize = ptrToCoords[0];
732             VTRACE(("ptSize=%f\n", ptSize));
733             FIXME("No support for ptSize yet\n");
734         }
735
736         /* Diffuse -------------------------------- */
737         if (sd->u.s.diffuse.lpData != NULL) {
738
739             DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
740             diffuseColor = ptrToCoords[0];
741             VTRACE(("diffuseColor=%lx\n", diffuseColor));
742         }
743
744         /* Specular  -------------------------------- */
745         if (sd->u.s.specular.lpData != NULL) {
746
747             DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
748             specularColor = ptrToCoords[0];
749             VTRACE(("specularColor=%lx\n", specularColor));
750         }
751
752         /* Texture coords --------------------------- */
753         for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
754
755             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
756                 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
757                 continue ;
758             }
759
760             /* Query tex coords */
761             if (This->stateBlock->textures[textureNo] != NULL) {
762
763                 int    coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
764                 float *ptrToCoords = NULL;
765                 float  s = 0.0, t = 0.0, r = 0.0, q = 0.0;
766
767                 if (coordIdx > 7) {
768                     VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
769                     ++texture_idx;
770                     continue;
771                 } else if (coordIdx < 0) {
772                     FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
773                     ++texture_idx;
774                     continue;
775                 }
776
777                 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
778                 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
779                     TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
780                     ++texture_idx;
781                     continue;
782                 } else {
783
784                     int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
785
786                     /* The coords to supply depend completely on the fvf / vertex shader */
787                     switch (coordsToUse) {
788                     case 4: q = ptrToCoords[3]; /* drop through */
789                     case 3: r = ptrToCoords[2]; /* drop through */
790                     case 2: t = ptrToCoords[1]; /* drop through */
791                     case 1: s = ptrToCoords[0];
792                     }
793
794                     /* Projected is more 'fun' - Move the last coord to the 'q'
795                           parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
796                     if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
797                         (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
798
799                         if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
800                             switch (coordsToUse) {
801                             case 0:  /* Drop Through */
802                             case 1:
803                                 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
804                                 break;
805                             case 2:
806                                 q = t;
807                                 t = 0.0;
808                                 coordsToUse = 4;
809                                 break;
810                             case 3:
811                                 q = r;
812                                 r = 0.0;
813                                 coordsToUse = 4;
814                                 break;
815                             case 4:  /* Nop here */
816                                 break;
817                             default:
818                                 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
819                                       This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
820                             }
821                         }
822                     }
823
824                     switch (coordsToUse) {   /* Supply the provided texture coords */
825                     case WINED3DTTFF_COUNT1:
826                         VTRACE(("tex:%d, s=%f\n", textureNo, s));
827                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
828                             GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
829                         } else {
830                             glTexCoord1f(s);
831                         }
832                         break;
833                     case WINED3DTTFF_COUNT2:
834                         VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
835                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
836                             GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
837                         } else {
838                             glTexCoord2f(s, t);
839                         }
840                         break;
841                     case WINED3DTTFF_COUNT3:
842                         VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
843                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
844                             GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
845                         } else {
846                             glTexCoord3f(s, t, r);
847                         }
848                         break;
849                     case WINED3DTTFF_COUNT4:
850                         VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
851                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
852                             GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
853                         } else {
854                             glTexCoord4f(s, t, r, q);
855                         }
856                         break;
857                     default:
858                         FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
859                     }
860                 }
861             }
862             if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/TRUE) ++texture_idx;
863         } /* End of textures */
864
865         /* Diffuse -------------------------------- */
866         if (sd->u.s.diffuse.lpData != NULL) {
867           glColor4ub(D3DCOLOR_B_R(diffuseColor),
868                      D3DCOLOR_B_G(diffuseColor),
869                      D3DCOLOR_B_B(diffuseColor),
870                      D3DCOLOR_B_A(diffuseColor));
871             VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n", 
872                     D3DCOLOR_B_R(diffuseColor),
873                     D3DCOLOR_B_G(diffuseColor),
874                     D3DCOLOR_B_B(diffuseColor),
875                     D3DCOLOR_B_A(diffuseColor)));
876         } else {
877             if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
878         }
879
880         /* Specular ------------------------------- */
881         if (sd->u.s.specular.lpData != NULL) {
882             /* special case where the fog density is stored in the diffuse alpha channel */
883             if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
884               (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
885               This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
886                 if(GL_SUPPORT(EXT_FOG_COORD)) {
887                     GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
888                 } else {
889                     static BOOL warned = FALSE;
890                     if(!warned) {
891                         /* TODO: Use the fog table code from old ddraw */
892                         FIXME("Implement fog for transformed vertices in software\n");
893                         warned = TRUE;
894                     }
895                 }
896             }
897
898             VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", 
899                     D3DCOLOR_B_R(specularColor), 
900                     D3DCOLOR_B_G(specularColor), 
901                     D3DCOLOR_B_B(specularColor)));
902             if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
903                 GL_EXTCALL(glSecondaryColor3ubEXT)(
904                            D3DCOLOR_B_R(specularColor),
905                            D3DCOLOR_B_G(specularColor),
906                            D3DCOLOR_B_B(specularColor));
907             } else {
908                 /* Do not worry if specular colour missing and disable request */
909                 VTRACE(("Specular color extensions not supplied\n"));
910             }
911         } else {
912             if (vx_index == 0) {
913                 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
914                     GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
915                 } else {
916                     /* Do not worry if specular colour missing and disable request */
917                     VTRACE(("Specular color extensions not supplied\n"));
918                 }
919             }
920         }
921
922         /* Normal -------------------------------- */
923         if (sd->u.s.normal.lpData != NULL) {
924             VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
925             glNormal3f(nx, ny, nz);
926         } else {
927             if (vx_index == 0) glNormal3f(0, 0, 1);
928         }
929
930         /* Position -------------------------------- */
931         if (sd->u.s.position.lpData != NULL) {
932             if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
933                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
934                 glVertex3f(x, y, z);
935             } else {
936                 GLfloat w = 1.0 / rhw;
937                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
938                 glVertex4f(x*w, y*w, z*w, w);
939             }
940         }
941
942         /* For non indexed mode, step onto next parts */
943         if (idxData == NULL) {
944             ++SkipnStrides;
945         }
946     }
947
948     glEnd();
949     checkGLcall("glEnd and previous calls");
950 }
951
952 #if 0 /* TODO: Software/Hardware vertex blending support */
953 /*
954  * Draw with emulated vertex shaders
955  * Note: strided data is uninitialized, as we need to pass the vertex
956  *     shader directly as ordering irs yet
957  */
958 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
959                      int PrimitiveType, ULONG NumPrimitives,
960                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
961
962     unsigned int               textureNo    = 0;
963     GLenum                     glPrimType   = GL_POINTS;
964     int                        NumVertexes  = NumPrimitives;
965     const short               *pIdxBufS     = NULL;
966     const long                *pIdxBufL     = NULL;
967     LONG                       SkipnStrides = 0;
968     LONG                       vx_index;
969     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
970     float rhw = 0.0f;                      /* rhw                        */
971     float ptSize = 0.0f;                   /* Point size                 */
972     D3DVECTOR_4 texcoords[8];              /* Texture Coords             */
973     int   numcoords[8];                    /* Number of coords           */
974     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
975
976     IDirect3DVertexShaderImpl* vertexShader = NULL;
977
978     TRACE("Using slow software vertex shader code\n");
979
980     /* Variable Initialization */
981     if (idxData != NULL) {
982         if (idxSize == 2) pIdxBufS = (const short *) idxData;
983         else pIdxBufL = (const long *) idxData;
984     }
985
986     /* Ok, Work out which primitive is requested and how many vertexes that will be */
987     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
988
989     /* Retrieve the VS information */
990     vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
991
992     /* Start drawing in GL */
993     VTRACE(("glBegin(%x)\n", glPrimType));
994     glBegin(glPrimType);
995
996     /* For each primitive */
997     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
998
999         /* For indexed data, we need to go a few more strides in */
1000         if (idxData != NULL) {
1001
1002             /* Indexed so work out the number of strides to skip */
1003             if (idxSize == 2) {
1004                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1005                 SkipnStrides = pIdxBufS[startIdx+vx_index];
1006             } else {
1007                 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1008                 SkipnStrides = pIdxBufL[startIdx+vx_index];
1009             }
1010         }
1011
1012         /* Fill the vertex shader input */
1013         IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1014
1015         /* Initialize the output fields to the same defaults as it would normally have */
1016         memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1017         vertexShader->output.oD[0].x = 1.0;
1018         vertexShader->output.oD[0].y = 1.0;
1019         vertexShader->output.oD[0].z = 1.0;
1020         vertexShader->output.oD[0].w = 1.0;
1021
1022         /* Now execute the vertex shader */
1023         IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1024
1025         /*
1026         TRACE_VECTOR(vertexShader->output.oPos);
1027         TRACE_VECTOR(vertexShader->output.oD[0]);
1028         TRACE_VECTOR(vertexShader->output.oD[1]);
1029         TRACE_VECTOR(vertexShader->output.oT[0]);
1030         TRACE_VECTOR(vertexShader->output.oT[1]);
1031         TRACE_VECTOR(vertexShader->input.V[0]);
1032         TRACE_VECTOR(vertexShader->data->C[0]);
1033         TRACE_VECTOR(vertexShader->data->C[1]);
1034         TRACE_VECTOR(vertexShader->data->C[2]);
1035         TRACE_VECTOR(vertexShader->data->C[3]);
1036         TRACE_VECTOR(vertexShader->data->C[4]);
1037         TRACE_VECTOR(vertexShader->data->C[5]);
1038         TRACE_VECTOR(vertexShader->data->C[6]);
1039         TRACE_VECTOR(vertexShader->data->C[7]);
1040         */
1041
1042         /* Extract out the output */
1043         /* FIXME: Fog coords? */
1044         x = vertexShader->output.oPos.x;
1045         y = vertexShader->output.oPos.y;
1046         z = vertexShader->output.oPos.z;
1047         rhw = vertexShader->output.oPos.w;
1048         ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1049
1050         /** Update textures coords using vertexShader->output.oT[0->7] */
1051         memset(texcoords, 0x00, sizeof(texcoords));
1052         memset(numcoords, 0x00, sizeof(numcoords));
1053         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1054             if (This->stateBlock->textures[textureNo] != NULL) {
1055                texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1056                texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1057                texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1058                texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1059                if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1060                    numcoords[textureNo]    = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1061                } else {
1062                    switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1063                    case WINED3DRTYPE_TEXTURE:       numcoords[textureNo] = 2; break;
1064                    case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1065                    default:                         numcoords[textureNo] = 4;
1066                    }
1067                }
1068             } else {
1069                 numcoords[textureNo] = 0;
1070             }
1071         }
1072
1073         /* Draw using this information */
1074         draw_vertex(iface,
1075                     TRUE, x, y, z, rhw,
1076                     TRUE, 0.0f, 0.0f, 1.0f,
1077                     TRUE, (float*) &vertexShader->output.oD[0],
1078                     TRUE, (float*) &vertexShader->output.oD[1],
1079                     FALSE, ptSize,         /* FIXME: Change back when supported */
1080                     texcoords, numcoords);
1081
1082         /* For non indexed mode, step onto next parts */
1083         if (idxData == NULL) {
1084            ++SkipnStrides;
1085         }
1086
1087     } /* for each vertex */
1088
1089     glEnd();
1090     checkGLcall("glEnd and previous calls");
1091 }
1092
1093 #endif
1094
1095 inline static void drawPrimitiveDrawStrided(
1096     IWineD3DDevice *iface,
1097     BOOL useVertexShaderFunction,
1098     BOOL usePixelShaderFunction,
1099     WineDirect3DVertexStridedData *dataLocations,
1100     ULONG baseVIndex,
1101     UINT numberOfvertices,
1102     UINT numberOfIndicies,
1103     GLenum glPrimType,
1104     const void *idxData,
1105     short idxSize,
1106     int minIndex,
1107     long StartIdx) {
1108
1109     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;    
1110
1111     /* Draw vertex-by-vertex */
1112     if (This->useDrawStridedSlow)
1113         drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1114     else
1115         drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1116 }
1117
1118 static void check_fbo_status(IWineD3DDevice *iface) {
1119     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1120
1121     GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
1122     switch(status) {
1123         case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
1124         default: TRACE("FBO status %#x.\n", status); break;
1125     }
1126 }
1127
1128 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
1129     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1130     GLint old_binding = 0;
1131
1132     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
1133
1134     glDisable(GL_CULL_FACE);
1135     glDisable(GL_BLEND);
1136     glDisable(GL_ALPHA_TEST);
1137     glDisable(GL_STENCIL_TEST);
1138     glEnable(GL_DEPTH_TEST);
1139     glDepthFunc(GL_ALWAYS);
1140
1141     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1142     glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1143     glBindTexture(GL_TEXTURE_2D, texture);
1144     glEnable(GL_TEXTURE_2D);
1145
1146     This->shader_backend->shader_select_depth_blt(iface);
1147
1148     glBegin(GL_TRIANGLE_STRIP);
1149     glVertex2f(-1.0f, -1.0f);
1150     glVertex2f(1.0f, -1.0f);
1151     glVertex2f(-1.0f, 1.0f);
1152     glVertex2f(1.0f, 1.0f);
1153     glEnd();
1154
1155     glBindTexture(GL_TEXTURE_2D, old_binding);
1156
1157     glPopAttrib();
1158
1159     /* Reselect the old shaders. There doesn't seem to be any glPushAttrib bit for arb shaders,
1160      * and this seems easier and more efficient than providing the shader backend with a private
1161      * storage to read and restore the old shader settings
1162      */
1163     This->shader_backend->shader_select(iface,
1164         This->stateBlock->pixelShader && ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function,
1165         This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function);
1166 }
1167
1168 static void depth_copy(IWineD3DDevice *iface) {
1169     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1170     IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
1171
1172     /* Only copy the depth buffer if there is one. */
1173     if (!depth_stencil) return;
1174
1175     /* TODO: Make this work for modes other than FBO */
1176     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
1177
1178     if (This->render_offscreen) {
1179         static GLuint tmp_texture = 0;
1180         GLint old_binding = 0;
1181
1182         TRACE("Copying onscreen depth buffer to offscreen surface\n");
1183
1184         if (!tmp_texture) {
1185             glGenTextures(1, &tmp_texture);
1186         }
1187
1188         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
1189          * directly on the FBO texture. That's because we need to flip. */
1190         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1191         glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1192         glBindTexture(GL_TEXTURE_2D, tmp_texture);
1193         glCopyTexImage2D(depth_stencil->glDescription.target,
1194                 depth_stencil->glDescription.level,
1195                 depth_stencil->glDescription.glFormatInternal,
1196                 0,
1197                 0,
1198                 depth_stencil->currentDesc.Width,
1199                 depth_stencil->currentDesc.Height,
1200                 0);
1201         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1202         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1203         glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
1204         glBindTexture(GL_TEXTURE_2D, old_binding);
1205
1206         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
1207         checkGLcall("glBindFramebuffer()");
1208         depth_blt(iface, tmp_texture);
1209         checkGLcall("depth_blt");
1210     } else {
1211         TRACE("Copying offscreen surface to onscreen depth buffer\n");
1212
1213         GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1214         checkGLcall("glBindFramebuffer()");
1215         depth_blt(iface, depth_stencil->glDescription.textureName);
1216         checkGLcall("depth_blt");
1217     }
1218 }
1219
1220 /* Routine common to the draw primitive and draw indexed primitive routines */
1221 void drawPrimitive(IWineD3DDevice *iface,
1222                    int PrimitiveType,
1223                    long NumPrimitives,
1224                    /* for Indexed: */
1225                    long  StartVertexIndex,
1226                    UINT  numberOfVertices,
1227                    long  StartIdx,
1228                    short idxSize,
1229                    const void *idxData,
1230                    int   minIndex) {
1231
1232     IWineD3DDeviceImpl           *This = (IWineD3DDeviceImpl *)iface;
1233     BOOL                          useVertexShaderFunction = FALSE;
1234     BOOL                          usePixelShaderFunction = FALSE;
1235     IWineD3DSwapChainImpl         *swapchain;
1236     int                           i;
1237     DWORD                         dirtyState, idx;
1238     BYTE                          shift;
1239
1240     /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
1241      * here simply check whether a shader was set, or the user disabled shaders */
1242     if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
1243         ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL) 
1244         useVertexShaderFunction = TRUE;
1245
1246     if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
1247         ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) 
1248         usePixelShaderFunction = TRUE;
1249
1250     /* Invalidate the back buffer memory so LockRect will read it the next time */
1251     for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
1252         IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
1253         if(swapchain) {
1254             if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
1255             IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1256         }
1257     }
1258
1259     /* Ok, we will be updating the screen from here onwards so grab the lock */
1260     ENTER_GL();
1261
1262     /* Apply dirty states */
1263     for(i=0; i < This->numDirtyEntries; i++) {
1264         dirtyState = This->dirtyArray[i];
1265         idx = dirtyState >> 5;
1266         shift = dirtyState & 0x1f;
1267         This->isStateDirty[idx] &= ~(1 << shift);
1268         StateTable[dirtyState].apply(dirtyState, This->stateBlock);
1269     }
1270     This->numDirtyEntries = 0; /* This makes the whole list clean */
1271
1272     if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1273         check_fbo_status(iface);
1274     }
1275
1276     if (This->depth_copy_state == WINED3D_DCS_COPY) {
1277         depth_copy(iface);
1278     }
1279     This->depth_copy_state = WINED3D_DCS_INITIAL;
1280
1281     /* Now initialize the materials state */
1282     init_materials(iface, (This->strided_streams.u.s.diffuse.lpData != NULL || This->strided_streams.u.s.diffuse.VBO != 0));
1283
1284     {
1285         GLenum glPrimType;
1286         /* Ok, Work out which primitive is requested and how many vertexes that
1287            will be                                                              */
1288         UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1289         if (numberOfVertices == 0 )
1290             numberOfVertices = calculatedNumberOfindices;
1291
1292         drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
1293             &This->strided_streams, StartVertexIndex, numberOfVertices, calculatedNumberOfindices, glPrimType,
1294             idxData, idxSize, minIndex, StartIdx);
1295     }
1296
1297     /* Finshed updating the screen, restore lock */
1298     LEAVE_GL();
1299     TRACE("Done all gl drawing\n");
1300
1301     /* Diagnostics */
1302 #ifdef SHOW_FRAME_MAKEUP
1303     {
1304         static long int primCounter = 0;
1305         /* NOTE: set primCounter to the value reported by drawprim 
1306            before you want to to write frame makeup to /tmp */
1307         if (primCounter >= 0) {
1308             WINED3DLOCKED_RECT r;
1309             char buffer[80];
1310             IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
1311             sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
1312             TRACE("Saving screenshot %s\n", buffer);
1313             IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
1314             IWineD3DSurface_UnlockRect(This->renderTarget);
1315
1316 #ifdef SHOW_TEXTURE_MAKEUP
1317            {
1318             IWineD3DSurface *pSur;
1319             int textureNo;
1320             for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1321                 if (This->stateBlock->textures[textureNo] != NULL) {
1322                     sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
1323                     TRACE("Saving texture %s\n", buffer);
1324                     if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
1325                             IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
1326                             IWineD3DSurface_SaveSnapshot(pSur, buffer);
1327                             IWineD3DSurface_Release(pSur);
1328                     } else  {
1329                         FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
1330                     }
1331                 }
1332             }
1333            }
1334 #endif
1335         }
1336         TRACE("drawprim #%d\n", primCounter);
1337         ++primCounter;
1338     }
1339 #endif
1340 }