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