dinput8: DirectInput8Create rewrite.
[wine] / dlls / wined3d / drawprim.c
1 /*
2  * WINED3D draw functions
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
30
31 #include <stdio.h>
32
33 #if 0 /* TODO */
34 extern IWineD3DVertexShaderImpl*            VertexShaders[64];
35 extern IWineD3DVertexDeclarationImpl*       VertexShaderDeclarations[64];
36 extern IWineD3DPixelShaderImpl*             PixelShaders[64];
37
38 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
39 #endif
40
41 /* Issues the glBegin call for gl given the primitive type and count */
42 static DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
43                     DWORD            NumPrimitives,
44                     GLenum          *primType)
45 {
46     DWORD   NumVertexes = NumPrimitives;
47
48     switch (PrimitiveType) {
49     case D3DPT_POINTLIST:
50         TRACE("POINTS\n");
51         *primType   = GL_POINTS;
52         NumVertexes = NumPrimitives;
53         break;
54
55     case D3DPT_LINELIST:
56         TRACE("LINES\n");
57         *primType   = GL_LINES;
58         NumVertexes = NumPrimitives * 2;
59         break;
60
61     case D3DPT_LINESTRIP:
62         TRACE("LINE_STRIP\n");
63         *primType   = GL_LINE_STRIP;
64         NumVertexes = NumPrimitives + 1;
65         break;
66
67     case D3DPT_TRIANGLELIST:
68         TRACE("TRIANGLES\n");
69         *primType   = GL_TRIANGLES;
70         NumVertexes = NumPrimitives * 3;
71         break;
72
73     case D3DPT_TRIANGLESTRIP:
74         TRACE("TRIANGLE_STRIP\n");
75         *primType   = GL_TRIANGLE_STRIP;
76         NumVertexes = NumPrimitives + 2;
77         break;
78
79     case D3DPT_TRIANGLEFAN:
80         TRACE("TRIANGLE_FAN\n");
81         *primType   = GL_TRIANGLE_FAN;
82         NumVertexes = NumPrimitives + 2;
83         break;
84
85     default:
86         FIXME("Unhandled primitive\n");
87         *primType    = GL_POINTS;
88         break;
89     }
90     return NumVertexes;
91 }
92
93 /* Ensure the appropriate material states are set up - only change
94    state if really required                                        */
95 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
96
97     BOOL requires_material_reset = FALSE;
98     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
99
100     if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
101         /* If we have not set up the material color tracking, do it now as required */
102         glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
103         checkGLcall("glDisable GL_COLOR_MATERIAL");
104         TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
105         glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
106         checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
107         glEnable(GL_COLOR_MATERIAL);
108         checkGLcall("glEnable GL_COLOR_MATERIAL");
109         This->tracking_color = IS_TRACKING;
110         requires_material_reset = TRUE; /* Restore material settings as will be used */
111
112     } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
113                (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
114         /* If we are tracking the current color but one isn't supplied, don't! */
115         glDisable(GL_COLOR_MATERIAL);
116         checkGLcall("glDisable GL_COLOR_MATERIAL");
117         This->tracking_color = NEEDS_TRACKING;
118         requires_material_reset = TRUE; /* Restore material settings as will be used */
119
120     } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
121         /* No need to reset material colors since no change to gl_color_material */
122         requires_material_reset = FALSE;
123
124     } else if (This->tracking_color == NEEDS_DISABLE) {
125         glDisable(GL_COLOR_MATERIAL);
126         checkGLcall("glDisable GL_COLOR_MATERIAL");
127         This->tracking_color = DISABLED_TRACKING;
128         requires_material_reset = TRUE; /* Restore material settings as will be used */
129     }
130
131     /* Reset the material colors which may have been tracking the color*/
132     if (requires_material_reset) {
133         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
134         checkGLcall("glMaterialfv");
135         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
136         checkGLcall("glMaterialfv");
137         if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
138            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
139            checkGLcall("glMaterialfv");
140         } else {
141            float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
142            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
143            checkGLcall("glMaterialfv");
144         }
145         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
146         checkGLcall("glMaterialfv");
147     }
148
149 }
150
151 static GLfloat invymat[16] = {
152         1.0f, 0.0f, 0.0f, 0.0f,
153         0.0f, -1.0f, 0.0f, 0.0f,
154         0.0f, 0.0f, 1.0f, 0.0f,
155         0.0f, 0.0f, 0.0f, 1.0f};
156
157 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
158     /* If the last draw was transformed as well, no need to reapply all the matrixes */
159     if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
160
161         double X, Y, height, width, minZ, maxZ;
162         This->last_was_rhw = TRUE;
163         This->viewport_changed = FALSE;
164
165         /* Transformed already into viewport coordinates, so we do not need transform
166             matrices. Reset all matrices to identity and leave the default matrix in world
167             mode.                                                                         */
168         glMatrixMode(GL_MODELVIEW);
169         checkGLcall("glMatrixMode(GL_MODELVIEW)");
170         glLoadIdentity();
171         checkGLcall("glLoadIdentity");
172
173         glMatrixMode(GL_PROJECTION);
174         checkGLcall("glMatrixMode(GL_PROJECTION)");
175         glLoadIdentity();
176         checkGLcall("glLoadIdentity");
177
178         /* Set up the viewport to be full viewport */
179         X      = This->stateBlock->viewport.X;
180         Y      = This->stateBlock->viewport.Y;
181         height = This->stateBlock->viewport.Height;
182         width  = This->stateBlock->viewport.Width;
183         minZ   = This->stateBlock->viewport.MinZ;
184         maxZ   = This->stateBlock->viewport.MaxZ;
185         TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
186         glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
187         checkGLcall("glOrtho");
188
189         /* Window Coord 0 is the middle of the first pixel, so translate by half
190             a pixel (See comment above glTranslate below)                         */
191         glTranslatef(0.375, 0.375, 0);
192         checkGLcall("glTranslatef(0.375, 0.375, 0)");
193         if (This->renderUpsideDown) {
194             glMultMatrixf(invymat);
195             checkGLcall("glMultMatrixf(invymat)");
196         }
197
198         /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
199         if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
200             if(GL_SUPPORT(EXT_FOG_COORD)) {
201                 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
202                 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
203                 glFogi(GL_FOG_MODE, GL_LINEAR);
204                 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
205                 /* The dx fog range in this case is fixed to 0 - 255,
206                  * but in GL it still depends on the fog start and end (according to the ext)
207                  * Use this to turn around the fog as it's needed. That prevents some
208                  * calculations during drawing :-)
209                  */
210                 glFogf(GL_FOG_START, (float) 0xff);
211                 checkGLcall("glFogfv GL_FOG_END");
212                 glFogf(GL_FOG_END, 0.0);
213                 checkGLcall("glFogfv GL_FOG_START");
214             } else {
215                 /* Disable GL fog, handle this in software in drawStridedSlow */
216                 glDisable(GL_FOG);
217                 checkGLcall("glDisable(GL_FOG)");
218             }
219         }
220     }
221 }
222 /* Setup views - Transformed & lit if RHW, else untransformed.
223        Only unlit if Normals are supplied
224     Returns: Whether to restore lighting afterwards           */
225 static void primitiveInitState(
226     IWineD3DDevice *iface,
227     WineDirect3DVertexStridedData* strided,
228     BOOL useVS,
229     BOOL* lighting_changed,
230     BOOL* lighting_original) {
231
232     BOOL fixed_vtx_transformed =
233        (strided->u.s.position.lpData != NULL || strided->u.s.position.VBO != 0 ||
234         strided->u.s.position2.lpData != NULL || strided->u.s.position2.VBO != 0) && 
235         strided->u.s.position_transformed;
236
237     BOOL fixed_vtx_lit = 
238         strided->u.s.normal.lpData == NULL && strided->u.s.normal.VBO == 0 &&
239         strided->u.s.normal2.lpData == NULL && strided->u.s.normal2.VBO == 0;
240
241     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
242
243     *lighting_changed = FALSE;
244
245     /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
246        set by the appropriate render state. Note Vertex Shader output is already lit */
247     if (fixed_vtx_lit || useVS) {
248         *lighting_changed = TRUE;
249         *lighting_original = glIsEnabled(GL_LIGHTING);
250         glDisable(GL_LIGHTING);
251         checkGLcall("glDisable(GL_LIGHTING);");
252         TRACE("Disabled lighting, old state = %d\n", *lighting_original);
253     }
254
255     if (!useVS && fixed_vtx_transformed) {
256         d3ddevice_set_ortho(This);
257
258     } else {
259
260         /* Untransformed, so relies on the view and projection matrices */
261
262         if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
263             /* Only reapply when have to */
264             This->modelview_valid = TRUE;
265             glMatrixMode(GL_MODELVIEW);
266             checkGLcall("glMatrixMode");
267
268             /* In the general case, the view matrix is the identity matrix */
269             if (This->view_ident) {
270                 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
271                 checkGLcall("glLoadMatrixf");
272             } else {
273                 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
274                 checkGLcall("glLoadMatrixf");
275                 glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
276                 checkGLcall("glMultMatrixf");
277             }
278         }
279
280         if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
281             /* Only reapply when have to */
282             This->proj_valid = TRUE;
283             glMatrixMode(GL_PROJECTION);
284             checkGLcall("glMatrixMode");
285
286             /* The rule is that the window coordinate 0 does not correspond to the
287                beginning of the first pixel, but the center of the first pixel.
288                As a consequence if you want to correctly draw one line exactly from
289                the left to the right end of the viewport (with all matrices set to
290                be identity), the x coords of both ends of the line would be not
291                -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
292                instead.                                                               */
293             glLoadIdentity();
294
295             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
296             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
297
298             if (This->renderUpsideDown) {
299                 glMultMatrixf(invymat);
300                 checkGLcall("glMultMatrixf(invymat)");
301             }
302             glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
303             checkGLcall("glLoadMatrixf");
304         }
305
306         /* Vertex Shader output is already transformed, so set up identity matrices */
307         /* FIXME: Actually, only true for software emulated ones, so when h/w ones
308              come along this needs to take into account whether s/w ones were
309              requested or not                                                       */
310         if (useVS) {
311             glMatrixMode(GL_MODELVIEW);
312             checkGLcall("glMatrixMode");
313             glLoadIdentity();
314             glMatrixMode(GL_PROJECTION);
315             checkGLcall("glMatrixMode");
316             glLoadIdentity();
317             /* Window Coord 0 is the middle of the first pixel, so translate by half
318                a pixel (See comment above glTranslate above)                         */
319             glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
320             checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
321             if (This->renderUpsideDown) {
322                 glMultMatrixf(invymat);
323                 checkGLcall("glMultMatrixf(invymat)");
324             }
325             This->modelview_valid = FALSE;
326             This->proj_valid = FALSE;
327         }
328         This->last_was_rhw = FALSE;
329
330         /* Setup fogging */
331         if (useVS && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->usesFog) {
332             /* In D3D vertex shader return the 'final' fog value, while in OpenGL it is the 'input' fog value.
333              * The code below 'disables' the OpenGL postprocessing by setting the formula to '1'. */
334             glFogi(GL_FOG_MODE, GL_LINEAR);
335             glFogf(GL_FOG_START, 1.0f);
336             glFogf(GL_FOG_END, 0.0f);
337
338         } else if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] 
339                   && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) {
340             
341             if(GL_SUPPORT(EXT_FOG_COORD)) {
342                 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT);
343                 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT)\n");
344                 /* Reapply the fog range */
345                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]);
346                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]);
347                 /* Restore the fog mode */
348                 IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]);
349             } else {
350                 /* Enable GL_FOG again because we disabled it above */
351                 glEnable(GL_FOG);
352                 checkGLcall("glEnable(GL_FOG)");
353             }
354         }
355     }
356 }
357
358 static BOOL fixed_get_input(
359     BYTE usage, BYTE usage_idx,
360     unsigned int* regnum) {
361
362     *regnum = -1;
363
364     /* Those positions must have the order in the
365      * named part of the strided data */
366
367     if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
368         *regnum = 0;
369     else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
370         *regnum = 1;
371     else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
372         *regnum = 2;
373     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
374         *regnum = 3;
375     else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
376         *regnum = 4;
377     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
378         *regnum = 5;
379     else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
380         *regnum = 6;
381     else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < D3DDP_MAXTEXCOORD)
382         *regnum = 7 + usage_idx;
383     else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
384         *regnum = 7 + D3DDP_MAXTEXCOORD;
385     else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
386         *regnum = 8 + D3DDP_MAXTEXCOORD;
387     else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
388         *regnum = 9 + D3DDP_MAXTEXCOORD;
389     else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
390         *regnum = 10 + D3DDP_MAXTEXCOORD;
391     else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
392         *regnum = 11 + D3DDP_MAXTEXCOORD;
393     else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
394         *regnum = 12 + D3DDP_MAXTEXCOORD;
395     else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
396         *regnum = 13 + D3DDP_MAXTEXCOORD;
397     else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
398         *regnum = 14 + D3DDP_MAXTEXCOORD;
399
400     if (*regnum < 0) {
401         FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
402             debug_d3ddeclusage(usage), usage_idx);
403         return FALSE;
404     }
405     return TRUE;
406 }
407
408 void primitiveDeclarationConvertToStridedData(
409      IWineD3DDevice *iface,
410      BOOL useVertexShaderFunction,
411      WineDirect3DVertexStridedData *strided,
412      LONG BaseVertexIndex, 
413      BOOL *fixup) {
414
415      /* We need to deal with frequency data!*/
416
417     BYTE  *data    = NULL;
418     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419     IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
420     int i;
421     WINED3DVERTEXELEMENT *element;
422     DWORD stride;
423     int reg;
424
425     /* Locate the vertex declaration */
426     if (useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
427         TRACE("Using vertex declaration from shader\n");
428         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
429     } else {
430         TRACE("Using vertex declaration\n");
431         vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
432     }
433
434     /* Translate the declaration into strided data */
435     for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
436         GLint streamVBO = 0;
437         BOOL stride_used;
438         unsigned int idx;
439
440         element = vertexDeclaration->pDeclarationWine + i;
441         TRACE("%p Elements %p %d or %d\n", vertexDeclaration->pDeclarationWine, element,  i, vertexDeclaration->declarationWNumElements);
442         if (This->stateBlock->streamIsUP) {
443             TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
444             streamVBO = 0;
445             data    = (BYTE *)This->stateBlock->streamSource[element->Stream];
446             if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
447         } else {
448             TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
449             IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
450             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
451             if(fixup) {
452                 if( streamVBO != 0) *fixup = TRUE;
453                 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
454             }
455         }
456         stride  = This->stateBlock->streamStride[element->Stream];
457         data += (BaseVertexIndex * stride);
458         data += element->Offset;
459         reg = element->Reg;
460
461         TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
462
463         if (useVertexShaderFunction)
464             stride_used = vshader_get_input(This->stateBlock->vertexShader,
465                 element->Usage, element->UsageIndex, &idx);
466         else
467             stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
468
469         if (stride_used) {
470            TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
471                  "stream=%u, offset=%u, stride=%lu, VBO=%u]\n",
472                  useVertexShaderFunction? "shader": "fixed function", idx,
473                  debug_d3ddeclusage(element->Usage), element->UsageIndex,
474                  element->Stream, element->Offset, stride, streamVBO);
475
476            strided->u.input[idx].lpData = data;
477            strided->u.input[idx].dwType = element->Type;
478            strided->u.input[idx].dwStride = stride;
479            strided->u.input[idx].VBO = streamVBO;
480            if (!useVertexShaderFunction) {
481                if (element->Usage == D3DDECLUSAGE_POSITION)
482                    strided->u.s.position_transformed = FALSE;
483                else if (element->Usage == D3DDECLUSAGE_POSITIONT)
484                    strided->u.s.position_transformed = TRUE;
485            }
486         }
487     };
488 }
489
490 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
491     int           numBlends;
492     int           numTextures;
493     int           textureNo;
494     int           coordIdxInfo = 0x00;    /* Information on number of coords supplied */
495     int           numCoords[8];           /* Holding place for D3DFVF_TEXTUREFORMATx  */
496
497     /* Either 3 or 4 floats depending on the FVF */
498     /* FIXME: Can blending data be in a different stream to the position data?
499           and if so using the fixed pipeline how do we handle it               */
500     if (thisFVF & D3DFVF_POSITION_MASK) {
501         strided->u.s.position.lpData    = data;
502         strided->u.s.position.dwType    = D3DDECLTYPE_FLOAT3;
503         strided->u.s.position.dwStride  = stride;
504         strided->u.s.position.VBO       = streamVBO;
505         data += 3 * sizeof(float);
506         if (thisFVF & D3DFVF_XYZRHW) {
507             strided->u.s.position.dwType = D3DDECLTYPE_FLOAT4;
508             strided->u.s.position_transformed = TRUE;
509             data += sizeof(float);
510         } else
511             strided->u.s.position_transformed = FALSE;
512     }
513
514     /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
515     /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
516     numBlends = 1 + (((thisFVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
517     if(thisFVF & D3DFVF_LASTBETA_UBYTE4) numBlends--;
518
519     if ((thisFVF & D3DFVF_XYZB5 ) > D3DFVF_XYZRHW) {
520         TRACE("Setting blend Weights to %p\n", data);
521         strided->u.s.blendWeights.lpData    = data;
522         strided->u.s.blendWeights.dwType    = D3DDECLTYPE_FLOAT1 + numBlends - 1;
523         strided->u.s.blendWeights.dwStride  = stride;
524         strided->u.s.blendWeights.VBO       = streamVBO;
525         data += numBlends * sizeof(FLOAT);
526
527         if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
528             strided->u.s.blendMatrixIndices.lpData = data;
529             strided->u.s.blendMatrixIndices.dwType  = D3DDECLTYPE_UBYTE4;
530             strided->u.s.blendMatrixIndices.dwStride= stride;
531             strided->u.s.blendMatrixIndices.VBO     = streamVBO;
532             data += sizeof(DWORD);
533         }
534     }
535
536     /* Normal is always 3 floats */
537     if (thisFVF & D3DFVF_NORMAL) {
538         strided->u.s.normal.lpData    = data;
539         strided->u.s.normal.dwType    = D3DDECLTYPE_FLOAT3;
540         strided->u.s.normal.dwStride  = stride;
541         strided->u.s.normal.VBO     = streamVBO;
542         data += 3 * sizeof(FLOAT);
543     }
544
545     /* Pointsize is a single float */
546     if (thisFVF & D3DFVF_PSIZE) {
547         strided->u.s.pSize.lpData    = data;
548         strided->u.s.pSize.dwType    = D3DDECLTYPE_FLOAT1;
549         strided->u.s.pSize.dwStride  = stride;
550         strided->u.s.pSize.VBO       = streamVBO;
551         data += sizeof(FLOAT);
552     }
553
554     /* Diffuse is 4 unsigned bytes */
555     if (thisFVF & D3DFVF_DIFFUSE) {
556         strided->u.s.diffuse.lpData    = data;
557         strided->u.s.diffuse.dwType    = D3DDECLTYPE_SHORT4;
558         strided->u.s.diffuse.dwStride  = stride;
559         strided->u.s.diffuse.VBO       = streamVBO;
560         data += sizeof(DWORD);
561     }
562
563     /* Specular is 4 unsigned bytes */
564     if (thisFVF & D3DFVF_SPECULAR) {
565         strided->u.s.specular.lpData    = data;
566         strided->u.s.specular.dwType    = D3DDECLTYPE_SHORT4;
567         strided->u.s.specular.dwStride  = stride;
568         strided->u.s.specular.VBO       = streamVBO;
569         data += sizeof(DWORD);
570     }
571
572     /* Texture coords */
573     numTextures   = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
574     coordIdxInfo  = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
575
576     /* numTextures indicates the number of texture coordinates supplied */
577     /* However, the first set may not be for stage 0 texture - it all   */
578     /*   depends on D3DTSS_TEXCOORDINDEX.                               */
579     /* The number of bytes for each coordinate set is based off         */
580     /*   D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits              */
581
582     /* So, for each supplied texture extract the coords */
583     for (textureNo = 0; textureNo < numTextures; ++textureNo) {
584
585         strided->u.s.texCoords[textureNo].lpData    = data;
586         strided->u.s.texCoords[textureNo].dwType    = D3DDECLTYPE_FLOAT1;
587         strided->u.s.texCoords[textureNo].dwStride  = stride;
588         strided->u.s.texCoords[textureNo].VBO       = streamVBO;
589         numCoords[textureNo] = coordIdxInfo & 0x03;
590
591         /* Always one set */
592         data += sizeof(float);
593         if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
594             strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT2;
595             data += sizeof(float);
596             if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
597                 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT3;
598                 data += sizeof(float);
599                 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
600                     strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT4;
601                     data += sizeof(float);
602                 }
603             }
604         }
605         coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
606     }
607 }
608
609 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, LONG BaseVertexIndex, BOOL *fixup) {
610
611     short         LoopThroughTo = 0;
612     short         nStream;
613     GLint         streamVBO = 0;
614
615     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
616
617     /* OK, Now to setup the data locations
618        For the non-created vertex shaders, the VertexShader var holds the real
619           FVF and only stream 0 matters
620        For the created vertex shaders, there is an FVF per stream              */
621     if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
622         LoopThroughTo = MAX_STREAMS;
623     } else {
624         LoopThroughTo = 1;
625     }
626
627     /* Work through stream by stream */
628     for (nStream=0; nStream<LoopThroughTo; ++nStream) {
629         DWORD  stride  = This->stateBlock->streamStride[nStream];
630         BYTE  *data    = NULL;
631         DWORD  thisFVF = 0;
632
633         /* Skip empty streams */
634         if (This->stateBlock->streamSource[nStream] == NULL) continue;
635
636         /* Retrieve appropriate FVF */
637         if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
638             thisFVF = This->stateBlock->fvf;
639             /* Handle memory passed directly as well as vertex buffers */
640             if (This->stateBlock->streamIsUP) {
641                 streamVBO = 0;
642                 data    = (BYTE *)This->stateBlock->streamSource[nStream];
643             } else {
644                 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
645                 /* GetMemory binds the VBO */
646                 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
647                 if(fixup) {
648                     if(streamVBO != 0 ) *fixup = TRUE;
649                 }
650             }
651         } else {
652 #if 0 /* TODO: Vertex shader support */
653             thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
654             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
655 #endif
656         }
657         VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
658         if (thisFVF == 0) continue;
659
660         /* Now convert the stream into pointers */
661
662         /* Shuffle to the beginning of the vertexes to render and index from there */
663         data = data + (BaseVertexIndex * stride);
664
665         primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
666     }
667 }
668
669 #if 0 /* TODO: Software Shaders */
670 /* Draw a single vertex using this information */
671 static void draw_vertex(IWineD3DDevice *iface,                         /* interface    */
672                  BOOL isXYZ,    float x, float y, float z, float rhw,  /* xyzn position*/
673                  BOOL isNormal, float nx, float ny, float nz,          /* normal       */
674                  BOOL isDiffuse, float *dRGBA,                         /* 1st   colors */
675                  BOOL isSpecular, float *sRGB,                         /* 2ndry colors */
676                  BOOL isPtSize, float ptSize,                       /* pointSize    */
677                  WINED3DVECTOR_4 *texcoords, int *numcoords)        /* texture info */
678 {
679     unsigned int textureNo;
680     float s, t, r, q;
681     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
682
683     /* Diffuse -------------------------------- */
684     if (isDiffuse) {
685         glColor4fv(dRGBA);
686         VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
687     }
688
689     /* Specular Colour ------------------------------------------*/
690     if (isSpecular) {
691         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
692           GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
693           VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
694         } else {
695           VTRACE(("Specular color extensions not supplied\n"));
696         }
697     }
698
699     /* Normal -------------------------------- */
700     if (isNormal) {
701         VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
702         glNormal3f(nx, ny, nz);
703     }
704
705     /* Point Size ----------------------------------------------*/
706     if (isPtSize) {
707
708         /* no such functionality in the fixed function GL pipeline */
709         FIXME("Cannot change ptSize here in openGl\n");
710     }
711
712     /* Texture coords --------------------------- */
713     for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
714
715         if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
716             FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
717             continue ;
718         }
719
720         /* Query tex coords */
721         if (This->stateBlock->textures[textureNo] != NULL) {
722
723             int    coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
724             if (coordIdx >= MAX_TEXTURES) {
725                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
726                 continue;
727             } else if (numcoords[coordIdx] == 0) {
728                 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
729                 continue;
730             } else {
731
732                 /* Initialize vars */
733                 s = 0.0f;
734                 t = 0.0f;
735                 r = 0.0f;
736                 q = 0.0f;
737
738                 switch (numcoords[coordIdx]) {
739                 case 4: q = texcoords[coordIdx].w; /* drop through */
740                 case 3: r = texcoords[coordIdx].z; /* drop through */
741                 case 2: t = texcoords[coordIdx].y; /* drop through */
742                 case 1: s = texcoords[coordIdx].x;
743                 }
744
745                 switch (numcoords[coordIdx]) {   /* Supply the provided texture coords */
746                 case D3DTTFF_COUNT1:
747                     VTRACE(("tex:%d, s=%f\n", textureNo, s));
748                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
749                         GLMULTITEXCOORD1F(textureNo, s);
750                     } else {
751                         glTexCoord1f(s);
752                     }
753                     break;
754                 case D3DTTFF_COUNT2:
755                     VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
756                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
757                         GLMULTITEXCOORD2F(textureNo, s, t);
758                     } else {
759                         glTexCoord2f(s, t);
760                     }
761                     break;
762                 case D3DTTFF_COUNT3:
763                     VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
764                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
765                         GLMULTITEXCOORD3F(textureNo, s, t, r);
766                     } else {
767                         glTexCoord3f(s, t, r);
768                     }
769                     break;
770                 case D3DTTFF_COUNT4:
771                     VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
772                     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
773                         GLMULTITEXCOORD4F(textureNo, s, t, r, q);
774                     } else {
775                         glTexCoord4f(s, t, r, q);
776                     }
777                     break;
778                 default:
779                     FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
780                 }
781             }
782         }
783     } /* End of textures */
784
785     /* Position -------------------------------- */
786     if (isXYZ) {
787         if (1.0f == rhw || rhw < 0.00001f) {
788             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
789             glVertex3f(x, y, z);
790         } else {
791             /* Cannot optimize by dividing through by rhw as rhw is required
792                later for perspective in the GL pipeline for vertex shaders   */
793             VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
794             glVertex4f(x,y,z,rhw);
795         }
796     }
797 }
798 #endif /* TODO: Software shaders */
799
800 static void loadNumberedArrays(
801     IWineD3DDevice *iface,
802     IWineD3DVertexShader *shader,
803     WineDirect3DVertexStridedData *strided) {
804
805     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
806     GLint curVBO = -1;
807     int i;
808
809     for (i = 0; i < MAX_ATTRIBS; i++) {
810
811         if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
812             continue;
813
814         TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
815
816         if(curVBO != strided->u.input[i].VBO) {
817             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
818             checkGLcall("glBindBufferARB");
819             curVBO = strided->u.input[i].VBO;
820         }
821         GL_EXTCALL(glVertexAttribPointerARB(i,
822                         WINED3D_ATR_SIZE(strided->u.input[i].dwType),
823                         WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
824                         WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
825                         strided->u.input[i].dwStride,
826                         strided->u.input[i].lpData));
827         GL_EXTCALL(glEnableVertexAttribArrayARB(i));
828    }
829 }
830
831 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
832     unsigned int textureNo   = 0;
833     unsigned int texture_idx = 0;
834     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
835     GLint curVBO = -1;
836
837     TRACE("Using fast vertex array code\n");
838     /* Blend Data ---------------------------------------------- */
839     if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
840         (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
841
842
843         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
844
845 #if 1
846             glEnableClientState(GL_WEIGHT_ARRAY_ARB);
847             checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
848 #endif
849
850             TRACE("Blend %d %p %ld\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
851                 sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
852             /* FIXME("TODO\n");*/
853             /* Note dwType == float3 or float4 == 2 or 3 */
854
855 #if 0
856             /* with this on, the normals appear to be being modified,
857                but the vertices aren't being translated as they should be
858                Maybe the world matrix aren't being setup properly? */
859             glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
860 #endif
861
862
863             VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %ld, %p)\n",
864                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
865                 sd->u.s.blendWeights.dwStride,
866                 sd->u.s.blendWeights.lpData));
867
868             if(curVBO != sd->u.s.blendWeights.VBO) {
869                 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
870                 checkGLcall("glBindBufferARB");
871                 curVBO = sd->u.s.blendWeights.VBO;
872             }
873
874             GL_EXTCALL(glWeightPointerARB)(
875                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
876                 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
877                 sd->u.s.blendWeights.dwStride,
878                 sd->u.s.blendWeights.lpData);
879
880             checkGLcall("glWeightPointerARB");
881
882             if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
883                 static BOOL showfixme = TRUE;
884                 if(showfixme){
885                     FIXME("blendMatrixIndices support\n");
886                     showfixme = FALSE;
887                 }
888             }
889
890         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
891             /* FIXME("TODO\n");*/
892 #if 0
893
894             GL_EXTCALL(glVertexWeightPointerEXT)(
895                 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
896                 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
897                 sd->u.s.blendWeights.dwStride,
898                 sd->u.s.blendWeights.lpData);
899             checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
900             glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
901             checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
902 #endif
903
904         } else {
905             /* TODO: support blends in fixupVertices */
906             FIXME("unsupported blending in openGl\n");
907         }
908     } else {
909         if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
910 #if 0    /* TODO: Vertex blending */
911             glDisable(GL_VERTEX_BLEND_ARB);
912 #endif
913             TRACE("ARB_VERTEX_BLEND\n");
914         } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
915             TRACE(" EXT_VERTEX_WEIGHTING\n");
916             glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
917             checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
918
919         }
920     }
921
922 #if 0 /* FOG  ----------------------------------------------*/
923     if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
924         /* TODO: fog*/
925     if (GL_SUPPORT(EXT_FOG_COORD) {
926              glEnableClientState(GL_FOG_COORDINATE_EXT);
927             (GL_EXTCALL)(FogCoordPointerEXT)(
928                 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
929                 sd->u.s.fog.dwStride,
930                 sd->u.s.fog.lpData);
931         } else {
932             /* don't bother falling back to 'slow' as we don't support software FOG yet. */
933             /* FIXME: fixme once */
934             TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
935         }
936     } else {
937         if (GL_SUPPRT(EXT_FOR_COORD) {
938              /* make sure fog is disabled */
939              glDisableClientState(GL_FOG_COORDINATE_EXT);
940         }
941     }
942 #endif
943
944 #if 0 /* tangents  ----------------------------------------------*/
945     if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
946         sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
947         /* TODO: tangents*/
948         if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
949             if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
950                 glEnable(GL_TANGENT_ARRAY_EXT);
951                 (GL_EXTCALL)(TangentPointerEXT)(
952                     WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
953                     sd->u.s.tangent.dwStride,
954                     sd->u.s.tangent.lpData);
955             } else {
956                     glDisable(GL_TANGENT_ARRAY_EXT);
957             }
958             if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
959                     glEnable(GL_BINORMAL_ARRAY_EXT);
960                     (GL_EXTCALL)(BinormalPointerEXT)(
961                         WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
962                         sd->u.s.binormal.dwStride,
963                         sd->u.s.binormal.lpData);
964             } else{
965                     glDisable(GL_BINORMAL_ARRAY_EXT);
966             }
967
968         } else {
969             /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
970             /* FIXME: fixme once */
971             TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
972         }
973     } else {
974         if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
975              /* make sure fog is disabled */
976              glDisable(GL_TANGENT_ARRAY_EXT);
977              glDisable(GL_BINORMAL_ARRAY_EXT);
978         }
979     }
980 #endif
981
982     /* Point Size ----------------------------------------------*/
983     if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
984
985         /* no such functionality in the fixed function GL pipeline */
986         TRACE("Cannot change ptSize here in openGl\n");
987         /* TODO: Implement this function in using shaders if they are available */
988
989     }
990
991     /* Vertex Pointers -----------------------------------------*/
992     if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
993         /* Note dwType == float3 or float4 == 2 or 3 */
994         VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
995                 sd->u.s.position.dwStride,
996                 sd->u.s.position.dwType + 1,
997                 sd->u.s.position.lpData));
998
999         if(curVBO != sd->u.s.position.VBO) {
1000             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
1001             checkGLcall("glBindBufferARB");
1002             curVBO = sd->u.s.position.VBO;
1003         }
1004
1005         /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1006            handling for rhw mode should not impact screen position whereas in GL it does.
1007            This may  result in very slightly distored textures in rhw mode, but
1008            a very minimal different. There's always the other option of
1009            fixing the view matrix to prevent w from having any effect
1010
1011            This only applies to user pointer sources, in VBOs the vertices are fixed up
1012          */
1013         if(sd->u.s.position.VBO == 0) {
1014             glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
1015                 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1016                 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1017         } else {
1018             glVertexPointer(
1019                 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
1020                 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
1021                 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1022         }
1023         checkGLcall("glVertexPointer(...)");
1024         glEnableClientState(GL_VERTEX_ARRAY);
1025         checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1026
1027     } else {
1028         glDisableClientState(GL_VERTEX_ARRAY);
1029         checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1030     }
1031
1032     /* Normals -------------------------------------------------*/
1033     if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
1034         /* Note dwType == float3 or float4 == 2 or 3 */
1035         VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
1036                 sd->u.s.normal.dwStride,
1037                 sd->u.s.normal.lpData));
1038         if(curVBO != sd->u.s.normal.VBO) {
1039             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
1040             checkGLcall("glBindBufferARB");
1041             curVBO = sd->u.s.normal.VBO;
1042         }
1043         glNormalPointer(
1044             WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
1045             sd->u.s.normal.dwStride,
1046             sd->u.s.normal.lpData);
1047         checkGLcall("glNormalPointer(...)");
1048         glEnableClientState(GL_NORMAL_ARRAY);
1049         checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1050
1051     } else {
1052         glDisableClientState(GL_NORMAL_ARRAY);
1053         checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1054         glNormal3f(0, 0, 1);
1055         checkGLcall("glNormal3f(0, 0, 1)");
1056     }
1057
1058     /* Diffuse Colour --------------------------------------------*/
1059     /*  WARNING: Data here MUST be in RGBA format, so cannot      */
1060     /*     go directly into fast mode from app pgm, because       */
1061     /*     directx requires data in BGRA format.                  */
1062     /* currently fixupVertices swizels the format, but this isn't */
1063     /* very practical when using VBOS                             */
1064     /* NOTE: Unless we write a vertex shader to swizel the colour */
1065     /* , or the user doesn't care and wants the speed advantage   */
1066
1067     if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
1068         /* Note dwType == float3 or float4 == 2 or 3 */
1069         VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1070                 sd->u.s.diffuse.dwStride,
1071                 sd->u.s.diffuse.lpData));
1072
1073         if(curVBO != sd->u.s.diffuse.VBO) {
1074             GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
1075             checkGLcall("glBindBufferARB");
1076             curVBO = sd->u.s.diffuse.VBO;
1077         }
1078         glColorPointer(4, GL_UNSIGNED_BYTE,
1079                        sd->u.s.diffuse.dwStride,
1080                        sd->u.s.diffuse.lpData);
1081         checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1082         glEnableClientState(GL_COLOR_ARRAY);
1083         checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1084
1085     } else {
1086         glDisableClientState(GL_COLOR_ARRAY);
1087         checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1088         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1089         checkGLcall("glColor4f(1, 1, 1, 1)");
1090     }
1091
1092     /* Specular Colour ------------------------------------------*/
1093     if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1094         TRACE("setting specular colour\n");
1095         /* Note dwType == float3 or float4 == 2 or 3 */
1096         VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1097                 sd->u.s.specular.dwStride,
1098                 sd->u.s.specular.lpData));
1099         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1100             if(curVBO != sd->u.s.specular.VBO) {
1101                 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1102                 checkGLcall("glBindBufferARB");
1103                 curVBO = sd->u.s.specular.VBO;
1104             }
1105             GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1106                                                    sd->u.s.specular.dwStride,
1107                                                    sd->u.s.specular.lpData);
1108             vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1109             glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1110             vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1111         } else {
1112
1113         /* Missing specular color is not critical, no warnings */
1114         VTRACE(("Specular colour is not supported in this GL implementation\n"));
1115         }
1116
1117     } else {
1118         if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1119
1120             glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1121             checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1122             GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1123             checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1124         } else {
1125
1126             /* Missing specular color is not critical, no warnings */
1127             VTRACE(("Specular colour is not supported in this GL implementation\n"));
1128         }
1129     }
1130
1131     /* Texture coords -------------------------------------------*/
1132
1133     for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1134         /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1135         /* Abort if we don't support the extension. */
1136         if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1137             FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1138             continue;
1139         }
1140
1141         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) {
1142             /* Select the correct texture stage */
1143             GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1144         }
1145
1146         if (This->stateBlock->textures[textureNo] != NULL) {
1147             int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1148             TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n", textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1149
1150             if (coordIdx >= MAX_TEXTURES) {
1151                 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1152                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1153                 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1154
1155             } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1156                 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1157                 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1158                 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1159
1160             } else {
1161                 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1162                     GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1163                     checkGLcall("glBindBufferARB");
1164                     curVBO = sd->u.s.texCoords[coordIdx].VBO;
1165                 }
1166                 /* The coords to supply depend completely on the fvf / vertex shader */
1167                 glTexCoordPointer(
1168                     WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1169                     WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1170                     sd->u.s.texCoords[coordIdx].dwStride,
1171                     sd->u.s.texCoords[coordIdx].lpData);
1172                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1173             }
1174         } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1175             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1176             GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1177         }
1178         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1179     }
1180     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1181         for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1182             GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1183             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1184             GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1185         }
1186     }
1187 }
1188
1189 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1190                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1191     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1192
1193     if (idxData != NULL /* This crashes sometimes!*/) {
1194         TRACE("(%p) : glElements(%x, %d, %ld, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1195         idxData = idxData == (void *)-1 ? NULL : idxData;
1196 #if 1
1197 #if 0
1198         glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1199         glEnableClientState(GL_INDEX_ARRAY);
1200 #endif
1201         glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1202                      (const char *)idxData+(idxSize * startIdx));
1203 #else /* using drawRangeElements may be faster */
1204
1205         glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1206                       idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1207                       (const char *)idxData+(idxSize * startIdx));
1208 #endif
1209         checkGLcall("glDrawRangeElements");
1210
1211     } else {
1212
1213         /* Note first is now zero as we shuffled along earlier */
1214         TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1215         glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1216         checkGLcall("glDrawArrays");
1217
1218     }
1219
1220     return;
1221 }
1222
1223 /*
1224  * Actually draw using the supplied information.
1225  * Slower GL version which extracts info about each vertex in turn
1226  */
1227         
1228 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1229                      UINT NumVertexes, GLenum glPrimType,
1230                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1231
1232     unsigned int               textureNo    = 0;
1233     unsigned int               texture_idx  = 0;
1234     const short               *pIdxBufS     = NULL;
1235     const long                *pIdxBufL     = NULL;
1236     LONG                       SkipnStrides = 0;
1237     LONG                       vx_index;
1238     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1239     float nx = 0.0f, ny = 0.0, nz = 0.0f;  /* normal x,y,z coordinates   */
1240     float rhw = 0.0f;                      /* rhw                        */
1241     float ptSize = 0.0f;                   /* Point size                 */
1242     DWORD diffuseColor = 0xFFFFFFFF;       /* Diffuse Color              */
1243     DWORD specularColor = 0;               /* Specular Color             */
1244     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245
1246     TRACE("Using slow vertex array code\n");
1247
1248     /* Variable Initialization */
1249     if (idxData != NULL) {
1250         if (idxSize == 2) pIdxBufS = (const short *) idxData;
1251         else pIdxBufL = (const long *) idxData;
1252     }
1253
1254     /* Start drawing in GL */
1255     VTRACE(("glBegin(%x)\n", glPrimType));
1256     glBegin(glPrimType);
1257
1258     /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1259      * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1260      */
1261
1262     /* For each primitive */
1263     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1264
1265         /* Initialize diffuse color */
1266         diffuseColor = 0xFFFFFFFF;
1267
1268         /* For indexed data, we need to go a few more strides in */
1269         if (idxData != NULL) {
1270
1271             /* Indexed so work out the number of strides to skip */
1272             if (idxSize == 2) {
1273                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1274                 SkipnStrides = pIdxBufS[startIdx + vx_index];
1275             } else {
1276                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1277                 SkipnStrides = pIdxBufL[startIdx + vx_index];
1278             }
1279         }
1280
1281         /* Position Information ------------------ */
1282         if (sd->u.s.position.lpData != NULL) {
1283
1284             float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1285             x = ptrToCoords[0];
1286             y = ptrToCoords[1];
1287             z = ptrToCoords[2];
1288             rhw = 1.0;
1289             VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1290
1291             /* RHW follows, only if transformed, ie 4 floats were provided */
1292             if (sd->u.s.position_transformed) {
1293                 rhw = ptrToCoords[3];
1294                 VTRACE(("rhw=%f\n", rhw));
1295             }
1296         }
1297
1298         /* Blending data -------------------------- */
1299         if (sd->u.s.blendWeights.lpData != NULL) {
1300             /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1301             FIXME("Blending not supported yet\n");
1302
1303             if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1304                 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1305             }
1306         }
1307
1308         /* Vertex Normal Data (untransformed only)- */
1309         if (sd->u.s.normal.lpData != NULL) {
1310
1311             float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1312             nx = ptrToCoords[0];
1313             ny = ptrToCoords[1];
1314             nz = ptrToCoords[2];
1315             VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1316         }
1317
1318         /* Point Size ----------------------------- */
1319         if (sd->u.s.pSize.lpData != NULL) {
1320
1321             float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1322             ptSize = ptrToCoords[0];
1323             VTRACE(("ptSize=%f\n", ptSize));
1324             FIXME("No support for ptSize yet\n");
1325         }
1326
1327         /* Diffuse -------------------------------- */
1328         if (sd->u.s.diffuse.lpData != NULL) {
1329
1330             DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1331             diffuseColor = ptrToCoords[0];
1332             VTRACE(("diffuseColor=%lx\n", diffuseColor));
1333         }
1334
1335         /* Specular  -------------------------------- */
1336         if (sd->u.s.specular.lpData != NULL) {
1337
1338             DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1339             specularColor = ptrToCoords[0];
1340             VTRACE(("specularColor=%lx\n", specularColor));
1341         }
1342
1343         /* Texture coords --------------------------- */
1344         for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1345
1346             if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1347                 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1348                 continue ;
1349             }
1350
1351             /* Query tex coords */
1352             if (This->stateBlock->textures[textureNo] != NULL) {
1353
1354                 int    coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1355                 float *ptrToCoords = NULL;
1356                 float  s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1357
1358                 if (coordIdx > 7) {
1359                     VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1360                     ++texture_idx;
1361                     continue;
1362                 } else if (coordIdx < 0) {
1363                     FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1364                     ++texture_idx;
1365                     continue;
1366                 }
1367
1368                 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1369                 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1370                     TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1371                     ++texture_idx;
1372                     continue;
1373                 } else {
1374
1375                     int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1376
1377                     /* The coords to supply depend completely on the fvf / vertex shader */
1378                     switch (coordsToUse) {
1379                     case 4: q = ptrToCoords[3]; /* drop through */
1380                     case 3: r = ptrToCoords[2]; /* drop through */
1381                     case 2: t = ptrToCoords[1]; /* drop through */
1382                     case 1: s = ptrToCoords[0];
1383                     }
1384
1385                     /* Projected is more 'fun' - Move the last coord to the 'q'
1386                           parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1387                     if ((This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1388                         (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1389
1390                         if (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1391                             switch (coordsToUse) {
1392                             case 0:  /* Drop Through */
1393                             case 1:
1394                                 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1395                                 break;
1396                             case 2:
1397                                 q = t;
1398                                 t = 0.0;
1399                                 coordsToUse = 4;
1400                                 break;
1401                             case 3:
1402                                 q = r;
1403                                 r = 0.0;
1404                                 coordsToUse = 4;
1405                                 break;
1406                             case 4:  /* Nop here */
1407                                 break;
1408                             default:
1409                                 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1410                                       This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1411                             }
1412                         }
1413                     }
1414
1415                     switch (coordsToUse) {   /* Supply the provided texture coords */
1416                     case D3DTTFF_COUNT1:
1417                         VTRACE(("tex:%d, s=%f\n", textureNo, s));
1418                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1419                             GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1420                         } else {
1421                             glTexCoord1f(s);
1422                         }
1423                         break;
1424                     case D3DTTFF_COUNT2:
1425                         VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1426                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1427                             GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1428                         } else {
1429                             glTexCoord2f(s, t);
1430                         }
1431                         break;
1432                     case D3DTTFF_COUNT3:
1433                         VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1434                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1435                             GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1436                         } else {
1437                             glTexCoord3f(s, t, r);
1438                         }
1439                         break;
1440                     case D3DTTFF_COUNT4:
1441                         VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1442                         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1443                             GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1444                         } else {
1445                             glTexCoord4f(s, t, r, q);
1446                         }
1447                         break;
1448                     default:
1449                         FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1450                     }
1451                 }
1452             }
1453             if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]) ++texture_idx;
1454         } /* End of textures */
1455
1456         /* Diffuse -------------------------------- */
1457         if (sd->u.s.diffuse.lpData != NULL) {
1458           glColor4ub(D3DCOLOR_B_R(diffuseColor),
1459                      D3DCOLOR_B_G(diffuseColor),
1460                      D3DCOLOR_B_B(diffuseColor),
1461                      D3DCOLOR_B_A(diffuseColor));
1462             VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n", 
1463                     D3DCOLOR_B_R(diffuseColor),
1464                     D3DCOLOR_B_G(diffuseColor),
1465                     D3DCOLOR_B_B(diffuseColor),
1466                     D3DCOLOR_B_A(diffuseColor)));
1467         } else {
1468             if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1469         }
1470
1471         /* Specular ------------------------------- */
1472         if (sd->u.s.specular.lpData != NULL) {
1473             /* special case where the fog density is stored in the diffuse alpha channel */
1474             if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1475               (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE || sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4 )&&
1476               This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) {
1477                 if(GL_SUPPORT(EXT_FOG_COORD)) {
1478                     GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1479                 } else {
1480                     static BOOL warned = FALSE;
1481                     if(!warned) {
1482                         /* TODO: Use the fog table code from old ddraw */
1483                         FIXME("Implement fog for transformed vertices in software\n");
1484                         warned = TRUE;
1485                     }
1486                 }
1487             }
1488
1489             VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", 
1490                     D3DCOLOR_B_R(specularColor), 
1491                     D3DCOLOR_B_G(specularColor), 
1492                     D3DCOLOR_B_B(specularColor)));
1493             if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1494                 GL_EXTCALL(glSecondaryColor3ubEXT)(
1495                            D3DCOLOR_B_R(specularColor),
1496                            D3DCOLOR_B_G(specularColor),
1497                            D3DCOLOR_B_B(specularColor));
1498             } else {
1499                 /* Do not worry if specular colour missing and disable request */
1500                 VTRACE(("Specular color extensions not supplied\n"));
1501             }
1502         } else {
1503             if (vx_index == 0) {
1504                 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1505                     GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1506                 } else {
1507                     /* Do not worry if specular colour missing and disable request */
1508                     VTRACE(("Specular color extensions not supplied\n"));
1509                 }
1510             }
1511         }
1512
1513         /* Normal -------------------------------- */
1514         if (sd->u.s.normal.lpData != NULL) {
1515             VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1516             glNormal3f(nx, ny, nz);
1517         } else {
1518             if (vx_index == 0) glNormal3f(0, 0, 1);
1519         }
1520
1521         /* Position -------------------------------- */
1522         if (sd->u.s.position.lpData != NULL) {
1523             if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1524                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1525                 glVertex3f(x, y, z);
1526             } else {
1527                 GLfloat w = 1.0 / rhw;
1528                 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1529                 glVertex4f(x*w, y*w, z*w, w);
1530             }
1531         }
1532
1533         /* For non indexed mode, step onto next parts */
1534         if (idxData == NULL) {
1535             ++SkipnStrides;
1536         }
1537     }
1538
1539     glEnd();
1540     checkGLcall("glEnd and previous calls");
1541 }
1542
1543 #if 0 /* TODO: Software/Hardware vertex blending support */
1544 /*
1545  * Draw with emulated vertex shaders
1546  * Note: strided data is uninitialized, as we need to pass the vertex
1547  *     shader directly as ordering irs yet
1548  */
1549 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1550                      int PrimitiveType, ULONG NumPrimitives,
1551                      const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1552
1553     unsigned int               textureNo    = 0;
1554     GLenum                     glPrimType   = GL_POINTS;
1555     int                        NumVertexes  = NumPrimitives;
1556     const short               *pIdxBufS     = NULL;
1557     const long                *pIdxBufL     = NULL;
1558     LONG                       SkipnStrides = 0;
1559     LONG                       vx_index;
1560     float x  = 0.0f, y  = 0.0f, z = 0.0f;  /* x,y,z coordinates          */
1561     float rhw = 0.0f;                      /* rhw                        */
1562     float ptSize = 0.0f;                   /* Point size                 */
1563     D3DVECTOR_4 texcoords[8];              /* Texture Coords             */
1564     int   numcoords[8];                    /* Number of coords           */
1565     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1566
1567     IDirect3DVertexShaderImpl* vertexShader = NULL;
1568
1569     TRACE("Using slow software vertex shader code\n");
1570
1571     /* Variable Initialization */
1572     if (idxData != NULL) {
1573         if (idxSize == 2) pIdxBufS = (const short *) idxData;
1574         else pIdxBufL = (const long *) idxData;
1575     }
1576
1577     /* Ok, Work out which primitive is requested and how many vertexes that will be */
1578     NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1579
1580     /* Retrieve the VS information */
1581     vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1582
1583     /* Start drawing in GL */
1584     VTRACE(("glBegin(%x)\n", glPrimType));
1585     glBegin(glPrimType);
1586
1587     /* For each primitive */
1588     for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1589
1590         /* For indexed data, we need to go a few more strides in */
1591         if (idxData != NULL) {
1592
1593             /* Indexed so work out the number of strides to skip */
1594             if (idxSize == 2) {
1595                 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1596                 SkipnStrides = pIdxBufS[startIdx+vx_index];
1597             } else {
1598                 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1599                 SkipnStrides = pIdxBufL[startIdx+vx_index];
1600             }
1601         }
1602
1603         /* Fill the vertex shader input */
1604         IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1605
1606         /* Initialize the output fields to the same defaults as it would normally have */
1607         memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1608         vertexShader->output.oD[0].x = 1.0;
1609         vertexShader->output.oD[0].y = 1.0;
1610         vertexShader->output.oD[0].z = 1.0;
1611         vertexShader->output.oD[0].w = 1.0;
1612
1613         /* Now execute the vertex shader */
1614         IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1615
1616         /*
1617         TRACE_VECTOR(vertexShader->output.oPos);
1618         TRACE_VECTOR(vertexShader->output.oD[0]);
1619         TRACE_VECTOR(vertexShader->output.oD[1]);
1620         TRACE_VECTOR(vertexShader->output.oT[0]);
1621         TRACE_VECTOR(vertexShader->output.oT[1]);
1622         TRACE_VECTOR(vertexShader->input.V[0]);
1623         TRACE_VECTOR(vertexShader->data->C[0]);
1624         TRACE_VECTOR(vertexShader->data->C[1]);
1625         TRACE_VECTOR(vertexShader->data->C[2]);
1626         TRACE_VECTOR(vertexShader->data->C[3]);
1627         TRACE_VECTOR(vertexShader->data->C[4]);
1628         TRACE_VECTOR(vertexShader->data->C[5]);
1629         TRACE_VECTOR(vertexShader->data->C[6]);
1630         TRACE_VECTOR(vertexShader->data->C[7]);
1631         */
1632
1633         /* Extract out the output */
1634         /* FIXME: Fog coords? */
1635         x = vertexShader->output.oPos.x;
1636         y = vertexShader->output.oPos.y;
1637         z = vertexShader->output.oPos.z;
1638         rhw = vertexShader->output.oPos.w;
1639         ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1640
1641         /** Update textures coords using vertexShader->output.oT[0->7] */
1642         memset(texcoords, 0x00, sizeof(texcoords));
1643         memset(numcoords, 0x00, sizeof(numcoords));
1644         for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1645             if (This->stateBlock->textures[textureNo] != NULL) {
1646                texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1647                texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1648                texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1649                texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1650                if (This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1651                    numcoords[textureNo]    = This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1652                } else {
1653                    switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1654                    case WINED3DRTYPE_TEXTURE:       numcoords[textureNo] = 2; break;
1655                    case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1656                    default:                         numcoords[textureNo] = 4;
1657                    }
1658                }
1659             } else {
1660                 numcoords[textureNo] = 0;
1661             }
1662         }
1663
1664         /* Draw using this information */
1665         draw_vertex(iface,
1666                     TRUE, x, y, z, rhw,
1667                     TRUE, 0.0f, 0.0f, 1.0f,
1668                     TRUE, (float*) &vertexShader->output.oD[0],
1669                     TRUE, (float*) &vertexShader->output.oD[1],
1670                     FALSE, ptSize,         /* FIXME: Change back when supported */
1671                     texcoords, numcoords);
1672
1673         /* For non indexed mode, step onto next parts */
1674         if (idxData == NULL) {
1675            ++SkipnStrides;
1676         }
1677
1678     } /* for each vertex */
1679
1680     glEnd();
1681     checkGLcall("glEnd and previous calls");
1682 }
1683
1684 #endif
1685
1686 inline static void drawPrimitiveDrawStrided(
1687     IWineD3DDevice *iface,
1688     BOOL useVertexShaderFunction,
1689     BOOL usePixelShaderFunction,
1690     WineDirect3DVertexStridedData *dataLocations,
1691     UINT numberOfvertices,
1692     UINT numberOfIndicies,
1693     GLenum glPrimType,
1694     const void *idxData,
1695     short idxSize,
1696     int minIndex,
1697     long StartIdx,
1698     BOOL fixup) {
1699
1700     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1701     BOOL useDrawStridedSlow;
1702
1703     int startStride = idxData == NULL ? 0 : 
1704                       idxData == (void *) -1 ? 0 :
1705                       (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1706     int endStride = startStride;
1707     TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1708         startStride, endStride, numberOfIndicies, numberOfvertices);
1709
1710 /* Generate some fixme's if unsupported functionality is being used */
1711 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1712     /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1713     if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1714         FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1715     }
1716     if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1717         FIXME("Tweening is only valid with vertex shaders\n");
1718     }
1719     if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1720         FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1721     }
1722     if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1723         FIXME("Extended attributes are only valid with vertex shaders\n");
1724     }
1725 #undef BUFFER_OR_DATA
1726
1727     /* Fixed pipeline, no fixups required - load arrays */
1728     if (!useVertexShaderFunction &&
1729        ((dataLocations->u.s.pSize.lpData == NULL &&
1730          dataLocations->u.s.diffuse.lpData == NULL &&
1731          dataLocations->u.s.specular.lpData == NULL) ||
1732          fixup) ) {
1733
1734         /* Load the vertex data using named arrays */
1735         TRACE("(%p) Loading vertex data\n", This);
1736         loadVertexData(iface, dataLocations);
1737         useDrawStridedSlow = FALSE;
1738
1739     /* Shader pipeline - load attribute arrays */
1740     } else if(useVertexShaderFunction) {
1741
1742         loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1743         useDrawStridedSlow = FALSE;
1744
1745     /* Draw vertex by vertex */
1746     } else { 
1747         TRACE("Not loading vertex data\n");
1748         useDrawStridedSlow = TRUE;
1749     }
1750
1751     /* If GLSL is used for either pixel or vertex shaders, make a GLSL program 
1752      * Otherwise set 0, which restores fixed function */
1753     if ((wined3d_settings.vs_selected_mode == SHADER_GLSL && useVertexShaderFunction) ||
1754         (wined3d_settings.ps_selected_mode == SHADER_GLSL && usePixelShaderFunction)) 
1755         set_glsl_shader_program(iface);
1756     else
1757         This->stateBlock->shaderPrgId = 0;
1758
1759     /* If GLSL is used now, or might have been used before, (re)set the program */
1760     if (wined3d_settings.vs_selected_mode == SHADER_GLSL || 
1761         wined3d_settings.ps_selected_mode == SHADER_GLSL) {
1762
1763         if (This->stateBlock->shaderPrgId) 
1764             TRACE_(d3d_shader)("Using GLSL program %u\n", This->stateBlock->shaderPrgId);
1765         GL_EXTCALL(glUseProgramObjectARB(This->stateBlock->shaderPrgId));
1766         checkGLcall("glUseProgramObjectARB");
1767     }
1768         
1769     if (useVertexShaderFunction) {
1770
1771         TRACE("Using vertex shader\n");
1772
1773         if (wined3d_settings.vs_selected_mode == SHADER_ARB) {
1774             /* Bind the vertex program */
1775             GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1776                 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1777             checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1778
1779             /* Enable OpenGL vertex programs */
1780             glEnable(GL_VERTEX_PROGRAM_ARB);
1781             checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1782             TRACE_(d3d_shader)("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1783                 This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1784         }
1785     }
1786
1787     if (usePixelShaderFunction) {
1788
1789         TRACE("Using pixel shader\n");
1790
1791         if (wined3d_settings.ps_selected_mode == SHADER_ARB) {
1792              /* Bind the fragment program */
1793              GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1794                  ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1795              checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1796
1797              /* Enable OpenGL fragment programs */
1798              glEnable(GL_FRAGMENT_PROGRAM_ARB);
1799              checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1800              TRACE_(d3d_shader)("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1801                  This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1802         }
1803         }
1804        
1805     /* Load any global constants/uniforms that may have been set by the application */
1806     if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL)
1807         shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction);
1808     else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB)
1809         shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction); 
1810         
1811     /* Draw vertex-by-vertex */
1812     if (useDrawStridedSlow)
1813         drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex,  StartIdx);
1814     else
1815         drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx);
1816
1817     /* Cleanup vertex program */
1818     if (useVertexShaderFunction) {
1819         /* disable any attribs (this is the same for both GLSL and ARB modes) */
1820         GLint maxAttribs;
1821         int i;
1822         /* Leave all the attribs disabled */
1823         glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
1824         /* MESA does not support it right not */
1825         if (glGetError() != GL_NO_ERROR)
1826             maxAttribs = 16;
1827         for (i = 0; i < maxAttribs; ++i) {
1828             GL_EXTCALL(glDisableVertexAttribArrayARB(i));
1829             checkGLcall("glDisableVertexAttribArrayARB(reg);");
1830         }
1831
1832         if (wined3d_settings.vs_selected_mode == SHADER_ARB)
1833             glDisable(GL_VERTEX_PROGRAM_ARB);
1834     }
1835
1836     /* Cleanup fragment program */
1837     if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB) 
1838         glDisable(GL_FRAGMENT_PROGRAM_ARB);
1839 }
1840
1841 inline void drawPrimitiveTraceDataLocations(
1842     WineDirect3DVertexStridedData *dataLocations) {
1843
1844     /* Dump out what parts we have supplied */
1845     TRACE("Strided Data:\n");
1846     TRACE_STRIDED((dataLocations), position);
1847     TRACE_STRIDED((dataLocations), blendWeights);
1848     TRACE_STRIDED((dataLocations), blendMatrixIndices);
1849     TRACE_STRIDED((dataLocations), normal);
1850     TRACE_STRIDED((dataLocations), pSize);
1851     TRACE_STRIDED((dataLocations), diffuse);
1852     TRACE_STRIDED((dataLocations), specular);
1853     TRACE_STRIDED((dataLocations), texCoords[0]);
1854     TRACE_STRIDED((dataLocations), texCoords[1]);
1855     TRACE_STRIDED((dataLocations), texCoords[2]);
1856     TRACE_STRIDED((dataLocations), texCoords[3]);
1857     TRACE_STRIDED((dataLocations), texCoords[4]);
1858     TRACE_STRIDED((dataLocations), texCoords[5]);
1859     TRACE_STRIDED((dataLocations), texCoords[6]);
1860     TRACE_STRIDED((dataLocations), texCoords[7]);
1861     TRACE_STRIDED((dataLocations), position2);
1862     TRACE_STRIDED((dataLocations), normal2);
1863     TRACE_STRIDED((dataLocations), tangent);
1864     TRACE_STRIDED((dataLocations), binormal);
1865     TRACE_STRIDED((dataLocations), tessFactor);
1866     TRACE_STRIDED((dataLocations), fog);
1867     TRACE_STRIDED((dataLocations), depth);
1868     TRACE_STRIDED((dataLocations), sample);
1869
1870     return;
1871
1872 }
1873
1874 static void drawPrimitiveUploadTexturesPS(IWineD3DDeviceImpl* This) {
1875     INT i;
1876
1877     for (i = 0; i < GL_LIMITS(samplers); ++i) {
1878         /* Pixel shader support should imply multitexture support. */
1879         if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1880             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1881             checkGLcall("glActiveTextureARB");
1882         } else if (i) {
1883             WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1884         }
1885
1886         if (!This->stateBlock->textures[i]) continue;
1887
1888         /* Enable the correct target. Is this required for GLSL? For ARB_fragment_program it isn't, afaik. */
1889         glDisable(GL_TEXTURE_1D);
1890         This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1891         switch(This->stateBlock->textureDimensions[i]) {
1892             case GL_TEXTURE_2D:
1893                 glDisable(GL_TEXTURE_3D);
1894                 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1895                 break;
1896             case GL_TEXTURE_3D:
1897                 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1898                 glDisable(GL_TEXTURE_2D);
1899                 break;
1900             case GLTEXTURECUBEMAP:
1901                 glDisable(GL_TEXTURE_2D);
1902                 glDisable(GL_TEXTURE_3D);
1903                 break;
1904         }
1905         glEnable(This->stateBlock->textureDimensions[i]);
1906
1907         /* Upload texture, apply states */
1908         IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1909         IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, i, REAPPLY_ALPHAOP);
1910         IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1911     }
1912 }
1913
1914 /* uploads textures and setup texture states ready for rendering */
1915 static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1916     INT current_sampler = 0;
1917     float constant_color[4];
1918     unsigned int i;
1919
1920     /* ARB_texture_env_combine is limited to GL_MAX_TEXTURE_UNITS stages. On
1921      * nVidia cards GL_MAX_TEXTURE_UNITS is generally not larger than 4.
1922      * Register combiners however provide up to 8 combiner stages. In order to
1923      * take advantage of this, we need to be separate D3D texture stages from
1924      * GL texture units. When using register combiners GL_MAX_TEXTURE_UNITS
1925      * corresponds to MaxSimultaneousTextures and GL_MAX_GENERAL_COMBINERS_NV
1926      * corresponds to MaxTextureBlendStages in the caps. */
1927
1928     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1929         glEnable(GL_REGISTER_COMBINERS_NV);
1930         D3DCOLORTOGLFLOAT4(This->stateBlock->renderState[WINED3DRS_TEXTUREFACTOR], constant_color);
1931         GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &constant_color[0]));
1932     }
1933
1934     for (i = 0; i < GL_LIMITS(texture_stages); ++i) {
1935         INT texture_idx = -1;
1936
1937         /* D3DTOP_DISABLE disables the current & any higher texture stages */
1938         if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] == D3DTOP_DISABLE) break;
1939
1940         if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[i]) {
1941             texture_idx = current_sampler++;
1942
1943             /* Active the texture unit corresponding to the current texture stage */
1944             if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1945                 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1946                 checkGLcall("glActiveTextureARB");
1947             } else if (i) {
1948                 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1949             }
1950         }
1951
1952         if (This->stateBlock->textures[i]) {
1953             /* Enable the correct target. */
1954             glDisable(GL_TEXTURE_1D);
1955             This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1956             switch(This->stateBlock->textureDimensions[i]) {
1957                 case GL_TEXTURE_2D:
1958                     glDisable(GL_TEXTURE_3D);
1959                     glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1960                     break;
1961                 case GL_TEXTURE_3D:
1962                     glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1963                     glDisable(GL_TEXTURE_2D);
1964                     break;
1965                 case GLTEXTURECUBEMAP:
1966                     glDisable(GL_TEXTURE_2D);
1967                     glDisable(GL_TEXTURE_3D);
1968                     break;
1969             }
1970
1971             /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
1972             if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
1973                 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1974             } else {
1975                 glEnable(This->stateBlock->textureDimensions[i]);
1976             }
1977
1978             /* Upload texture, apply states */
1979             IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1980             IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, texture_idx, REAPPLY_ALPHAOP);
1981             IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1982         } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1983             /* ARB_texture_env_combine needs a valid texture bound to the
1984              * texture unit, even if it isn't used. Bind a dummy texture. */
1985             glDisable(GL_TEXTURE_2D);
1986             glDisable(GL_TEXTURE_3D);
1987             glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1988             glEnable(GL_TEXTURE_1D);
1989             This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
1990             glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
1991         }
1992
1993         /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
1994           dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
1995         if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1996             set_tex_op_nvrc((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
1997                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
1998                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
1999                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG0],
2000                     texture_idx);
2001             /* alphaop */
2002             set_tex_op_nvrc((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2003                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2004                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2005                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0],
2006                     texture_idx);
2007         } else {
2008             set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
2009                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
2010                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
2011                     This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
2012             /* alphaop */
2013             set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
2014                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
2015                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
2016                     This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
2017         }
2018     }
2019
2020     /* If we're using register combiners, set the amount of *used* combiners.
2021      * Ie, the number of stages below the first stage to have a color op of
2022      * D3DTOP_DISABLE. */
2023     if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2024         /* NUM_GENERAL_COMBINERS_NV should be > 0 */
2025         if (!i) glDisable(GL_REGISTER_COMBINERS_NV);
2026         else GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, i));
2027     }
2028
2029     /* Disable the remaining texture units. */
2030     for (i = current_sampler; i < GL_LIMITS(textures); ++i) {
2031         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2032         glDisable(GL_TEXTURE_1D);
2033         glDisable(GL_TEXTURE_2D);
2034         glDisable(GL_TEXTURE_3D);
2035         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2036     }
2037 }
2038
2039 /* Routine common to the draw primitive and draw indexed primitive routines */
2040 void drawPrimitive(IWineD3DDevice *iface,
2041                    int PrimitiveType,
2042                    long NumPrimitives,
2043                    /* for Indexed: */
2044                    long  StartVertexIndex,
2045                    UINT  numberOfVertices,
2046                    long  StartIdx,
2047                    short idxSize,
2048                    const void *idxData,
2049                    int   minIndex,
2050                    WineDirect3DVertexStridedData *DrawPrimStrideData) {
2051
2052     IWineD3DDeviceImpl           *This = (IWineD3DDeviceImpl *)iface;
2053     BOOL                          useVertexShaderFunction = FALSE;
2054     BOOL                          usePixelShaderFunction = FALSE;
2055     WineDirect3DVertexStridedData *dataLocations;
2056     IWineD3DSwapChainImpl         *swapchain;
2057     int                           i;
2058     BOOL                          fixup = FALSE;
2059
2060     BOOL lighting_changed, lighting_original = FALSE;
2061
2062     /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software - 
2063      * here simply check whether a shader was set, or the user disabled shaders */
2064     if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader && 
2065         ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL) 
2066         useVertexShaderFunction = TRUE;
2067
2068     if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
2069         ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) 
2070         usePixelShaderFunction = TRUE;
2071
2072     /* Invalidate the back buffer memory so LockRect will read it the next time */
2073     for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
2074         IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
2075         if(swapchain) {
2076             if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
2077             IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2078         }
2079     }
2080
2081     /* Ok, we will be updating the screen from here onwards so grab the lock */
2082     ENTER_GL();
2083
2084     if(DrawPrimStrideData) {
2085
2086         /* Note: this is a ddraw fixed-function code path */
2087
2088         TRACE("================ Strided Input ===================\n");
2089         dataLocations = DrawPrimStrideData;
2090         drawPrimitiveTraceDataLocations(dataLocations);
2091         fixup = FALSE;
2092     }
2093
2094     else if (This->stateBlock->vertexDecl != NULL || useVertexShaderFunction) {
2095
2096         /* Note: This is a fixed function or shader codepath.
2097          * This means it must handle both types of strided data.
2098          * Shaders must go through here to zero the strided data, even if they
2099          * don't set any declaration at all */
2100
2101         TRACE("================ Vertex Declaration  ===================\n");
2102         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2103         if(!dataLocations) {
2104             ERR("Out of memory!\n");
2105             return;
2106         }
2107
2108         if (This->stateBlock->vertexDecl != NULL ||
2109             ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration != NULL)            
2110
2111             primitiveDeclarationConvertToStridedData(iface, useVertexShaderFunction, 
2112                 dataLocations, StartVertexIndex, &fixup);
2113
2114     } else {
2115
2116         /* Note: This codepath is not reachable from d3d9 (see fvf->decl9 conversion)
2117          * It is reachable through d3d8, but only for fixed-function.
2118          * It will not work properly for shaders. */
2119
2120         TRACE("================ FVF ===================\n");
2121         dataLocations = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dataLocations));
2122         if(!dataLocations) {
2123             ERR("Out of memory!\n");
2124             return;
2125         }
2126         primitiveConvertToStridedData(iface, dataLocations, StartVertexIndex, &fixup);
2127         drawPrimitiveTraceDataLocations(dataLocations);
2128     }
2129
2130     /* Setup transform matrices and sort out */
2131     primitiveInitState(iface, dataLocations, useVertexShaderFunction, &lighting_changed, &lighting_original);
2132
2133     /* Now initialize the materials state */
2134     init_materials(iface, (dataLocations->u.s.diffuse.lpData != NULL || dataLocations->u.s.diffuse.VBO != 0));
2135
2136     if (usePixelShaderFunction) {
2137         drawPrimitiveUploadTexturesPS(This);
2138     } else {
2139         drawPrimitiveUploadTextures(This);
2140     }
2141
2142     {
2143         GLenum glPrimType;
2144         /* Ok, Work out which primitive is requested and how many vertexes that
2145            will be                                                              */
2146         UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2147         if (numberOfVertices == 0 )
2148             numberOfVertices = calculatedNumberOfindices;
2149
2150         drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
2151             dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType,
2152             idxData, idxSize, minIndex, StartIdx, fixup);
2153     }
2154
2155     if(!DrawPrimStrideData) HeapFree(GetProcessHeap(), 0, dataLocations);
2156
2157     /* If vertex shaders or no normals, restore previous lighting state */
2158     if (lighting_changed) {
2159         if (lighting_original) glEnable(GL_LIGHTING);
2160         else glDisable(GL_LIGHTING);
2161         TRACE("Restored lighting to original state\n");
2162     }
2163
2164     /* Finshed updating the screen, restore lock */
2165     LEAVE_GL();
2166     TRACE("Done all gl drawing\n");
2167
2168     /* Diagnostics */
2169 #ifdef SHOW_FRAME_MAKEUP
2170     {
2171         static long int primCounter = 0;
2172         /* NOTE: set primCounter to the value reported by drawprim 
2173            before you want to to write frame makeup to /tmp */
2174         if (primCounter >= 0) {
2175             WINED3DLOCKED_RECT r;
2176             char buffer[80];
2177             IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
2178             sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
2179             TRACE("Saving screenshot %s\n", buffer);
2180             IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2181             IWineD3DSurface_UnlockRect(This->renderTarget);
2182
2183 #ifdef SHOW_TEXTURE_MAKEUP
2184            {
2185             IWineD3DSurface *pSur;
2186             int textureNo;
2187             for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2188                 if (This->stateBlock->textures[textureNo] != NULL) {
2189                     sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2190                     TRACE("Saving texture %s\n", buffer);
2191                     if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
2192                             IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2193                             IWineD3DSurface_SaveSnapshot(pSur, buffer);
2194                             IWineD3DSurface_Release(pSur);
2195                     } else  {
2196                         FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2197                     }
2198                 }
2199             }
2200            }
2201 #endif
2202         }
2203         TRACE("drawprim #%ld\n", primCounter);
2204         ++primCounter;
2205     }
2206 #endif
2207 }