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