DXTn stride is to the next block, which is the equivalent to 4 rows
[wine] / dlls / d3d8 / drawprim.c
1 /*
2  * D3D8 utils
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  *                     Raphael Junqueira
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <math.h>
25 #include <stdarg.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "wingdi.h"
33 #include "wine/debug.h"
34
35 #include "d3d8_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
39
40 extern IDirect3DVertexShaderImpl*            VertexShaders[64];
41 extern IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64];
42 extern IDirect3DPixelShaderImpl*             PixelShaders[64];
43
44 /* Useful holding place for 4 floats */
45 typedef struct _D3DVECTOR_4 {
46     float x;
47     float y;
48     float z;
49     float w;
50 } D3DVECTOR_4;
51
52 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
53
54 /* Returns bits for what is expected from the fixed function pipeline, and whether 
55    a vertex shader will be in use. Note the fvf bits returned may be split over
56    multiple streams only if the vertex shader was created, otherwise it all relates
57    to stream 0                                                                      */
58 BOOL initializeFVF(LPDIRECT3DDEVICE8 iface, 
59                    DWORD *FVFbits,                 /* What to expect in the FVF across all streams */
60                    BOOL *useVertexShaderFunction)  /* Should we use the vertex shader              */
61 {
62
63     ICOM_THIS(IDirect3DDevice8Impl,iface);
64
65     /* The first thing to work out is if we are using the fixed function pipeline 
66        which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this
67        is the FVF, or with a shader which was created with no function - in which
68        case there is an FVF per declared stream. If this occurs, we also maintain
69        an 'OR' of all the FVF's together so we know what to expect across all the     
70        streams                                                                        */
71
72     if (This->UpdateStateBlock->VertexShader <= VS_HIGHESTFIXEDFXF) {
73
74         /* Use this as the FVF */
75         *FVFbits = This->UpdateStateBlock->VertexShader;
76         *useVertexShaderFunction = FALSE;
77         TRACE("FVF explicitally defined, using fixed function pipeline with FVF=%lx\n", *FVFbits);
78
79     } else {
80
81         /* Use created shader */
82         IDirect3DVertexShaderImpl* vertex_shader = NULL;
83         vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
84
85         if (vertex_shader == NULL) {
86
87             /* Hmm - User pulled figure out of the air? Unlikely, probably a bug */
88             ERR("trying to use unitialised vertex shader: %lu\n", This->UpdateStateBlock->VertexShader);
89             return TRUE;
90
91         } else {
92
93             *FVFbits = This->UpdateStateBlock->vertexShaderDecl->allFVF;
94
95             if (vertex_shader->function == NULL) {
96                 /* No function, so many streams supplied plus FVF definition pre stream */
97                 *useVertexShaderFunction = FALSE;
98                 TRACE("vertex shader (%lx) declared without program, using fixed function pipeline with FVF=%lx\n", 
99                             This->StateBlock->VertexShader, *FVFbits);
100             } else {
101                 /* Vertex shader needs calling */
102                 *useVertexShaderFunction = TRUE;
103                 TRACE("vertex shader will be used (unusued FVF=%lx)\n", *FVFbits);
104             }
105         }
106     }
107     return FALSE;
108 }
109
110 /* Issues the glBegin call for gl given the primitive type and count */
111 DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
112                     DWORD            NumPrimitives,
113                     GLenum          *primType)
114 {
115     DWORD   NumVertexes = NumPrimitives;
116
117     switch (PrimitiveType) {
118     case D3DPT_POINTLIST:
119         TRACE("POINTS\n");
120         *primType = GL_POINTS;
121         NumVertexes = NumPrimitives;
122         break;
123
124     case D3DPT_LINELIST:
125         TRACE("LINES\n");
126         *primType = GL_LINES;
127         NumVertexes = NumPrimitives * 2;
128         break;
129
130     case D3DPT_LINESTRIP:
131         TRACE("LINE_STRIP\n");
132         *primType = GL_LINE_STRIP;
133         NumVertexes = NumPrimitives + 1;
134         break;
135
136     case D3DPT_TRIANGLELIST:
137         TRACE("TRIANGLES\n");
138         *primType = GL_TRIANGLES;
139         NumVertexes = NumPrimitives * 3;
140         break;
141
142     case D3DPT_TRIANGLESTRIP:
143         TRACE("TRIANGLE_STRIP\n");
144         *primType = GL_TRIANGLE_STRIP;
145         NumVertexes = NumPrimitives + 2;
146         break;
147
148     case D3DPT_TRIANGLEFAN:
149         TRACE("TRIANGLE_FAN\n");
150         *primType = GL_TRIANGLE_FAN;
151         NumVertexes = NumPrimitives + 2;
152         break;
153
154     default:
155         FIXME("Unhandled primitive\n");
156         *primType    = GL_POINTS;
157         break;
158     }  
159     return NumVertexes;
160 }
161
162 /* Ensure the appropriate material states are set up - only change
163    state if really required                                        */
164 void init_materials(LPDIRECT3DDEVICE8 iface, BOOL isDiffuseSupplied) {
165
166     BOOL requires_material_reset = FALSE;
167     ICOM_THIS(IDirect3DDevice8Impl,iface);
168
169     if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == TRUE) {
170         /* If we have not set up the material color tracking, do it now as required */
171         glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
172         checkGLcall("glDisable GL_COLOR_MATERIAL");
173         TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
174         glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
175         checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
176         glEnable(GL_COLOR_MATERIAL); 
177         checkGLcall("glEnable GL_COLOR_MATERIAL");
178         This->tracking_color = IS_TRACKING;
179         requires_material_reset = TRUE; /* Restore material settings as will be used */
180
181     } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
182                (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
183         /* If we are tracking the current color but one isnt supplied, dont! */
184         glDisable(GL_COLOR_MATERIAL);
185         checkGLcall("glDisable GL_COLOR_MATERIAL");
186         This->tracking_color = NEEDS_TRACKING;
187         requires_material_reset = TRUE; /* Restore material settings as will be used */
188
189     } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied == TRUE) {
190         /* No need to reset material colors since no change to gl_color_material */
191         requires_material_reset = FALSE;
192
193     } else if (This->tracking_color == NEEDS_DISABLE) {
194         glDisable(GL_COLOR_MATERIAL);
195         checkGLcall("glDisable GL_COLOR_MATERIAL");
196         This->tracking_color = DISABLED_TRACKING;
197         requires_material_reset = TRUE; /* Restore material settings as will be used */
198     }
199
200     /* Reset the material colors which may have been tracking the color*/
201     if (requires_material_reset == TRUE) {
202         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->StateBlock->material.Ambient);
203         checkGLcall("glMaterialfv");
204         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->StateBlock->material.Diffuse);
205         checkGLcall("glMaterialfv");
206         if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) {
207            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->StateBlock->material.Specular);
208            checkGLcall("glMaterialfv");
209         } else {
210            float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
211            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
212            checkGLcall("glMaterialfv");
213         }
214         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->StateBlock->material.Emissive);
215         checkGLcall("glMaterialfv");
216     }
217
218 }
219
220 /* Setup views - Transformed & lit if RHW, else untransformed.
221        Only unlit if Normals are supplied                       
222     Returns: Whether to restore lighting afterwards           */
223 BOOL primitiveInitState(LPDIRECT3DDEVICE8 iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) {
224
225     BOOL isLightingOn = FALSE;
226     ICOM_THIS(IDirect3DDevice8Impl,iface);
227
228     /* If no normals, DISABLE lighting otherwise, dont touch lighing as it is 
229        set by the appropriate render state. Note Vertex Shader output is already lit */
230     if (vtx_lit || useVS) {
231         isLightingOn = glIsEnabled(GL_LIGHTING);
232         glDisable(GL_LIGHTING);
233         checkGLcall("glDisable(GL_LIGHTING);");
234         TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
235     }
236
237     if (!useVS && vtx_transformed) {
238
239         /* If the last draw was transformed as well, no need to reapply all the matrixes */
240         if (!This->last_was_rhw) {
241
242             double X, Y, height, width, minZ, maxZ;
243             This->last_was_rhw = TRUE;
244
245             /* Transformed already into viewport coordinates, so we do not need transform
246                matrices. Reset all matrices to identity and leave the default matrix in world 
247                mode.                                                                         */
248             glMatrixMode(GL_MODELVIEW);
249             checkGLcall("glMatrixMode");
250             glLoadIdentity();
251             checkGLcall("glLoadIdentity");
252
253             glMatrixMode(GL_PROJECTION);
254             checkGLcall("glMatrixMode");
255             glLoadIdentity();
256             checkGLcall("glLoadIdentity");
257
258             /* Set up the viewport to be full viewport */
259             X      = This->StateBlock->viewport.X;
260             Y      = This->StateBlock->viewport.Y;
261             height = This->StateBlock->viewport.Height;
262             width  = This->StateBlock->viewport.Width;
263             minZ   = This->StateBlock->viewport.MinZ;
264             maxZ   = This->StateBlock->viewport.MaxZ;
265             TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
266             glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
267             checkGLcall("glOrtho");
268
269             /* Window Coord 0 is the middle of the first pixel, so translate by half
270                a pixel (See comment above glTranslate below)                         */
271             glTranslatef(0.5, 0.5, 0);
272             checkGLcall("glTranslatef(0.5, 0.5, 0)");
273         }
274
275     } else {
276
277         /* Untransformed, so relies on the view and projection matrices */
278
279         if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
280             /* Only reapply when have to */
281             This->modelview_valid = TRUE;
282             glMatrixMode(GL_MODELVIEW);
283             checkGLcall("glMatrixMode");
284
285             /* In the general case, the view matrix is the identity matrix */
286             if (This->view_ident) {
287                 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
288                 checkGLcall("glLoadMatrixf");
289             } else {
290                 glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
291                 checkGLcall("glLoadMatrixf");
292                 glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
293                 checkGLcall("glMultMatrixf");
294             }
295         }
296
297         if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
298             /* Only reapply when have to */
299             This->proj_valid = TRUE;
300             glMatrixMode(GL_PROJECTION);
301             checkGLcall("glMatrixMode");
302
303             /* The rule is that the window coordinate 0 does not correspond to the
304                beginning of the first pixel, but the center of the first pixel.
305                As a consequence if you want to correctly draw one line exactly from
306                the left to the right end of the viewport (with all matrices set to
307                be identity), the x coords of both ends of the line would be not
308                -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
309                instead.                                                               */
310             glLoadIdentity();
311             glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
312             checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
313             glMultMatrixf((float *) &This->StateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
314             checkGLcall("glLoadMatrixf");
315         }
316
317         /* Vertex Shader output is already transformed, so set up identity matrices */
318         /* FIXME: Actually, only true for software emulated ones, so when h/w ones  
319              come along this needs to take into account whether s/w ones were 
320              requested or not                                                       */
321         if (useVS) {
322             glMatrixMode(GL_MODELVIEW);
323             checkGLcall("glMatrixMode");
324             glLoadIdentity();
325             glMatrixMode(GL_PROJECTION);
326             checkGLcall("glMatrixMode");
327             glLoadIdentity();
328             /* Window Coord 0 is the middle of the first pixel, so translate by half
329                a pixel (See comment above glTranslate above)                         */
330             glTranslatef(1.0/This->StateBlock->viewport.Width, -1.0/This->StateBlock->viewport.Height, 0);
331             checkGLcall("glTranslatef (1.0/width, -1.0/height, 0)");
332             This->modelview_valid = FALSE;
333             This->proj_valid = FALSE;
334         } 
335         This->last_was_rhw = FALSE;
336     }
337     return isLightingOn;
338 }
339
340 void primitiveConvertToStridedData(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
341
342     short         LoopThroughTo = 0;
343     short         nStream;
344     BOOL          canDoViaGLPointers = TRUE;
345     int           numBlends;
346     int           numTextures;
347     int           textureNo;
348     int           coordIdxInfo = 0x00;    /* Information on number of coords supplied */
349     int           numCoords[8];           /* Holding place for D3DFVF_TEXTUREFORMATx  */
350
351     ICOM_THIS(IDirect3DDevice8Impl,iface);
352
353     /* OK, Now to setup the data locations 
354        For the non-created vertex shaders, the VertexShader var holds the real 
355           FVF and only stream 0 matters
356        For the created vertex shaders, there is an FVF per stream              */
357     if (This->UpdateStateBlock->VertexShader > VS_HIGHESTFIXEDFXF) {
358         LoopThroughTo = MAX_STREAMS;
359     } else {
360         LoopThroughTo = 1;
361     }
362
363     /* Work through stream by stream */
364     for (nStream=0; nStream<LoopThroughTo; nStream++) {
365         DWORD  stride  = This->StateBlock->stream_stride[nStream];
366         BYTE  *data    = NULL;
367         DWORD  thisFVF = 0;
368
369         /* Skip empty streams */
370         if (This->StateBlock->stream_source[nStream] == NULL) continue;
371
372         /* Retrieve appropriate FVF */
373         if (LoopThroughTo == 1) { /* VertexShader is FVF */
374             thisFVF = This->UpdateStateBlock->VertexShader;
375             /* Handle memory passed directly as well as vertex buffers */
376             if (This->StateBlock->streamIsUP == TRUE) {
377                 data    = (BYTE *)This->StateBlock->stream_source[nStream];
378             } else {
379                 data    = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
380             }
381         } else {
382             thisFVF = This->StateBlock->vertexShaderDecl->fvf[nStream];
383             data    = ((IDirect3DVertexBuffer8Impl *)This->StateBlock->stream_source[nStream])->allocatedMemory;
384         }
385         VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
386         if (thisFVF == 0) continue;
387
388         /* Now convert the stream into pointers */
389
390         /* Shuffle to the beginning of the vertexes to render and index from there */
391         data = data + (BaseVertexIndex * stride);
392
393         /* Either 3 or 4 floats depending on the FVF */
394         /* FIXME: Can blending data be in a different stream to the position data? 
395               and if so using the fixed pipeline how do we handle it               */
396         if (thisFVF & D3DFVF_POSITION_MASK) {
397             strided->u.s.position.lpData    = data;
398             strided->u.s.position.dwType    = D3DVSDT_FLOAT3;
399             strided->u.s.position.dwStride  = stride;
400             data += 3 * sizeof(float);
401             if (thisFVF & D3DFVF_XYZRHW) {
402                 strided->u.s.position.dwType = D3DVSDT_FLOAT4;
403                 data += sizeof(float);
404             }
405         }
406
407         /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
408         /** do we have to Check This->UpdateStateBlock->renderstate[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
409         numBlends = ((thisFVF & D3DFVF_POSITION_MASK) >> 1) - 2 + 
410                     ((FALSE == (thisFVF & D3DFVF_LASTBETA_UBYTE4)) ? 0 : -1);    /* WARNING can be < 0 because -2 */
411         if (numBlends > 0) {
412             canDoViaGLPointers = FALSE; 
413             strided->u.s.blendWeights.lpData    = data;
414             strided->u.s.blendWeights.dwType    = D3DVSDT_FLOAT1 + (numBlends - 1);
415             strided->u.s.blendWeights.dwStride  = stride;
416             data += numBlends * sizeof(FLOAT);
417
418             if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
419                 strided->u.s.blendMatrixIndices.lpData = data;
420                 strided->u.s.blendMatrixIndices.dwType  = D3DVSDT_UBYTE4; 
421                 strided->u.s.blendMatrixIndices.dwStride= stride; 
422                 data += sizeof(DWORD);
423             }
424         }
425
426         /* Normal is always 3 floats */
427         if (thisFVF & D3DFVF_NORMAL) {
428             strided->u.s.normal.lpData    = data;
429             strided->u.s.normal.dwType    = D3DVSDT_FLOAT3;
430             strided->u.s.normal.dwStride  = stride;
431             data += 3 * sizeof(FLOAT);
432         }
433
434         /* Pointsize is a single float */
435         if (thisFVF & D3DFVF_PSIZE) {
436             strided->u.s.pSize.lpData    = data;
437             strided->u.s.pSize.dwType    = D3DVSDT_FLOAT1;
438             strided->u.s.pSize.dwStride  = stride;
439             data += sizeof(FLOAT);
440         }
441
442         /* Diffuse is 4 unsigned bytes */
443         if (thisFVF & D3DFVF_DIFFUSE) {
444             strided->u.s.diffuse.lpData    = data;
445             strided->u.s.diffuse.dwType    = D3DVSDT_SHORT4;
446             strided->u.s.diffuse.dwStride  = stride;
447             data += sizeof(DWORD);
448         }
449
450         /* Specular is 4 unsigned bytes */
451         if (thisFVF & D3DFVF_SPECULAR) {
452             strided->u.s.specular.lpData    = data;
453             strided->u.s.specular.dwType    = D3DVSDT_SHORT4;
454             strided->u.s.specular.dwStride  = stride;
455             data += sizeof(DWORD);
456         }
457
458         /* Texture coords */
459         numTextures   = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
460         coordIdxInfo  = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
461
462         /* numTextures indicates the number of texture coordinates supplied */
463         /* However, the first set may not be for stage 0 texture - it all   */
464         /*   depends on D3DTSS_TEXCOORDINDEX.                               */
465         /* The number of bytes for each coordinate set is based off         */
466         /*   D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits              */
467
468         /* So, for each supplied texture extract the coords */
469         for (textureNo = 0; textureNo < numTextures; ++textureNo) {
470
471             strided->u.s.texCoords[textureNo].lpData    = data;
472             strided->u.s.texCoords[textureNo].dwType    = D3DVSDT_FLOAT1;
473             strided->u.s.texCoords[textureNo].dwStride  = stride;
474             numCoords[textureNo] = coordIdxInfo & 0x03;
475
476             /* Always one set */
477             data += sizeof(float);
478             if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
479                 strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT2;
480                 data += sizeof(float);
481                 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
482                     strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT3;
483                     data += sizeof(float);
484                     if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
485                         strided->u.s.texCoords[textureNo].dwType = D3DVSDT_FLOAT4;
486                         data += sizeof(float);
487                     }
488                 }
489             }
490             coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
491         }
492     }
493 }
494
495 /* Draw a single vertex using this information */
496 void draw_vertex(LPDIRECT3DDEVICE8 iface,                              /* interface    */
497                  BOOL isXYZ,    float x, float y, float z, float rhw,  /* xyzn position*/
498                  BOOL isNormal, float nx, float ny, float nz,          /* normal       */
499                  BOOL isDiffuse, float *dRGBA,                         /* 1st   colors */
500                  BOOL isSpecular, float *sRGB,                         /* 2ndry colors */
501                  BOOL isPtSize, float ptSize,                       /* pointSize    */
502                  D3DVECTOR_4 *texcoords, int *numcoords)               /* texture info */
503 {
504     int textureNo;
505     float s, t, r, q;
506     ICOM_THIS(IDirect3DDevice8Impl,iface);
507
508     /* Diffuse -------------------------------- */
509     if (isDiffuse == TRUE) {
510         glColor4fv(dRGBA);
511         VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
512     }
513
514     /* Specular Colour ------------------------------------------*/
515     if (isSpecular == TRUE) {
516 #if defined(GL_EXT_secondary_color)
517         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
518           GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
519           VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
520         }
521 #endif
522     }
523
524     /* Normal -------------------------------- */
525     if (isNormal == TRUE) {
526         VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
527         glNormal3f(nx, ny, nz);
528     } 
529
530     /* Point Size ----------------------------------------------*/
531     if (isPtSize == TRUE) {
532
533         /* no such functionality in the fixed function GL pipeline */
534         FIXME("Cannot change ptSize here in openGl\n");
535     }
536
537     /* Texture coords --------------------------- */
538     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
539
540         if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
541             FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
542             continue ;
543         }
544
545         /* Query tex coords */
546         if (This->StateBlock->textures[textureNo] != NULL) {
547
548             int    coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
549             if (coordIdx > 7) {
550                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
551                 continue;
552             } else if (numcoords[coordIdx] == 0) {
553                 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
554                 continue;
555             } else {
556
557                 /* Initialize vars */
558                 s = 0.0f;
559                 t = 0.0f;
560                 r = 0.0f;
561                 q = 0.0f;
562
563                 switch (numcoords[coordIdx]) {
564                 case 4: q = texcoords[coordIdx].w; /* drop through */
565                 case 3: r = texcoords[coordIdx].z; /* drop through */
566                 case 2: t = texcoords[coordIdx].y; /* drop through */
567                 case 1: s = texcoords[coordIdx].x; 
568                 }
569
570                 switch (numcoords[coordIdx]) {   /* Supply the provided texture coords */
571                 case D3DTTFF_COUNT1:
572                     VTRACE(("tex:%d, s=%f\n", textureNo, s));
573                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
574 #if defined(GL_VERSION_1_3)
575                         glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
576 #else
577                         glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
578 #endif
579                     } else {
580                         glTexCoord1f(s);
581                     }
582                     break;
583                 case D3DTTFF_COUNT2:
584                     VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
585                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
586 #if defined(GL_VERSION_1_3)
587                         glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
588 #else
589                         glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
590 #endif
591                     } else {
592                         glTexCoord2f(s, t);
593                     }
594                     break;
595                 case D3DTTFF_COUNT3:
596                     VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
597                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
598 #if defined(GL_VERSION_1_3)
599                         glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
600 #else
601                         glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
602 #endif
603                     } else {
604                         glTexCoord3f(s, t, r);
605                     }
606                     break;
607                 case D3DTTFF_COUNT4:
608                     VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
609                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
610 #if defined(GL_VERSION_1_3)
611                         glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
612 #else
613                         glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
614 #endif
615                     } else {
616                         glTexCoord4f(s, t, r, q);
617                     }
618                     break;
619                 default:
620                     FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
621                 }
622             }
623         }
624     } /* End of textures */
625
626     /* Position -------------------------------- */
627     if (isXYZ == TRUE) {
628         if (1.0f == rhw || rhw < 0.00001f) {
629             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
630             glVertex3f(x, y, z);
631         } else {
632             /* Cannot optimize by dividing through by rhw as rhw is required
633                later for perspective in the GL pipeline for vertex shaders   */
634             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
635             glVertex4f(x,y,z,rhw);
636         }
637     }
638 }
639
640 /* 
641  * Actually draw using the supplied information.
642  * Faster GL version using pointers to data, harder to debug though 
643  * Note does not handle vertex shaders yet                             
644  */
645 void drawStridedFast(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, 
646                      int PrimitiveType, ULONG NumPrimitives,
647                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
648     int          textureNo   = 0;
649     GLenum       glPrimType  = GL_POINTS;
650     int          NumVertexes = NumPrimitives;
651     ICOM_THIS(IDirect3DDevice8Impl,iface);
652
653     TRACE("Using fast vertex array code\n");
654
655     /* Vertex Pointers -----------------------------------------*/
656     if (sd->u.s.position.lpData != NULL) {
657
658         /* Note dwType == float3 or float4 == 2 or 3 */
659         VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n", 
660                 sd->u.s.position.dwStride, 
661                 sd->u.s.position.dwType + 1, 
662                 sd->u.s.position.lpData));
663         glVertexPointer(sd->u.s.position.dwType + 1, GL_FLOAT, 
664                         sd->u.s.position.dwStride, 
665                         sd->u.s.position.lpData);
666         checkGLcall("glVertexPointer(...)");
667         glEnableClientState(GL_VERTEX_ARRAY);
668         checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
669
670     } else {
671
672         glDisableClientState(GL_VERTEX_ARRAY);
673         checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
674     }
675
676     /* Blend Data ----------------------------------------------*/
677     if ((sd->u.s.blendWeights.lpData != NULL) || 
678         (sd->u.s.blendMatrixIndices.lpData != NULL)) {
679         /* FIXME: Wont get here as will drop to slow method        */
680         FIXME("Blending not supported in fast draw routine\n");
681
682 #if 0 /* Vertex blend support needs to be added */
683         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
684             /*FIXME("TODO\n");*/
685         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
686             /*FIXME("TODO\n");*/
687             /*
688             GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos); 
689             checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
690             glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
691             checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
692             */
693         } else {
694             FIXME("unsupported blending in openGl\n");
695         }
696     } else {
697         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
698             FIXME("TODO\n");
699         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
700             FIXME("TODO\n");
701             /*
702             glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
703             checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
704             */
705         }
706 #endif
707     }
708
709     /* Normals -------------------------------------------------*/
710     if (sd->u.s.normal.lpData != NULL) {
711
712         /* Note dwType == float3 or float4 == 2 or 3 */
713         VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n", 
714                 sd->u.s.normal.dwStride, 
715                 sd->u.s.normal.lpData));
716         glNormalPointer(GL_FLOAT, 
717                         sd->u.s.normal.dwStride, 
718                         sd->u.s.normal.lpData);
719         checkGLcall("glNormalPointer(...)");
720         glEnableClientState(GL_NORMAL_ARRAY);
721         checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
722
723     } else {
724
725         glDisableClientState(GL_NORMAL_ARRAY);
726         checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
727         glNormal3f(0, 0, 1);
728         checkGLcall("glNormal3f(0, 0, 1)");
729     }
730
731     /* Point Size ----------------------------------------------*/
732     if (sd->u.s.pSize.lpData != NULL) {
733
734         /* no such functionality in the fixed function GL pipeline */
735         /* FIXME: Wont get here as will drop to slow method        */
736         FIXME("Cannot change ptSize here in openGl\n");
737     }
738
739     /* Diffuse Colour ------------------------------------------*/
740     /*  WARNING: Data here MUST be in RGBA format, so cannot    */
741     /*     go directly into fast mode from app pgm, because     */
742     /*     directx requires data in BGRA format.                */
743     if (sd->u.s.diffuse.lpData != NULL) {
744
745         /* Note dwType == float3 or float4 == 2 or 3 */
746         VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", 
747                 sd->u.s.diffuse.dwStride, 
748                 sd->u.s.diffuse.lpData));
749         glColorPointer(4, GL_UNSIGNED_BYTE, 
750                        sd->u.s.diffuse.dwStride, 
751                        sd->u.s.diffuse.lpData);
752         checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
753         glEnableClientState(GL_COLOR_ARRAY);
754         checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
755
756     } else {
757
758         glDisableClientState(GL_COLOR_ARRAY);
759         checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
760         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
761         checkGLcall("glColor4f(1, 1, 1, 1)");
762     }
763
764     /* Specular Colour ------------------------------------------*/
765     if (sd->u.s.specular.lpData != NULL) {
766
767         /* Note dwType == float3 or float4 == 2 or 3 */
768         VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", 
769                 sd->u.s.specular.dwStride, 
770                 sd->u.s.specular.lpData));
771
772 #if defined(GL_VERSION_1_4)
773         glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, 
774                                    sd->u.s.specular.dwStride, 
775                                    sd->u.s.specular.lpData);
776         vcheckGLcall("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, ...)");
777         glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
778         vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY)");
779 #elif defined(GL_EXT_secondary_color)
780         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
781             GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
782                                                    sd->u.s.specular.dwStride, 
783                                                    sd->u.s.specular.lpData);
784             checkGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
785             glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
786             checkGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
787         }
788 #else
789         /* Missing specular color is not critical, no warnings */
790         VTRACE(("Specular colour is not supported in this GL implementation\n"));
791 #endif
792
793     } else {
794
795 #if defined(GL_VERSION_1_4)
796         glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
797         checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY)");
798         glSecondaryColor3f(0, 0, 0);
799         checkGLcall("glSecondaryColor3f(0, 0, 0)");
800 #elif defined(GL_EXT_secondary_color)
801         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
802               glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
803             checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
804             GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
805             checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
806         }
807 #else
808         /* Do not worry if specular colour missing and disable request */
809 #endif
810     }
811
812     /* Texture coords -------------------------------------------*/
813     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
814
815         /* Select the correct texture stage */
816 #if defined(GL_VERSION_1_3)
817         glClientActiveTexture(GL_TEXTURE0 + textureNo);
818 #else
819         glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo);
820 #endif
821
822         /* Query tex coords */
823         if (This->StateBlock->textures[textureNo] != NULL) {
824             int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
825
826             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
827                 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
828                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
829                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
830                 continue;
831             }
832
833             if (coordIdx > 7) {
834                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
835                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
836                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
837             } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
838                 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
839                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
840                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
841             } else {
842
843                 /* The coords to supply depend completely on the fvf / vertex shader */
844                 GLint size;
845                 GLenum type;
846
847                 switch (sd->u.s.texCoords[coordIdx].dwType) {
848                 case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break;
849                 case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break;
850                 case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break;
851                 case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break;
852                 case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break;
853                 case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break;
854                 case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
855                 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
856                       size = 4; type = GL_UNSIGNED_BYTE;
857                 }
858
859                 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
860                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
861             }
862         } else {
863             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
864             glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
865         }
866     } 
867
868     /* Ok, Work out which primitive is requested and how many vertexes that 
869        will be                                                              */
870     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
871
872     /* Finally do the drawing */
873     if (idxData != NULL) {
874
875         TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
876 #if 1  /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
877         glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
878                       (char *)idxData+(idxSize * startIdx));
879 #else
880         glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes, 
881                       idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, 
882                       (char *)idxData+(idxSize * startIdx));
883 #endif
884         checkGLcall("glDrawRangeElements");
885
886     } else {
887
888         /* Note first is now zero as we shuffled along earlier */
889         TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
890         glDrawArrays(glPrimType, 0, NumVertexes);
891         checkGLcall("glDrawArrays");
892
893     }
894 }
895
896 /* 
897  * Actually draw using the supplied information.
898  * Slower GL version which extracts info about each vertex in turn
899  */
900 void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, 
901                      int PrimitiveType, ULONG NumPrimitives,
902                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
903
904     int                        textureNo    = 0;
905     GLenum                     glPrimType   = GL_POINTS;
906     int                        NumVertexes  = NumPrimitives;
907     const short               *pIdxBufS     = NULL;
908     const long                *pIdxBufL     = NULL;
909     LONG                       SkipnStrides = 0;
910     LONG                       vx_index;
911     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
912     float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */
913     float rhw = 0.0f;                      /* rhw                        */
914     float ptSize = 0.0f;                   /* Point size                 */
915     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
916     DWORD specularColor = 0;               /* Specular Color             */
917     ICOM_THIS(IDirect3DDevice8Impl,iface);
918
919     TRACE("Using slow vertex array code\n");
920
921     /* Variable Initialization */
922     if (idxData != NULL) {
923         if (idxSize == 2) pIdxBufS = (short *) idxData;
924         else pIdxBufL = (long *) idxData;
925     }
926
927     /* Ok, Work out which primitive is requested and how many vertexes that will be */
928     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
929
930     /* Start drawing in GL */
931     VTRACE(("glBegin(%x)\n", glPrimType));
932     glBegin(glPrimType);
933
934     /* For each primitive */
935     for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
936
937         /* Initialize diffuse color */
938         diffuseColor = 0xFFFFFFFF;
939
940         /* For indexed data, we need to go a few more strides in */
941         if (idxData != NULL) {
942
943             /* Indexed so work out the number of strides to skip */
944             if (idxSize == 2) {
945                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
946                 SkipnStrides = pIdxBufS[startIdx+vx_index];
947             } else {
948                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
949                 SkipnStrides = pIdxBufL[startIdx+vx_index];
950             }
951         }
952
953         /* Position Information ------------------ */
954         if (sd->u.s.position.lpData != NULL) {
955
956             float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
957             x = ptrToCoords[0];
958             y = ptrToCoords[1];
959             z = ptrToCoords[2];
960             rhw = 1.0;
961             VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
962
963             /* RHW follows, only if transformed, ie 4 floats were provided */
964             if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) {
965                 rhw = ptrToCoords[3];
966                 VTRACE(("rhw=%f\n", rhw));
967             }
968         }
969
970         /* Blending data -------------------------- */
971         if (sd->u.s.blendWeights.lpData != NULL) {
972             /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
973             FIXME("Blending not supported yet\n");
974
975             if (sd->u.s.blendMatrixIndices.lpData != NULL) {
976                 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
977             }
978         }
979
980         /* Vertex Normal Data (untransformed only)- */
981         if (sd->u.s.normal.lpData != NULL) {
982
983             float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
984             nx = ptrToCoords[0];
985             ny = ptrToCoords[1];
986             nz = ptrToCoords[2];
987             VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
988         }
989
990         /* Point Size ----------------------------- */
991         if (sd->u.s.pSize.lpData != NULL) {
992
993             float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
994             ptSize = ptrToCoords[0];
995             VTRACE(("ptSize=%f\n", ptSize));
996             FIXME("No support for ptSize yet\n");
997         }
998
999         /* Diffuse -------------------------------- */
1000         if (sd->u.s.diffuse.lpData != NULL) {
1001
1002             DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1003             diffuseColor = ptrToCoords[0];
1004             VTRACE(("diffuseColor=%lx\n", diffuseColor));
1005         }
1006
1007         /* Specular  -------------------------------- */
1008         if (sd->u.s.specular.lpData != NULL) {
1009
1010             DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1011             specularColor = ptrToCoords[0];
1012             VTRACE(("specularColor=%lx\n", specularColor));
1013         }
1014
1015         /* Texture coords --------------------------- */
1016         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1017
1018             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1019                 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
1020                 continue ;
1021             }
1022
1023             /* Query tex coords */
1024             if (This->StateBlock->textures[textureNo] != NULL) {
1025
1026                 int    coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
1027                 float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1028                 float  s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1029
1030                 if (coordIdx > 7) {
1031                     VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1032                     continue;
1033                 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1034                     TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1035                     continue;
1036                 } else {
1037
1038                     int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */
1039
1040                     /* The coords to supply depend completely on the fvf / vertex shader */
1041                     switch (coordsToUse) {
1042                     case 4: q = ptrToCoords[3]; /* drop through */
1043                     case 3: r = ptrToCoords[2]; /* drop through */
1044                     case 2: t = ptrToCoords[1]; /* drop through */
1045                     case 1: s = ptrToCoords[0]; 
1046                     }
1047
1048                     /* Projected is more 'fun' - Move the last coord to the 'q'
1049                           parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1050                     if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1051                         (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1052
1053                         if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1054                             switch (coordsToUse) {
1055                             case 0:  /* Drop Through */
1056                             case 1:
1057                                 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1058                                 break;
1059                             case 2:
1060                                 q = t;
1061                                 t = 0.0;
1062                                 coordsToUse = 4;
1063                                 break;
1064                             case 3:
1065                                 q = r;
1066                                 r = 0.0;
1067                                 coordsToUse = 4;
1068                                 break;
1069                             case 4:  /* Nop here */
1070                                 break;
1071                             default:
1072                                 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n", 
1073                                       This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1074                             }
1075                         }
1076                     }
1077
1078                     switch (coordsToUse) {   /* Supply the provided texture coords */
1079                     case D3DTTFF_COUNT1:
1080                         VTRACE(("tex:%d, s=%f\n", textureNo, s));
1081                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1082 #if defined(GL_VERSION_1_3)
1083                             glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
1084 #else
1085                             glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
1086 #endif
1087                         } else {
1088                             glTexCoord1f(s);
1089                         }
1090                         break;
1091                     case D3DTTFF_COUNT2:
1092                         VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1093                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1094 #if defined(GL_VERSION_1_3)
1095                             glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
1096 #else
1097                             glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
1098 #endif
1099                         } else {
1100                             glTexCoord2f(s, t);
1101                         }
1102                         break;
1103                     case D3DTTFF_COUNT3:
1104                         VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1105                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1106 #if defined(GL_VERSION_1_3)
1107                             glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
1108 #else
1109                             glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
1110 #endif
1111                         } else {
1112                             glTexCoord3f(s, t, r);
1113                         }
1114                         break;
1115                     case D3DTTFF_COUNT4:
1116                         VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1117                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1118 #if defined(GL_VERSION_1_3)
1119                             glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
1120 #else
1121                             glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
1122 #endif
1123                         } else {
1124                             glTexCoord4f(s, t, r, q);
1125                         }
1126                         break;
1127                     default:
1128                         FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1129                     }
1130                 }
1131             }
1132         } /* End of textures */
1133
1134         /* Diffuse -------------------------------- */
1135         if (sd->u.s.diffuse.lpData != NULL) {
1136             glColor4ub((diffuseColor >> 16) & 0xFF,
1137                        (diffuseColor >>  8) & 0xFF,
1138                        (diffuseColor >>  0) & 0xFF,
1139                        (diffuseColor >> 24) & 0xFF);
1140             VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", 
1141                     ((diffuseColor >> 16) & 0xFF) / 255.0f, 
1142                     ((diffuseColor >>  8) & 0xFF) / 255.0f,
1143                     ((diffuseColor >>  0) & 0xFF) / 255.0f, 
1144                     ((diffuseColor >> 24) & 0xFF) / 255.0f));
1145         } else {
1146             if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1147         }
1148
1149 #if 1
1150         /* Specular ------------------------------- */
1151         if (sd->u.s.diffuse.lpData != NULL) {
1152             VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n", 
1153                     ((specularColor >> 16) & 0xFF) / 255.0f, 
1154                     ((specularColor >>  8) & 0xFF) / 255.0f,
1155                     ((specularColor >>  0) & 0xFF) / 255.0f));
1156 #if defined(GL_VERSION_1_4)
1157             glSecondaryColor3ub((specularColor >> 16) & 0xFF,
1158                                 (specularColor >>  8) & 0xFF,
1159                                 (specularColor >>  0) & 0xFF);
1160 #elif defined(GL_EXT_secondary_color)
1161             if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1162                 GL_EXTCALL(glSecondaryColor3ubEXT)(
1163                            (specularColor >> 16) & 0xFF,
1164                            (specularColor >>  8) & 0xFF,
1165                            (specularColor >>  0) & 0xFF);
1166             }
1167 #else
1168             /* Do not worry if specular colour missing and disable request */
1169             VTRACE(("Specular color extensions not supplied\n"));
1170 #endif
1171         } else {
1172 #if defined(GL_VERSION_1_4)
1173             if (vx_index == 0) glSecondaryColor3f(0, 0, 0);
1174 #elif defined(GL_EXT_secondary_color)
1175             if (vx_index == 0 && GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1176                 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1177             }
1178 #else
1179             /* Do not worry if specular colour missing and disable request */
1180 #endif
1181         }
1182 #endif
1183
1184         /* Normal -------------------------------- */
1185         if (sd->u.s.normal.lpData != NULL) {
1186             VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1187             glNormal3f(nx, ny, nz);
1188         } else {
1189             if (vx_index == 0) glNormal3f(0, 0, 1);
1190         }
1191         
1192         /* Position -------------------------------- */
1193         if (sd->u.s.position.lpData != NULL) {
1194             if (1.0f == rhw || rhw < 0.0001f) {
1195                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1196                 glVertex3f(x, y, z);
1197             } else {
1198                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1199                 glVertex4f(x,y,z,rhw);
1200             }
1201         }
1202
1203         /* For non indexed mode, step onto next parts */
1204         if (idxData == NULL) {
1205             SkipnStrides += 1;
1206         }
1207     }
1208
1209     glEnd();
1210     checkGLcall("glEnd and previous calls");
1211 }
1212
1213 /* 
1214  * Draw with emulated vertex shaders
1215  * Note: strided data is uninitialized, as we need to pass the vertex
1216  *     shader directly as ordering irs yet                             
1217  */
1218 void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, 
1219                      int PrimitiveType, ULONG NumPrimitives,
1220                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1221
1222     int                        textureNo    = 0;
1223     GLenum                     glPrimType   = GL_POINTS;
1224     int                        NumVertexes  = NumPrimitives;
1225     const short               *pIdxBufS     = NULL;
1226     const long                *pIdxBufL     = NULL;
1227     LONG                       SkipnStrides = 0;
1228     LONG                       vx_index;
1229     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1230     float rhw = 0.0f;                      /* rhw                        */
1231     float ptSize = 0.0f;                   /* Point size                 */
1232     D3DVECTOR_4 texcoords[8];              /* Texture Coords             */
1233     int   numcoords[8];                    /* Number of coords           */
1234     ICOM_THIS(IDirect3DDevice8Impl,iface);
1235
1236     IDirect3DVertexShaderImpl* vertex_shader = NULL;
1237
1238     TRACE("Using slow software vertex shader code\n");
1239
1240     /* Variable Initialization */
1241     if (idxData != NULL) {
1242         if (idxSize == 2) pIdxBufS = (short *) idxData;
1243         else pIdxBufL = (long *) idxData;
1244     }
1245
1246     /* Ok, Work out which primitive is requested and how many vertexes that will be */
1247     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1248
1249     /* Retrieve the VS information */
1250     vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1251
1252     /* Start drawing in GL */
1253     VTRACE(("glBegin(%x)\n", glPrimType));
1254     glBegin(glPrimType);
1255
1256     /* For each primitive */
1257     for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1258
1259         /* For indexed data, we need to go a few more strides in */
1260         if (idxData != NULL) {
1261
1262             /* Indexed so work out the number of strides to skip */
1263             if (idxSize == 2) {
1264                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1265                 SkipnStrides = pIdxBufS[startIdx+vx_index];
1266             } else {
1267                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1268                 SkipnStrides = pIdxBufL[startIdx+vx_index];
1269             }
1270         }
1271
1272         /* Fill the vertex shader input */
1273         IDirect3DDeviceImpl_FillVertexShaderInput(This, vertex_shader, SkipnStrides);
1274
1275         /* Initialize the output fields to the same defaults as it would normally have */
1276         memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1277         vertex_shader->output.oD[0].x = 1.0;
1278         vertex_shader->output.oD[0].y = 1.0;
1279         vertex_shader->output.oD[0].z = 1.0;
1280         vertex_shader->output.oD[0].w = 1.0; 
1281
1282         /* Now execute the vertex shader */
1283         IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1284
1285         /*
1286         TRACE_VECTOR(vertex_shader->output.oPos);
1287         TRACE_VECTOR(vertex_shader->output.oD[0]);
1288         TRACE_VECTOR(vertex_shader->output.oD[1]);
1289         TRACE_VECTOR(vertex_shader->output.oT[0]);
1290         TRACE_VECTOR(vertex_shader->output.oT[1]);
1291         TRACE_VECTOR(vertex_shader->input.V[0]);
1292         TRACE_VECTOR(vertex_shader->data->C[0]);
1293         TRACE_VECTOR(vertex_shader->data->C[1]);
1294         TRACE_VECTOR(vertex_shader->data->C[2]);
1295         TRACE_VECTOR(vertex_shader->data->C[3]);
1296         TRACE_VECTOR(vertex_shader->data->C[4]);
1297         TRACE_VECTOR(vertex_shader->data->C[5]);
1298         TRACE_VECTOR(vertex_shader->data->C[6]);
1299         TRACE_VECTOR(vertex_shader->data->C[7]);
1300         */
1301
1302         /* Extract out the output */
1303         /*FIXME: Fog coords? */
1304         x = vertex_shader->output.oPos.x;
1305         y = vertex_shader->output.oPos.y;
1306         z = vertex_shader->output.oPos.z;
1307         rhw = vertex_shader->output.oPos.w;
1308         ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1309
1310         /** Update textures coords using vertex_shader->output.oT[0->7] */
1311         memset(texcoords, 0x00, sizeof(texcoords));
1312         memset(numcoords, 0x00, sizeof(numcoords));
1313         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1314             if (This->StateBlock->textures[textureNo] != NULL) {
1315                texcoords[textureNo].x   = vertex_shader->output.oT[textureNo].x;
1316                texcoords[textureNo].y   = vertex_shader->output.oT[textureNo].y;
1317                texcoords[textureNo].z   = vertex_shader->output.oT[textureNo].z;
1318                texcoords[textureNo].w   = vertex_shader->output.oT[textureNo].w;
1319                if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1320                    numcoords[textureNo]    = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1321                } else {
1322                    switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) {
1323                    case D3DRTYPE_TEXTURE:       numcoords[textureNo]    = 2; break;
1324                    case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo]    = 3; break;
1325                    default:                     numcoords[textureNo]    = 4;
1326                    }
1327                }
1328             } else {
1329                 numcoords[textureNo]    = 0;
1330             }
1331         }
1332
1333         /* Draw using this information */
1334         draw_vertex(iface,
1335                     TRUE, x, y, z, rhw, 
1336                     TRUE, 0.0f, 0.0f, 1.0f, 
1337                     TRUE, (float*) &vertex_shader->output.oD[0],  
1338                     TRUE, (float*) &vertex_shader->output.oD[1],  
1339                     FALSE, ptSize,         /* FIXME: Change back when supported */
1340                     texcoords, numcoords);
1341
1342         /* For non indexed mode, step onto next parts */
1343         if (idxData == NULL) {
1344             SkipnStrides += 1;
1345         }
1346
1347     } /* for each vertex */
1348
1349     glEnd();
1350     checkGLcall("glEnd and previous calls");
1351 }
1352
1353 /* Routine common to the draw primitive and draw indexed primitive routines */
1354 void drawPrimitive(LPDIRECT3DDEVICE8 iface,
1355                     int PrimitiveType, long NumPrimitives,
1356
1357                     /* for Indexed: */
1358                     long  StartVertexIndex,
1359                     long  StartIdx,
1360                     short idxSize,
1361                     const void *idxData,
1362                     int   minIndex) {
1363
1364     BOOL                          rc = FALSE;
1365     DWORD                         fvf = 0;
1366     IDirect3DVertexShaderImpl    *vertex_shader = NULL;
1367     BOOL                          useVertexShaderFunction = FALSE;
1368     BOOL                          isLightingOn = FALSE;
1369     Direct3DVertexStridedData     dataLocations;
1370     ICOM_THIS(IDirect3DDevice8Impl,iface);
1371
1372
1373     /* Work out what the FVF should look like */
1374     rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1375     if (rc) return;
1376
1377     /* If we will be using a vertex shader, do some initialization for it */
1378     if (useVertexShaderFunction == TRUE) {
1379         vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
1380         memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1381
1382         /** init Constants */
1383         if (TRUE == This->UpdateStateBlock->Changed.vertexShaderConstant) {
1384             TRACE_(d3d_shader)("vertex shader initializing constants\n");
1385             IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96);
1386         }
1387     }
1388
1389     /* Ok, we will be updating the screen from here onwards so grab the lock */
1390     ENTER_GL();
1391
1392     /* Setup transform matrices and sort out */
1393     isLightingOn = primitiveInitState(iface, 
1394                                       fvf & D3DFVF_XYZRHW, 
1395                                       !(fvf & D3DFVF_NORMAL),
1396                                       useVertexShaderFunction);
1397
1398     /* Initialize all values to null */
1399     if (useVertexShaderFunction == FALSE) {
1400         memset(&dataLocations, 0x00, sizeof(dataLocations));
1401
1402         /* Convert to strided data */
1403         primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex); 
1404
1405         /* Dump out what parts we have supplied */
1406         TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1407         TRACE_STRIDED((&dataLocations), position);
1408         TRACE_STRIDED((&dataLocations), blendWeights);
1409         TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1410         TRACE_STRIDED((&dataLocations), normal);
1411         TRACE_STRIDED((&dataLocations), pSize);
1412         TRACE_STRIDED((&dataLocations), diffuse);
1413         TRACE_STRIDED((&dataLocations), specular);
1414         TRACE_STRIDED((&dataLocations), texCoords[0]);
1415         TRACE_STRIDED((&dataLocations), texCoords[1]);
1416         TRACE_STRIDED((&dataLocations), texCoords[2]);
1417         TRACE_STRIDED((&dataLocations), texCoords[3]);
1418         TRACE_STRIDED((&dataLocations), texCoords[4]);
1419         TRACE_STRIDED((&dataLocations), texCoords[5]);
1420         TRACE_STRIDED((&dataLocations), texCoords[6]);
1421         TRACE_STRIDED((&dataLocations), texCoords[7]);
1422     }
1423
1424     /* Now initialize the materials state */
1425     init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1426
1427     /* Now draw the graphics to the screen */
1428     if  (useVertexShaderFunction == TRUE) {
1429
1430         /* Ideally, we should have software FV and hardware VS, possibly
1431            depending on the device type?                                 */
1432
1433         /* We will have to use the very, very slow emulation layer */
1434         drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1435                         idxData, idxSize, minIndex, StartIdx);            
1436
1437     } else if ((dataLocations.u.s.pSize.lpData        != NULL) || 
1438                (dataLocations.u.s.diffuse.lpData      != NULL) || 
1439                (dataLocations.u.s.blendWeights.lpData != NULL)) {
1440
1441         /* Fixme, Ideally, only use the per-vertex code for software HAL 
1442            but until opengl supports all the functions returned to setup 
1443            vertex arrays, we need to drop down to the slow mechanism for  
1444            certain functions                                              */
1445
1446         /* We will have to use the slow version of GL per vertex setup */
1447         drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1448                         idxData, idxSize, minIndex, StartIdx); 
1449
1450     } else {
1451
1452         /* We can use the fast version of GL pointers */
1453         drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1454                         idxData, idxSize, minIndex, StartIdx);
1455     }
1456
1457     /* If vertex shaders or no normals, restore previous lighting state */
1458     if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
1459         if (isLightingOn) glEnable(GL_LIGHTING);
1460         else glDisable(GL_LIGHTING);
1461         TRACE("Restored lighting to original state\n");
1462     }
1463
1464     /* Finshed updating the screen, restore lock */
1465     LEAVE_GL();
1466     TRACE("Done all gl drawing\n");
1467
1468     /* Diagnostics */
1469 #if defined(SHOW_FRAME_MAKEUP)
1470     {
1471         if (isDumpingFrames == TRUE) {
1472             D3DLOCKED_RECT r;
1473             char buffer[80];
1474             IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->backBuffer, &r, NULL, D3DLOCK_READONLY);
1475             sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1476             TRACE("Saving screenshot %s\n", buffer);
1477             IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->backBuffer, buffer);
1478             IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->backBuffer);
1479
1480 #if defined(SHOW_TEXTURE_MAKEUP)
1481            {
1482             LPDIRECT3DSURFACE8 pSur;
1483             int textureNo;
1484             for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1485                 if (This->StateBlock->textures[textureNo] != NULL) {
1486                     sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1487                     TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->StateBlock->textures[textureNo])->format));
1488                     IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur);
1489                     IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1490                     IDirect3DSurface8Impl_Release(pSur);
1491                 }
1492             }
1493            }
1494 #endif
1495            primCounter = primCounter + 1; 
1496         }
1497     }
1498 #endif
1499 }