Add support for display of dibs on MSB XServers.
[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
664         /* Disable RHW mode as 'w' coord handling for rhw mode should
665            not impact screen position whereas in GL it does. This may 
666            result in very slightly distored textures in rhw mode, but
667            a very minimal different                                   */
668         glVertexPointer(3, GL_FLOAT,  /* RHW: Was 'sd->u.s.position.dwType + 1' */
669                         sd->u.s.position.dwStride, 
670                         sd->u.s.position.lpData);
671         checkGLcall("glVertexPointer(...)");
672         glEnableClientState(GL_VERTEX_ARRAY);
673         checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
674
675     } else {
676
677         glDisableClientState(GL_VERTEX_ARRAY);
678         checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
679     }
680
681     /* Blend Data ----------------------------------------------*/
682     if ((sd->u.s.blendWeights.lpData != NULL) || 
683         (sd->u.s.blendMatrixIndices.lpData != NULL)) {
684         /* FIXME: Wont get here as will drop to slow method        */
685         FIXME("Blending not supported in fast draw routine\n");
686
687 #if 0 /* Vertex blend support needs to be added */
688         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
689             /*FIXME("TODO\n");*/
690         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
691             /*FIXME("TODO\n");*/
692             /*
693             GLExtCall(glVertexWeightPointerEXT)(numBlends, GL_FLOAT, skip, curPos); 
694             checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
695             glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
696             checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
697             */
698         } else {
699             FIXME("unsupported blending in openGl\n");
700         }
701     } else {
702         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
703             FIXME("TODO\n");
704         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
705             FIXME("TODO\n");
706             /*
707             glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
708             checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
709             */
710         }
711 #endif
712     }
713
714     /* Normals -------------------------------------------------*/
715     if (sd->u.s.normal.lpData != NULL) {
716
717         /* Note dwType == float3 or float4 == 2 or 3 */
718         VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n", 
719                 sd->u.s.normal.dwStride, 
720                 sd->u.s.normal.lpData));
721         glNormalPointer(GL_FLOAT, 
722                         sd->u.s.normal.dwStride, 
723                         sd->u.s.normal.lpData);
724         checkGLcall("glNormalPointer(...)");
725         glEnableClientState(GL_NORMAL_ARRAY);
726         checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
727
728     } else {
729
730         glDisableClientState(GL_NORMAL_ARRAY);
731         checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
732         glNormal3f(0, 0, 1);
733         checkGLcall("glNormal3f(0, 0, 1)");
734     }
735
736     /* Point Size ----------------------------------------------*/
737     if (sd->u.s.pSize.lpData != NULL) {
738
739         /* no such functionality in the fixed function GL pipeline */
740         /* FIXME: Wont get here as will drop to slow method        */
741         FIXME("Cannot change ptSize here in openGl\n");
742     }
743
744     /* Diffuse Colour ------------------------------------------*/
745     /*  WARNING: Data here MUST be in RGBA format, so cannot    */
746     /*     go directly into fast mode from app pgm, because     */
747     /*     directx requires data in BGRA format.                */
748     if (sd->u.s.diffuse.lpData != NULL) {
749
750         /* Note dwType == float3 or float4 == 2 or 3 */
751         VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", 
752                 sd->u.s.diffuse.dwStride, 
753                 sd->u.s.diffuse.lpData));
754         glColorPointer(4, GL_UNSIGNED_BYTE, 
755                        sd->u.s.diffuse.dwStride, 
756                        sd->u.s.diffuse.lpData);
757         checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
758         glEnableClientState(GL_COLOR_ARRAY);
759         checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
760
761     } else {
762
763         glDisableClientState(GL_COLOR_ARRAY);
764         checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
765         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
766         checkGLcall("glColor4f(1, 1, 1, 1)");
767     }
768
769     /* Specular Colour ------------------------------------------*/
770     if (sd->u.s.specular.lpData != NULL) {
771
772         /* Note dwType == float3 or float4 == 2 or 3 */
773         VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n", 
774                 sd->u.s.specular.dwStride, 
775                 sd->u.s.specular.lpData));
776
777 #if defined(GL_VERSION_1_4)
778         glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, 
779                                    sd->u.s.specular.dwStride, 
780                                    sd->u.s.specular.lpData);
781         vcheckGLcall("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, ...)");
782         glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
783         vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY)");
784 #elif defined(GL_EXT_secondary_color)
785         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
786             GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
787                                                    sd->u.s.specular.dwStride, 
788                                                    sd->u.s.specular.lpData);
789             checkGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
790             glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
791             checkGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
792         }
793 #else
794         /* Missing specular color is not critical, no warnings */
795         VTRACE(("Specular colour is not supported in this GL implementation\n"));
796 #endif
797
798     } else {
799
800 #if defined(GL_VERSION_1_4)
801         glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
802         checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY)");
803         glSecondaryColor3f(0, 0, 0);
804         checkGLcall("glSecondaryColor3f(0, 0, 0)");
805 #elif defined(GL_EXT_secondary_color)
806         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
807               glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
808             checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
809             GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
810             checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
811         }
812 #else
813         /* Do not worry if specular colour missing and disable request */
814 #endif
815     }
816
817     /* Texture coords -------------------------------------------*/
818     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
819
820         /* Select the correct texture stage */
821 #if defined(GL_VERSION_1_3)
822         glClientActiveTexture(GL_TEXTURE0 + textureNo);
823 #else
824         glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo);
825 #endif
826
827         /* Query tex coords */
828         if (This->StateBlock->textures[textureNo] != NULL) {
829             int coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
830
831             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
832                 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
833                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
834                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
835                 continue;
836             }
837
838             if (coordIdx > 7) {
839                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
840                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
841                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
842             } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
843                 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
844                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
845                 glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
846             } else {
847
848                 /* The coords to supply depend completely on the fvf / vertex shader */
849                 GLint size;
850                 GLenum type;
851
852                 switch (sd->u.s.texCoords[coordIdx].dwType) {
853                 case D3DVSDT_FLOAT1: size = 1, type = GL_FLOAT; break;
854                 case D3DVSDT_FLOAT2: size = 2, type = GL_FLOAT; break;
855                 case D3DVSDT_FLOAT3: size = 3, type = GL_FLOAT; break;
856                 case D3DVSDT_FLOAT4: size = 4, type = GL_FLOAT; break;
857                 case D3DVSDT_SHORT2: size = 2, type = GL_SHORT; break;
858                 case D3DVSDT_SHORT4: size = 4, type = GL_SHORT; break;
859                 case D3DVSDT_UBYTE4: size = 4, type = GL_UNSIGNED_BYTE; break;
860                 default: FIXME("Unrecognized data type %ld\n", sd->u.s.texCoords[coordIdx].dwType);
861                       size = 4; type = GL_UNSIGNED_BYTE;
862                 }
863
864                 glTexCoordPointer(size, type, sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
865                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
866             }
867         } else {
868             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
869             glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1);
870         }
871     } 
872
873     /* Ok, Work out which primitive is requested and how many vertexes that 
874        will be                                                              */
875     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
876
877     /* Finally do the drawing */
878     if (idxData != NULL) {
879
880         TRACE("glElements(%x, %d, %ld, ...)\n", glPrimType, NumVertexes, minIndex);
881 #if 1  /* FIXME: Want to use DrawRangeElements, but wrong calculation! */
882         glDrawElements(glPrimType, NumVertexes, idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT,
883                       (char *)idxData+(idxSize * startIdx));
884 #else
885         glDrawRangeElements(glPrimType, minIndex, minIndex+NumVertexes-1, NumVertexes, 
886                       idxSize==2?GL_UNSIGNED_SHORT:GL_UNSIGNED_INT, 
887                       (char *)idxData+(idxSize * startIdx));
888 #endif
889         checkGLcall("glDrawRangeElements");
890
891     } else {
892
893         /* Note first is now zero as we shuffled along earlier */
894         TRACE("glDrawArrays(%x, 0, %d)\n", glPrimType, NumVertexes);
895         glDrawArrays(glPrimType, 0, NumVertexes);
896         checkGLcall("glDrawArrays");
897
898     }
899 }
900
901 /* 
902  * Actually draw using the supplied information.
903  * Slower GL version which extracts info about each vertex in turn
904  */
905 void drawStridedSlow(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, 
906                      int PrimitiveType, ULONG NumPrimitives,
907                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
908
909     int                        textureNo    = 0;
910     GLenum                     glPrimType   = GL_POINTS;
911     int                        NumVertexes  = NumPrimitives;
912     const short               *pIdxBufS     = NULL;
913     const long                *pIdxBufL     = NULL;
914     LONG                       SkipnStrides = 0;
915     LONG                       vx_index;
916     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
917     float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */
918     float rhw = 0.0f;                      /* rhw                        */
919     float ptSize = 0.0f;                   /* Point size                 */
920     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
921     DWORD specularColor = 0;               /* Specular Color             */
922     ICOM_THIS(IDirect3DDevice8Impl,iface);
923
924     TRACE("Using slow vertex array code\n");
925
926     /* Variable Initialization */
927     if (idxData != NULL) {
928         if (idxSize == 2) pIdxBufS = (short *) idxData;
929         else pIdxBufL = (long *) idxData;
930     }
931
932     /* Ok, Work out which primitive is requested and how many vertexes that will be */
933     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
934
935     /* Start drawing in GL */
936     VTRACE(("glBegin(%x)\n", glPrimType));
937     glBegin(glPrimType);
938
939     /* For each primitive */
940     for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
941
942         /* Initialize diffuse color */
943         diffuseColor = 0xFFFFFFFF;
944
945         /* For indexed data, we need to go a few more strides in */
946         if (idxData != NULL) {
947
948             /* Indexed so work out the number of strides to skip */
949             if (idxSize == 2) {
950                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
951                 SkipnStrides = pIdxBufS[startIdx+vx_index];
952             } else {
953                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
954                 SkipnStrides = pIdxBufL[startIdx+vx_index];
955             }
956         }
957
958         /* Position Information ------------------ */
959         if (sd->u.s.position.lpData != NULL) {
960
961             float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
962             x = ptrToCoords[0];
963             y = ptrToCoords[1];
964             z = ptrToCoords[2];
965             rhw = 1.0;
966             VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
967
968             /* RHW follows, only if transformed, ie 4 floats were provided */
969             if (sd->u.s.position.dwType == D3DVSDT_FLOAT4) {
970                 rhw = ptrToCoords[3];
971                 VTRACE(("rhw=%f\n", rhw));
972             }
973         }
974
975         /* Blending data -------------------------- */
976         if (sd->u.s.blendWeights.lpData != NULL) {
977             /*float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride));*/
978             FIXME("Blending not supported yet\n");
979
980             if (sd->u.s.blendMatrixIndices.lpData != NULL) {
981                 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
982             }
983         }
984
985         /* Vertex Normal Data (untransformed only)- */
986         if (sd->u.s.normal.lpData != NULL) {
987
988             float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
989             nx = ptrToCoords[0];
990             ny = ptrToCoords[1];
991             nz = ptrToCoords[2];
992             VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
993         }
994
995         /* Point Size ----------------------------- */
996         if (sd->u.s.pSize.lpData != NULL) {
997
998             float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
999             ptSize = ptrToCoords[0];
1000             VTRACE(("ptSize=%f\n", ptSize));
1001             FIXME("No support for ptSize yet\n");
1002         }
1003
1004         /* Diffuse -------------------------------- */
1005         if (sd->u.s.diffuse.lpData != NULL) {
1006
1007             DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1008             diffuseColor = ptrToCoords[0];
1009             VTRACE(("diffuseColor=%lx\n", diffuseColor));
1010         }
1011
1012         /* Specular  -------------------------------- */
1013         if (sd->u.s.specular.lpData != NULL) {
1014
1015             DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1016             specularColor = ptrToCoords[0];
1017             VTRACE(("specularColor=%lx\n", specularColor));
1018         }
1019
1020         /* Texture coords --------------------------- */
1021         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1022
1023             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1024                 FIXME("Program using multiple concurrent textures which this opengl implementation doesnt support\n");
1025                 continue ;
1026             }
1027
1028             /* Query tex coords */
1029             if (This->StateBlock->textures[textureNo] != NULL) {
1030
1031                 int    coordIdx = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXCOORDINDEX];
1032                 float *ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1033                 float  s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1034
1035                 if (coordIdx > 7) {
1036                     VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1037                     continue;
1038                 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1039                     TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1040                     continue;
1041                 } else {
1042
1043                     int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DVSDT_FLOAT1 etc */
1044
1045                     /* The coords to supply depend completely on the fvf / vertex shader */
1046                     switch (coordsToUse) {
1047                     case 4: q = ptrToCoords[3]; /* drop through */
1048                     case 3: r = ptrToCoords[2]; /* drop through */
1049                     case 2: t = ptrToCoords[1]; /* drop through */
1050                     case 1: s = ptrToCoords[0]; 
1051                     }
1052
1053                     /* Projected is more 'fun' - Move the last coord to the 'q'
1054                           parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1055                     if ((This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1056                         (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1057
1058                         if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1059                             switch (coordsToUse) {
1060                             case 0:  /* Drop Through */
1061                             case 1:
1062                                 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1063                                 break;
1064                             case 2:
1065                                 q = t;
1066                                 t = 0.0;
1067                                 coordsToUse = 4;
1068                                 break;
1069                             case 3:
1070                                 q = r;
1071                                 r = 0.0;
1072                                 coordsToUse = 4;
1073                                 break;
1074                             case 4:  /* Nop here */
1075                                 break;
1076                             default:
1077                                 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n", 
1078                                       This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1079                             }
1080                         }
1081                     }
1082
1083                     switch (coordsToUse) {   /* Supply the provided texture coords */
1084                     case D3DTTFF_COUNT1:
1085                         VTRACE(("tex:%d, s=%f\n", textureNo, s));
1086                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1087 #if defined(GL_VERSION_1_3)
1088                             glMultiTexCoord1f(GL_TEXTURE0 + textureNo, s);
1089 #else
1090                             glMultiTexCoord1fARB(GL_TEXTURE0_ARB + textureNo, s);
1091 #endif
1092                         } else {
1093                             glTexCoord1f(s);
1094                         }
1095                         break;
1096                     case D3DTTFF_COUNT2:
1097                         VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1098                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1099 #if defined(GL_VERSION_1_3)
1100                             glMultiTexCoord2f(GL_TEXTURE0 + textureNo, s, t);
1101 #else
1102                             glMultiTexCoord2fARB(GL_TEXTURE0_ARB + textureNo, s, t);
1103 #endif
1104                         } else {
1105                             glTexCoord2f(s, t);
1106                         }
1107                         break;
1108                     case D3DTTFF_COUNT3:
1109                         VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1110                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1111 #if defined(GL_VERSION_1_3)
1112                             glMultiTexCoord3f(GL_TEXTURE0 + textureNo, s, t, r);
1113 #else
1114                             glMultiTexCoord3fARB(GL_TEXTURE0_ARB + textureNo, s, t, r);
1115 #endif
1116                         } else {
1117                             glTexCoord3f(s, t, r);
1118                         }
1119                         break;
1120                     case D3DTTFF_COUNT4:
1121                         VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1122                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1123 #if defined(GL_VERSION_1_3)
1124                             glMultiTexCoord4f(GL_TEXTURE0 + textureNo, s, t, r, q);
1125 #else
1126                             glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, s, t, r, q);
1127 #endif
1128                         } else {
1129                             glTexCoord4f(s, t, r, q);
1130                         }
1131                         break;
1132                     default:
1133                         FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1134                     }
1135                 }
1136             }
1137         } /* End of textures */
1138
1139         /* Diffuse -------------------------------- */
1140         if (sd->u.s.diffuse.lpData != NULL) {
1141             glColor4ub((diffuseColor >> 16) & 0xFF,
1142                        (diffuseColor >>  8) & 0xFF,
1143                        (diffuseColor >>  0) & 0xFF,
1144                        (diffuseColor >> 24) & 0xFF);
1145             VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", 
1146                     ((diffuseColor >> 16) & 0xFF) / 255.0f, 
1147                     ((diffuseColor >>  8) & 0xFF) / 255.0f,
1148                     ((diffuseColor >>  0) & 0xFF) / 255.0f, 
1149                     ((diffuseColor >> 24) & 0xFF) / 255.0f));
1150         } else {
1151             if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1152         }
1153
1154 #if 1
1155         /* Specular ------------------------------- */
1156         if (sd->u.s.diffuse.lpData != NULL) {
1157             VTRACE(("glSecondaryColor4ub: r,g,b=%f,%f,%f\n", 
1158                     ((specularColor >> 16) & 0xFF) / 255.0f, 
1159                     ((specularColor >>  8) & 0xFF) / 255.0f,
1160                     ((specularColor >>  0) & 0xFF) / 255.0f));
1161 #if defined(GL_VERSION_1_4)
1162             glSecondaryColor3ub((specularColor >> 16) & 0xFF,
1163                                 (specularColor >>  8) & 0xFF,
1164                                 (specularColor >>  0) & 0xFF);
1165 #elif defined(GL_EXT_secondary_color)
1166             if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1167                 GL_EXTCALL(glSecondaryColor3ubEXT)(
1168                            (specularColor >> 16) & 0xFF,
1169                            (specularColor >>  8) & 0xFF,
1170                            (specularColor >>  0) & 0xFF);
1171             }
1172 #else
1173             /* Do not worry if specular colour missing and disable request */
1174             VTRACE(("Specular color extensions not supplied\n"));
1175 #endif
1176         } else {
1177 #if defined(GL_VERSION_1_4)
1178             if (vx_index == 0) glSecondaryColor3f(0, 0, 0);
1179 #elif defined(GL_EXT_secondary_color)
1180             if (vx_index == 0 && GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1181                 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1182             }
1183 #else
1184             /* Do not worry if specular colour missing and disable request */
1185 #endif
1186         }
1187 #endif
1188
1189         /* Normal -------------------------------- */
1190         if (sd->u.s.normal.lpData != NULL) {
1191             VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1192             glNormal3f(nx, ny, nz);
1193         } else {
1194             if (vx_index == 0) glNormal3f(0, 0, 1);
1195         }
1196         
1197         /* Position -------------------------------- */
1198         if (sd->u.s.position.lpData != NULL) {
1199             if (1.0f == rhw || rhw < 0.0001f) {
1200                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1201                 glVertex3f(x, y, z);
1202             } else {
1203                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1204                 /* Disable RHW mode as 'w' coord handling for rhw mode should
1205                    not impact screen position whereas in GL it does. This may 
1206                    result in very slightly distored textures in rhw mode, but
1207                    a very minimal different. In slow mode a possible 'fix' is
1208                    glVertex4f(x*rhw,y*rhw,z*rhw,rhw) but not sure this is right */
1209                 glVertex3f(x,y,z);
1210             }
1211         }
1212
1213         /* For non indexed mode, step onto next parts */
1214         if (idxData == NULL) {
1215             SkipnStrides += 1;
1216         }
1217     }
1218
1219     glEnd();
1220     checkGLcall("glEnd and previous calls");
1221 }
1222
1223 /* 
1224  * Draw with emulated vertex shaders
1225  * Note: strided data is uninitialized, as we need to pass the vertex
1226  *     shader directly as ordering irs yet                             
1227  */
1228 void drawStridedSoftwareVS(LPDIRECT3DDEVICE8 iface, Direct3DVertexStridedData *sd, 
1229                      int PrimitiveType, ULONG NumPrimitives,
1230                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1231
1232     int                        textureNo    = 0;
1233     GLenum                     glPrimType   = GL_POINTS;
1234     int                        NumVertexes  = NumPrimitives;
1235     const short               *pIdxBufS     = NULL;
1236     const long                *pIdxBufL     = NULL;
1237     LONG                       SkipnStrides = 0;
1238     LONG                       vx_index;
1239     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1240     float rhw = 0.0f;                      /* rhw                        */
1241     float ptSize = 0.0f;                   /* Point size                 */
1242     D3DVECTOR_4 texcoords[8];              /* Texture Coords             */
1243     int   numcoords[8];                    /* Number of coords           */
1244     ICOM_THIS(IDirect3DDevice8Impl,iface);
1245
1246     IDirect3DVertexShaderImpl* vertex_shader = NULL;
1247
1248     TRACE("Using slow software vertex shader code\n");
1249
1250     /* Variable Initialization */
1251     if (idxData != NULL) {
1252         if (idxSize == 2) pIdxBufS = (short *) idxData;
1253         else pIdxBufL = (long *) idxData;
1254     }
1255
1256     /* Ok, Work out which primitive is requested and how many vertexes that will be */
1257     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1258
1259     /* Retrieve the VS information */
1260     vertex_shader = VERTEX_SHADER(This->StateBlock->VertexShader);
1261
1262     /* Start drawing in GL */
1263     VTRACE(("glBegin(%x)\n", glPrimType));
1264     glBegin(glPrimType);
1265
1266     /* For each primitive */
1267     for (vx_index = 0; vx_index < NumVertexes; vx_index++) {
1268
1269         /* For indexed data, we need to go a few more strides in */
1270         if (idxData != NULL) {
1271
1272             /* Indexed so work out the number of strides to skip */
1273             if (idxSize == 2) {
1274                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1275                 SkipnStrides = pIdxBufS[startIdx+vx_index];
1276             } else {
1277                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1278                 SkipnStrides = pIdxBufL[startIdx+vx_index];
1279             }
1280         }
1281
1282         /* Fill the vertex shader input */
1283         IDirect3DDeviceImpl_FillVertexShaderInput(This, vertex_shader, SkipnStrides);
1284
1285         /* Initialize the output fields to the same defaults as it would normally have */
1286         memset(&vertex_shader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1287         vertex_shader->output.oD[0].x = 1.0;
1288         vertex_shader->output.oD[0].y = 1.0;
1289         vertex_shader->output.oD[0].z = 1.0;
1290         vertex_shader->output.oD[0].w = 1.0; 
1291
1292         /* Now execute the vertex shader */
1293         IDirect3DVertexShaderImpl_ExecuteSW(vertex_shader, &vertex_shader->input, &vertex_shader->output);
1294
1295         /*
1296         TRACE_VECTOR(vertex_shader->output.oPos);
1297         TRACE_VECTOR(vertex_shader->output.oD[0]);
1298         TRACE_VECTOR(vertex_shader->output.oD[1]);
1299         TRACE_VECTOR(vertex_shader->output.oT[0]);
1300         TRACE_VECTOR(vertex_shader->output.oT[1]);
1301         TRACE_VECTOR(vertex_shader->input.V[0]);
1302         TRACE_VECTOR(vertex_shader->data->C[0]);
1303         TRACE_VECTOR(vertex_shader->data->C[1]);
1304         TRACE_VECTOR(vertex_shader->data->C[2]);
1305         TRACE_VECTOR(vertex_shader->data->C[3]);
1306         TRACE_VECTOR(vertex_shader->data->C[4]);
1307         TRACE_VECTOR(vertex_shader->data->C[5]);
1308         TRACE_VECTOR(vertex_shader->data->C[6]);
1309         TRACE_VECTOR(vertex_shader->data->C[7]);
1310         */
1311
1312         /* Extract out the output */
1313         /*FIXME: Fog coords? */
1314         x = vertex_shader->output.oPos.x;
1315         y = vertex_shader->output.oPos.y;
1316         z = vertex_shader->output.oPos.z;
1317         rhw = vertex_shader->output.oPos.w;
1318         ptSize = vertex_shader->output.oPts.x; /* Fixme - Is this right? */
1319
1320         /** Update textures coords using vertex_shader->output.oT[0->7] */
1321         memset(texcoords, 0x00, sizeof(texcoords));
1322         memset(numcoords, 0x00, sizeof(numcoords));
1323         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1324             if (This->StateBlock->textures[textureNo] != NULL) {
1325                texcoords[textureNo].x   = vertex_shader->output.oT[textureNo].x;
1326                texcoords[textureNo].y   = vertex_shader->output.oT[textureNo].y;
1327                texcoords[textureNo].z   = vertex_shader->output.oT[textureNo].z;
1328                texcoords[textureNo].w   = vertex_shader->output.oT[textureNo].w;
1329                if (This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1330                    numcoords[textureNo]    = This->UpdateStateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1331                } else {
1332                    switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->StateBlock->textures[textureNo])) {
1333                    case D3DRTYPE_TEXTURE:       numcoords[textureNo]    = 2; break;
1334                    case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo]    = 3; break;
1335                    default:                     numcoords[textureNo]    = 4;
1336                    }
1337                }
1338             } else {
1339                 numcoords[textureNo]    = 0;
1340             }
1341         }
1342
1343         /* Draw using this information */
1344         draw_vertex(iface,
1345                     TRUE, x, y, z, rhw, 
1346                     TRUE, 0.0f, 0.0f, 1.0f, 
1347                     TRUE, (float*) &vertex_shader->output.oD[0],  
1348                     TRUE, (float*) &vertex_shader->output.oD[1],  
1349                     FALSE, ptSize,         /* FIXME: Change back when supported */
1350                     texcoords, numcoords);
1351
1352         /* For non indexed mode, step onto next parts */
1353         if (idxData == NULL) {
1354             SkipnStrides += 1;
1355         }
1356
1357     } /* for each vertex */
1358
1359     glEnd();
1360     checkGLcall("glEnd and previous calls");
1361 }
1362
1363 /* Routine common to the draw primitive and draw indexed primitive routines */
1364 void drawPrimitive(LPDIRECT3DDEVICE8 iface,
1365                     int PrimitiveType, long NumPrimitives,
1366
1367                     /* for Indexed: */
1368                     long  StartVertexIndex,
1369                     long  StartIdx,
1370                     short idxSize,
1371                     const void *idxData,
1372                     int   minIndex) {
1373
1374     BOOL                          rc = FALSE;
1375     DWORD                         fvf = 0;
1376     IDirect3DVertexShaderImpl    *vertex_shader = NULL;
1377     BOOL                          useVertexShaderFunction = FALSE;
1378     BOOL                          isLightingOn = FALSE;
1379     Direct3DVertexStridedData     dataLocations;
1380     ICOM_THIS(IDirect3DDevice8Impl,iface);
1381
1382
1383     /* Work out what the FVF should look like */
1384     rc = initializeFVF(iface, &fvf, &useVertexShaderFunction);
1385     if (rc) return;
1386
1387     /* If we will be using a vertex shader, do some initialization for it */
1388     if (useVertexShaderFunction == TRUE) {
1389         vertex_shader = VERTEX_SHADER(This->UpdateStateBlock->VertexShader);
1390         memset(&vertex_shader->input, 0, sizeof(VSHADERINPUTDATA8));
1391
1392         /** init Constants */
1393         if (TRUE == This->UpdateStateBlock->Changed.vertexShaderConstant) {
1394             TRACE_(d3d_shader)("vertex shader initializing constants\n");
1395             IDirect3DVertexShaderImpl_SetConstantF(vertex_shader, 0, (CONST FLOAT*) &This->UpdateStateBlock->vertexShaderConstant[0], 96);
1396         }
1397     }
1398
1399     /* Ok, we will be updating the screen from here onwards so grab the lock */
1400     ENTER_GL();
1401
1402     /* Setup transform matrices and sort out */
1403     isLightingOn = primitiveInitState(iface, 
1404                                       fvf & D3DFVF_XYZRHW, 
1405                                       !(fvf & D3DFVF_NORMAL),
1406                                       useVertexShaderFunction);
1407
1408     /* Initialize all values to null */
1409     if (useVertexShaderFunction == FALSE) {
1410         memset(&dataLocations, 0x00, sizeof(dataLocations));
1411
1412         /* Convert to strided data */
1413         primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex); 
1414
1415         /* Dump out what parts we have supplied */
1416         TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1417         TRACE_STRIDED((&dataLocations), position);
1418         TRACE_STRIDED((&dataLocations), blendWeights);
1419         TRACE_STRIDED((&dataLocations), blendMatrixIndices);
1420         TRACE_STRIDED((&dataLocations), normal);
1421         TRACE_STRIDED((&dataLocations), pSize);
1422         TRACE_STRIDED((&dataLocations), diffuse);
1423         TRACE_STRIDED((&dataLocations), specular);
1424         TRACE_STRIDED((&dataLocations), texCoords[0]);
1425         TRACE_STRIDED((&dataLocations), texCoords[1]);
1426         TRACE_STRIDED((&dataLocations), texCoords[2]);
1427         TRACE_STRIDED((&dataLocations), texCoords[3]);
1428         TRACE_STRIDED((&dataLocations), texCoords[4]);
1429         TRACE_STRIDED((&dataLocations), texCoords[5]);
1430         TRACE_STRIDED((&dataLocations), texCoords[6]);
1431         TRACE_STRIDED((&dataLocations), texCoords[7]);
1432     }
1433
1434     /* Now initialize the materials state */
1435     init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
1436
1437     /* Now draw the graphics to the screen */
1438     if  (useVertexShaderFunction == TRUE) {
1439
1440         /* Ideally, we should have software FV and hardware VS, possibly
1441            depending on the device type?                                 */
1442
1443         /* We will have to use the very, very slow emulation layer */
1444         drawStridedSoftwareVS(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1445                         idxData, idxSize, minIndex, StartIdx);            
1446
1447     } else if ((dataLocations.u.s.pSize.lpData        != NULL) || 
1448                (dataLocations.u.s.diffuse.lpData      != NULL) || 
1449                (dataLocations.u.s.blendWeights.lpData != NULL)) {
1450
1451         /* Fixme, Ideally, only use the per-vertex code for software HAL 
1452            but until opengl supports all the functions returned to setup 
1453            vertex arrays, we need to drop down to the slow mechanism for  
1454            certain functions                                              */
1455
1456         /* We will have to use the slow version of GL per vertex setup */
1457         drawStridedSlow(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1458                         idxData, idxSize, minIndex, StartIdx); 
1459
1460     } else {
1461
1462         /* We can use the fast version of GL pointers */
1463         drawStridedFast(iface, &dataLocations, PrimitiveType, NumPrimitives, 
1464                         idxData, idxSize, minIndex, StartIdx);
1465     }
1466
1467     /* If vertex shaders or no normals, restore previous lighting state */
1468     if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
1469         if (isLightingOn) glEnable(GL_LIGHTING);
1470         else glDisable(GL_LIGHTING);
1471         TRACE("Restored lighting to original state\n");
1472     }
1473
1474     /* Finshed updating the screen, restore lock */
1475     LEAVE_GL();
1476     TRACE("Done all gl drawing\n");
1477
1478     /* Diagnostics */
1479 #if defined(SHOW_FRAME_MAKEUP)
1480     {
1481         if (isDumpingFrames == TRUE) {
1482             D3DLOCKED_RECT r;
1483             char buffer[80];
1484             IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) This->backBuffer, &r, NULL, D3DLOCK_READONLY);
1485             sprintf(buffer, "/tmp/backbuffer_%ld.ppm", primCounter);
1486             TRACE("Saving screenshot %s\n", buffer);
1487             IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This->backBuffer, buffer);
1488             IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) This->backBuffer);
1489
1490 #if defined(SHOW_TEXTURE_MAKEUP)
1491            {
1492             LPDIRECT3DSURFACE8 pSur;
1493             int textureNo;
1494             for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1495                 if (This->StateBlock->textures[textureNo] != NULL) {
1496                     sprintf(buffer, "/tmp/texture_%ld_%d.ppm", primCounter, textureNo);
1497                     TRACE("Saving texture %s (Format:%s)\n", buffer, debug_d3dformat(((IDirect3DBaseTexture8Impl *)This->StateBlock->textures[textureNo])->format));
1498                     IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) This->StateBlock->textures[textureNo], 0, &pSur);
1499                     IDirect3DSurface8Impl_SaveSnapshot(pSur, buffer);
1500                     IDirect3DSurface8Impl_Release(pSur);
1501                 }
1502             }
1503            }
1504 #endif
1505            primCounter = primCounter + 1; 
1506         }
1507     }
1508 #endif
1509 }