2 * WINED3D draw functions
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wined3d_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
28 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
31 #ifdef SHOW_FRAME_MAKEUP
36 extern IWineD3DVertexShaderImpl* VertexShaders[64];
37 extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64];
38 extern IWineD3DPixelShaderImpl* PixelShaders[64];
40 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
43 /* Returns bits for what is expected from the fixed function pipeline, and whether
44 a vertex shader will be in use. Note the fvf bits returned may be split over
45 multiple streams only if the vertex shader was created, otherwise it all relates
47 static BOOL initializeFVF(IWineD3DDevice *iface, DWORD *FVFbits)
50 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
52 #if 0 /* TODO: d3d8 call setvertexshader needs to set the FVF in the state block when implemented */
53 /* The first thing to work out is if we are using the fixed function pipeline
54 which is either SetVertexShader with < VS_HIGHESTFIXEDFXF - in which case this
55 is the FVF, or with a shader which was created with no function - in which
56 case there is an FVF per declared stream. If this occurs, we also maintain
57 an 'OR' of all the FVF's together so we know what to expect across all the
60 *FVFbits = This->stateBlock->fvf;
62 *FVFbits = This->stateBlock->vertexShaderDecl->allFVF;
67 /* Issues the glBegin call for gl given the primitive type and count */
68 static DWORD primitiveToGl(D3DPRIMITIVETYPE PrimitiveType,
72 DWORD NumVertexes = NumPrimitives;
74 switch (PrimitiveType) {
77 *primType = GL_POINTS;
78 NumVertexes = NumPrimitives;
84 NumVertexes = NumPrimitives * 2;
88 TRACE("LINE_STRIP\n");
89 *primType = GL_LINE_STRIP;
90 NumVertexes = NumPrimitives + 1;
93 case D3DPT_TRIANGLELIST:
95 *primType = GL_TRIANGLES;
96 NumVertexes = NumPrimitives * 3;
99 case D3DPT_TRIANGLESTRIP:
100 TRACE("TRIANGLE_STRIP\n");
101 *primType = GL_TRIANGLE_STRIP;
102 NumVertexes = NumPrimitives + 2;
105 case D3DPT_TRIANGLEFAN:
106 TRACE("TRIANGLE_FAN\n");
107 *primType = GL_TRIANGLE_FAN;
108 NumVertexes = NumPrimitives + 2;
112 FIXME("Unhandled primitive\n");
113 *primType = GL_POINTS;
119 /* Ensure the appropriate material states are set up - only change
120 state if really required */
121 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
123 BOOL requires_material_reset = FALSE;
124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
126 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
127 /* If we have not set up the material color tracking, do it now as required */
128 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
129 checkGLcall("glDisable GL_COLOR_MATERIAL");
130 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
131 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
132 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
133 glEnable(GL_COLOR_MATERIAL);
134 checkGLcall("glEnable GL_COLOR_MATERIAL");
135 This->tracking_color = IS_TRACKING;
136 requires_material_reset = TRUE; /* Restore material settings as will be used */
138 } else if ((This->tracking_color == IS_TRACKING && isDiffuseSupplied == FALSE) ||
139 (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied == FALSE)) {
140 /* If we are tracking the current color but one isn't supplied, don't! */
141 glDisable(GL_COLOR_MATERIAL);
142 checkGLcall("glDisable GL_COLOR_MATERIAL");
143 This->tracking_color = NEEDS_TRACKING;
144 requires_material_reset = TRUE; /* Restore material settings as will be used */
146 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
147 /* No need to reset material colors since no change to gl_color_material */
148 requires_material_reset = FALSE;
150 } else if (This->tracking_color == NEEDS_DISABLE) {
151 glDisable(GL_COLOR_MATERIAL);
152 checkGLcall("glDisable GL_COLOR_MATERIAL");
153 This->tracking_color = DISABLED_TRACKING;
154 requires_material_reset = TRUE; /* Restore material settings as will be used */
157 /* Reset the material colors which may have been tracking the color*/
158 if (requires_material_reset) {
159 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
160 checkGLcall("glMaterialfv");
161 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
162 checkGLcall("glMaterialfv");
163 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
164 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
165 checkGLcall("glMaterialfv");
167 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
168 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
169 checkGLcall("glMaterialfv");
171 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
172 checkGLcall("glMaterialfv");
177 static GLfloat invymat[16] = {
178 1.0f, 0.0f, 0.0f, 0.0f,
179 0.0f, -1.0f, 0.0f, 0.0f,
180 0.0f, 0.0f, 1.0f, 0.0f,
181 0.0f, 0.0f, 0.0f, 1.0f};
183 /* Setup views - Transformed & lit if RHW, else untransformed.
184 Only unlit if Normals are supplied
185 Returns: Whether to restore lighting afterwards */
186 static BOOL primitiveInitState(IWineD3DDevice *iface, BOOL vtx_transformed, BOOL vtx_lit, BOOL useVS) {
188 BOOL isLightingOn = FALSE;
189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
191 /* If no normals, DISABLE lighting otherwise, don't touch lighing as it is
192 set by the appropriate render state. Note Vertex Shader output is already lit */
193 if (vtx_lit || useVS) {
194 isLightingOn = glIsEnabled(GL_LIGHTING);
195 glDisable(GL_LIGHTING);
196 checkGLcall("glDisable(GL_LIGHTING);");
197 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
200 if (!useVS && vtx_transformed) {
202 /* If the last draw was transformed as well, no need to reapply all the matrixes */
203 if (!This->last_was_rhw) {
205 double X, Y, height, width, minZ, maxZ;
206 This->last_was_rhw = TRUE;
208 /* Transformed already into viewport coordinates, so we do not need transform
209 matrices. Reset all matrices to identity and leave the default matrix in world
211 glMatrixMode(GL_MODELVIEW);
212 checkGLcall("glMatrixMode(GL_MODELVIEW)");
214 checkGLcall("glLoadIdentity");
216 glMatrixMode(GL_PROJECTION);
217 checkGLcall("glMatrixMode(GL_PROJECTION)");
219 checkGLcall("glLoadIdentity");
221 /* Set up the viewport to be full viewport */
222 X = This->stateBlock->viewport.X;
223 Y = This->stateBlock->viewport.Y;
224 height = This->stateBlock->viewport.Height;
225 width = This->stateBlock->viewport.Width;
226 minZ = This->stateBlock->viewport.MinZ;
227 maxZ = This->stateBlock->viewport.MaxZ;
228 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
229 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
230 checkGLcall("glOrtho");
232 /* Window Coord 0 is the middle of the first pixel, so translate by half
233 a pixel (See comment above glTranslate below) */
234 glTranslatef(0.5, 0.5, 0);
235 checkGLcall("glTranslatef(0.5, 0.5, 0)");
236 if (This->renderUpsideDown) {
237 glMultMatrixf(invymat);
238 checkGLcall("glMultMatrixf(invymat)");
244 /* Untransformed, so relies on the view and projection matrices */
246 if (!useVS && (This->last_was_rhw || !This->modelview_valid)) {
247 /* Only reapply when have to */
248 This->modelview_valid = TRUE;
249 glMatrixMode(GL_MODELVIEW);
250 checkGLcall("glMatrixMode");
252 /* In the general case, the view matrix is the identity matrix */
253 if (This->view_ident) {
254 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
255 checkGLcall("glLoadMatrixf");
257 glLoadMatrixf((float *) &This->stateBlock->transforms[D3DTS_VIEW].u.m[0][0]);
258 checkGLcall("glLoadMatrixf");
259 glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_WORLDMATRIX(0)].u.m[0][0]);
260 checkGLcall("glMultMatrixf");
264 if (!useVS && (This->last_was_rhw || !This->proj_valid)) {
265 /* Only reapply when have to */
266 This->proj_valid = TRUE;
267 glMatrixMode(GL_PROJECTION);
268 checkGLcall("glMatrixMode");
270 /* The rule is that the window coordinate 0 does not correspond to the
271 beginning of the first pixel, but the center of the first pixel.
272 As a consequence if you want to correctly draw one line exactly from
273 the left to the right end of the viewport (with all matrices set to
274 be identity), the x coords of both ends of the line would be not
275 -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width)
279 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
280 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
282 if (This->renderUpsideDown) {
283 glMultMatrixf(invymat);
284 checkGLcall("glMultMatrixf(invymat)");
286 glMultMatrixf((float *) &This->stateBlock->transforms[D3DTS_PROJECTION].u.m[0][0]);
287 checkGLcall("glLoadMatrixf");
290 /* Vertex Shader output is already transformed, so set up identity matrices */
291 /* FIXME: Actually, only true for software emulated ones, so when h/w ones
292 come along this needs to take into account whether s/w ones were
295 glMatrixMode(GL_MODELVIEW);
296 checkGLcall("glMatrixMode");
298 glMatrixMode(GL_PROJECTION);
299 checkGLcall("glMatrixMode");
301 /* Window Coord 0 is the middle of the first pixel, so translate by half
302 a pixel (See comment above glTranslate above) */
303 glTranslatef(0.9 / This->stateBlock->viewport.Width, -0.9 / This->stateBlock->viewport.Height, 0);
304 checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)");
305 if (This->renderUpsideDown) {
306 glMultMatrixf(invymat);
307 checkGLcall("glMultMatrixf(invymat)");
309 This->modelview_valid = FALSE;
310 This->proj_valid = FALSE;
312 This->last_was_rhw = FALSE;
317 void primitiveDeclarationConvertToStridedData(IWineD3DDevice *iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex, DWORD *fvf) {
318 /* We need to deal with frequency data!*/
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DVertexDeclarationImpl* vertexDeclaration = (IWineD3DVertexDeclarationImpl*)This->stateBlock->vertexDecl;
325 D3DVERTEXELEMENT9 *element;
327 for (i = 0 ; i < vertexDeclaration->declaration9NumElements - 1; ++i) {
329 element = vertexDeclaration->pDeclaration9 + i;
330 TRACE("%p Elements %p %d or %d\n", vertexDeclaration->pDeclaration9, element, i, vertexDeclaration->declaration9NumElements);
331 if (This->stateBlock->streamIsUP) {
332 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
333 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
335 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
336 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0);
338 stride = This->stateBlock->streamStride[element->Stream];
339 data += (BaseVertexIndex * stride);
340 data += element->Offset;
341 /* Why can't I just use a lookup table instead of a switch statment? */
342 switch (element->Usage) {
343 case D3DDECLUSAGE_POSITION:
344 switch (element->UsageIndex) {
345 case 0: /* N-patch */
346 strided->u.s.position.lpData = data;
347 strided->u.s.position.dwType = element->Type;
348 strided->u.s.position.dwStride = stride;
350 case 1: /* tweened see http://www.gamedev.net/reference/articles/article2017.asp */
351 TRACE("Tweened positions\n");
352 strided->u.s.position2.lpData = data;
353 strided->u.s.position2.dwType = element->Type;
354 strided->u.s.position2.dwStride = stride;
358 case D3DDECLUSAGE_NORMAL:
359 switch (element->UsageIndex) {
360 case 0: /* N-patch */
361 strided->u.s.normal.lpData = data;
362 strided->u.s.normal.dwType = element->Type;
363 strided->u.s.normal.dwStride = stride;
365 case 1: /* skinning */
366 TRACE("Skinning / tween normals\n");
367 strided->u.s.normal2.lpData = data;
368 strided->u.s.normal2.dwType = element->Type;
369 strided->u.s.normal2.dwStride = stride;
372 *fvf |= D3DFVF_NORMAL;
374 case D3DDECLUSAGE_BLENDINDICES:
375 /* demo @http://www.ati.com/developer/vertexblend.html
376 and http://www.flipcode.com/articles/article_dx8shaders.shtml
378 strided->u.s.blendMatrixIndices.lpData = data;
379 strided->u.s.blendMatrixIndices.dwType = element->Type;
380 strided->u.s.blendMatrixIndices.dwStride= stride;
382 case D3DDECLUSAGE_BLENDWEIGHT:
383 strided->u.s.blendWeights.lpData = data;
384 strided->u.s.blendWeights.dwType = element->Type;
385 strided->u.s.blendWeights.dwStride = stride;
387 case D3DDECLUSAGE_PSIZE:
388 strided->u.s.pSize.lpData = data;
389 strided->u.s.pSize.dwType = element->Type;
390 strided->u.s.pSize.dwStride = stride;
392 case D3DDECLUSAGE_COLOR:
393 switch (element->UsageIndex) {
395 strided->u.s.diffuse.lpData = data;
396 strided->u.s.diffuse.dwType = element->Type;
397 strided->u.s.diffuse.dwStride = stride;
399 case 1: /* specular */
400 strided->u.s.specular.lpData = data;
401 strided->u.s.specular.dwType = element->Type;
402 strided->u.s.specular.dwStride = stride;
406 case D3DDECLUSAGE_TEXCOORD:
407 /* For some odd reason Microsoft decided to sum usage accross all the streams,
408 which means we need to do a count and not just use the usage number */
410 strided->u.s.texCoords[textureNo].lpData = data;
411 strided->u.s.texCoords[textureNo].dwType = element->Type;
412 strided->u.s.texCoords[textureNo].dwStride = stride;
416 case D3DDECLUSAGE_TANGENT:
417 /* Implement tangents and binormals using http://oss.sgi.com/projects/ogl-sample/registry/EXT/coordinate_frame.txt
418 this is easy so long as the OpenGL implementation supports it, otherwise drop back to calculating the
419 normal using tangents where no normal data has been provided */
421 strided->u.s.tangent.lpData = data;
422 strided->u.s.tangent.dwType = element->Type;
423 strided->u.s.tangent.dwStride = stride;
425 case D3DDECLUSAGE_BINORMAL:
426 /* Binormals are really bitangents perpendicular to the normal but s-aligned to the tangent, basically they are the vectors of any two lines on the plain at right angles to the normal and at right angles to each other, like the x,y,z axis.
427 tangent data makes it easier to perform some calculations (a bit like using 2d graph paper instead of the normal of the piece of paper)
428 The only thing they are useful for in fixed function would be working out normals when none are given.
430 TRACE("BI-Normal\n");
431 strided->u.s.binormal.lpData = data;
432 strided->u.s.binormal.dwType = element->Type;
433 strided->u.s.binormal.dwStride = stride;
435 case D3DDECLUSAGE_TESSFACTOR:
436 /* a google for D3DDECLUSAGE_TESSFACTOR turns up a whopping 36 entries, 7 of which are from MSDN.
438 TRACE("Tess Factor\n");
439 strided->u.s.tessFactor.lpData = data;
440 strided->u.s.tessFactor.dwType = element->Type;
441 strided->u.s.tessFactor.dwStride = stride;
443 case D3DDECLUSAGE_POSITIONT:
445 switch (element->UsageIndex) {
446 case 0: /* N-patch */
447 strided->u.s.position.lpData = data;
448 strided->u.s.position.dwType = element->Type;
449 strided->u.s.position.dwStride = stride;
451 case 1: /* skinning */
452 /* see http://rsn.gamedev.net/tutorials/ms3danim.asp
453 http://xface.blogspot.com/2004_08_01_xface_archive.html
455 TRACE("Skinning positionsT\n");
456 strided->u.s.position2.lpData = data;
457 strided->u.s.position2.dwType = element->Type;
458 strided->u.s.position2.dwStride = stride;
461 /* TODO: change fvf usage to a plain boolean flag */
462 *fvf |= D3DFVF_XYZRHW;
463 /* FIXME: were faking this flag so that we don't transform the data again */
465 case D3DDECLUSAGE_FOG:
466 /* maybe GL_EXT_fog_coord ?
467 * http://oss.sgi.com/projects/ogl-sample/registry/EXT/fog_coord.txt
468 * This extension allows specifying an explicit per-vertex fog
469 * coordinate to be used in fog computations, rather than using a
470 * fragment depth-based fog equation.
474 strided->u.s.fog.lpData = data;
475 strided->u.s.fog.dwType = element->Type;
476 strided->u.s.fog.dwStride = stride;
478 case D3DDECLUSAGE_DEPTH:
480 strided->u.s.depth.lpData = data;
481 strided->u.s.depth.dwType = element->Type;
482 strided->u.s.depth.dwStride = stride;
484 case D3DDECLUSAGE_SAMPLE: /* VertexShader textures */
486 strided->u.s.sample.lpData = data;
487 strided->u.s.sample.dwType = element->Type;
488 strided->u.s.sample.dwStride = stride;
496 static void primitiveConvertToStridedData(IWineD3DDevice *iface, Direct3DVertexStridedData *strided, LONG BaseVertexIndex) {
498 short LoopThroughTo = 0;
503 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
504 int numCoords[8]; /* Holding place for D3DFVF_TEXTUREFORMATx */
506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
508 /* OK, Now to setup the data locations
509 For the non-created vertex shaders, the VertexShader var holds the real
510 FVF and only stream 0 matters
511 For the created vertex shaders, there is an FVF per stream */
512 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
513 LoopThroughTo = MAX_STREAMS;
518 /* Work through stream by stream */
519 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
520 DWORD stride = This->stateBlock->streamStride[nStream];
524 /* Skip empty streams */
525 if (This->stateBlock->streamSource[nStream] == NULL) continue;
527 /* Retrieve appropriate FVF */
528 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
529 thisFVF = This->stateBlock->fvf;
530 /* Handle memory passed directly as well as vertex buffers */
531 if (This->stateBlock->streamIsUP) {
532 data = (BYTE *)This->stateBlock->streamSource[nStream];
534 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
537 #if 0 /* TODO: Vertex shader support */
538 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
539 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
542 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
543 if (thisFVF == 0) continue;
545 /* Now convert the stream into pointers */
547 /* Shuffle to the beginning of the vertexes to render and index from there */
548 data = data + (BaseVertexIndex * stride);
550 /* Either 3 or 4 floats depending on the FVF */
551 /* FIXME: Can blending data be in a different stream to the position data?
552 and if so using the fixed pipeline how do we handle it */
553 if (thisFVF & D3DFVF_POSITION_MASK) {
554 strided->u.s.position.lpData = data;
555 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT3;
556 strided->u.s.position.dwStride = stride;
557 data += 3 * sizeof(float);
558 if (thisFVF & D3DFVF_XYZRHW) {
559 strided->u.s.position.dwType = D3DDECLTYPE_FLOAT4;
560 data += sizeof(float);
564 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
565 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
566 numBlends = 1 + (((thisFVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
567 if(thisFVF & D3DFVF_LASTBETA_UBYTE4) numBlends--;
569 if ((thisFVF & D3DFVF_XYZB5 ) > D3DFVF_XYZRHW) {
570 TRACE("Setting blend Weights to %p\n", data);
571 strided->u.s.blendWeights.lpData = data;
572 strided->u.s.blendWeights.dwType = D3DDECLTYPE_FLOAT1 + numBlends - 1;
573 strided->u.s.blendWeights.dwStride = stride;
574 data += numBlends * sizeof(FLOAT);
576 if (thisFVF & D3DFVF_LASTBETA_UBYTE4) {
577 strided->u.s.blendMatrixIndices.lpData = data;
578 strided->u.s.blendMatrixIndices.dwType = D3DDECLTYPE_UBYTE4;
579 strided->u.s.blendMatrixIndices.dwStride= stride;
580 data += sizeof(DWORD);
584 /* Normal is always 3 floats */
585 if (thisFVF & D3DFVF_NORMAL) {
586 strided->u.s.normal.lpData = data;
587 strided->u.s.normal.dwType = D3DDECLTYPE_FLOAT3;
588 strided->u.s.normal.dwStride = stride;
589 data += 3 * sizeof(FLOAT);
592 /* Pointsize is a single float */
593 if (thisFVF & D3DFVF_PSIZE) {
594 strided->u.s.pSize.lpData = data;
595 strided->u.s.pSize.dwType = D3DDECLTYPE_FLOAT1;
596 strided->u.s.pSize.dwStride = stride;
597 data += sizeof(FLOAT);
600 /* Diffuse is 4 unsigned bytes */
601 if (thisFVF & D3DFVF_DIFFUSE) {
602 strided->u.s.diffuse.lpData = data;
603 strided->u.s.diffuse.dwType = D3DDECLTYPE_SHORT4;
604 strided->u.s.diffuse.dwStride = stride;
605 data += sizeof(DWORD);
608 /* Specular is 4 unsigned bytes */
609 if (thisFVF & D3DFVF_SPECULAR) {
610 strided->u.s.specular.lpData = data;
611 strided->u.s.specular.dwType = D3DDECLTYPE_SHORT4;
612 strided->u.s.specular.dwStride = stride;
613 data += sizeof(DWORD);
617 numTextures = (thisFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
618 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of D3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
620 /* numTextures indicates the number of texture coordinates supplied */
621 /* However, the first set may not be for stage 0 texture - it all */
622 /* depends on D3DTSS_TEXCOORDINDEX. */
623 /* The number of bytes for each coordinate set is based off */
624 /* D3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
626 /* So, for each supplied texture extract the coords */
627 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
629 strided->u.s.texCoords[textureNo].lpData = data;
630 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT1;
631 strided->u.s.texCoords[textureNo].dwStride = stride;
632 numCoords[textureNo] = coordIdxInfo & 0x03;
635 data += sizeof(float);
636 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT1) {
637 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT2;
638 data += sizeof(float);
639 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT2) {
640 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT3;
641 data += sizeof(float);
642 if (numCoords[textureNo] != D3DFVF_TEXTUREFORMAT3) {
643 strided->u.s.texCoords[textureNo].dwType = D3DDECLTYPE_FLOAT4;
644 data += sizeof(float);
648 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
653 #if 0 /* TODO: Software Shaders */
654 /* Draw a single vertex using this information */
655 static void draw_vertex(IWineD3DDevice *iface, /* interface */
656 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
657 BOOL isNormal, float nx, float ny, float nz, /* normal */
658 BOOL isDiffuse, float *dRGBA, /* 1st colors */
659 BOOL isSpecular, float *sRGB, /* 2ndry colors */
660 BOOL isPtSize, float ptSize, /* pointSize */
661 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
663 unsigned int textureNo;
665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
667 /* Diffuse -------------------------------- */
670 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
673 /* Specular Colour ------------------------------------------*/
675 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
676 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
677 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
679 VTRACE(("Specular color extensions not supplied\n"));
683 /* Normal -------------------------------- */
685 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
686 glNormal3f(nx, ny, nz);
689 /* Point Size ----------------------------------------------*/
692 /* no such functionality in the fixed function GL pipeline */
693 FIXME("Cannot change ptSize here in openGl\n");
696 /* Texture coords --------------------------- */
697 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
699 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
700 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
704 /* Query tex coords */
705 if (This->stateBlock->textures[textureNo] != NULL) {
707 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
708 if (coordIdx >= MAX_TEXTURES) {
709 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
711 } else if (numcoords[coordIdx] == 0) {
712 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
716 /* Initialize vars */
722 switch (numcoords[coordIdx]) {
723 case 4: q = texcoords[coordIdx].w; /* drop through */
724 case 3: r = texcoords[coordIdx].z; /* drop through */
725 case 2: t = texcoords[coordIdx].y; /* drop through */
726 case 1: s = texcoords[coordIdx].x;
729 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
731 VTRACE(("tex:%d, s=%f\n", textureNo, s));
732 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
733 GLMULTITEXCOORD1F(textureNo, s);
739 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
740 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
741 GLMULTITEXCOORD2F(textureNo, s, t);
747 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
748 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
749 GLMULTITEXCOORD3F(textureNo, s, t, r);
751 glTexCoord3f(s, t, r);
755 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
756 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
757 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
759 glTexCoord4f(s, t, r, q);
763 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
767 } /* End of textures */
769 /* Position -------------------------------- */
771 if (1.0f == rhw || rhw < 0.00001f) {
772 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
775 /* Cannot optimize by dividing through by rhw as rhw is required
776 later for perspective in the GL pipeline for vertex shaders */
777 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
778 glVertex4f(x,y,z,rhw);
782 #endif /* TODO: Software shaders */
784 void loadNumberedArrays(IWineD3DDevice *iface, Direct3DVertexStridedData *sd, INT arrayUsageMap[WINED3DSHADERDECLUSAGE_MAX_USAGE]) {
785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
787 #define LOAD_NUMBERED_ARRAY(_arrayName, _lookupName) \
788 if (sd->u.s._arrayName.lpData != NULL && ((arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName] & 0x7FFF) == arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName])) { \
789 TRACE_(d3d_shader)("Loading array %u with data from %s\n", arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName], #_arrayName); \
790 GL_EXTCALL(glVertexAttribPointerARB(arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName], \
791 WINED3D_ATR_SIZE(_arrayName), \
792 WINED3D_ATR_GLTYPE(_arrayName), \
793 WINED3D_ATR_NORMALIZED(_arrayName), \
794 sd->u.s._arrayName.dwStride, \
795 sd->u.s._arrayName.lpData)); \
796 GL_EXTCALL(glEnableVertexAttribArrayARB(arrayUsageMap[WINED3DSHADERDECLUSAGE_##_lookupName])); \
800 #define LOAD_NUMBERED_POSITION_ARRAY(_lookupNumber) \
801 if (sd->u.s.position2.lpData != NULL && ((arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber] & 0x7FFF) == arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber])) { \
802 FIXME_(d3d_shader)("Loading array %u with data from %s\n", arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber], "position2"); \
803 GL_EXTCALL(glVertexAttribPointerARB(arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber], \
804 WINED3D_ATR_SIZE(position2), \
805 WINED3D_ATR_GLTYPE(position2), \
806 WINED3D_ATR_NORMALIZED(position2), \
807 sd->u.s.position2.dwStride, \
808 ((char *)sd->u.s.position2.lpData) + \
809 WINED3D_ATR_SIZE(position2) * WINED3D_ATR_TYPESIZE(position2) * _lookupNumber)); \
810 GL_EXTCALL(glEnableVertexAttribArrayARB(arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + _lookupNumber])); \
813 /* Generate some lookup tables */
814 /* drop the RHW coord, there must be a nicer way of doing this. */
815 sd->u.s.position.dwType = min(D3DDECLTYPE_FLOAT3, sd->u.s.position.dwType);
816 sd->u.s.position2.dwType = min(D3DDECLTYPE_FLOAT3, sd->u.s.position.dwType);
818 LOAD_NUMBERED_ARRAY(blendWeights,BLENDWEIGHT);
819 LOAD_NUMBERED_ARRAY(blendMatrixIndices,BLENDINDICES);
820 LOAD_NUMBERED_ARRAY(position,POSITION);
821 LOAD_NUMBERED_ARRAY(normal,NORMAL);
822 LOAD_NUMBERED_ARRAY(pSize,PSIZE);
823 LOAD_NUMBERED_ARRAY(diffuse,DIFFUSE);
824 LOAD_NUMBERED_ARRAY(specular,SPECULAR);
825 LOAD_NUMBERED_ARRAY(texCoords[0],TEXCOORD0);
826 LOAD_NUMBERED_ARRAY(texCoords[1],TEXCOORD1);
827 LOAD_NUMBERED_ARRAY(texCoords[2],TEXCOORD2);
828 LOAD_NUMBERED_ARRAY(texCoords[3],TEXCOORD3);
829 LOAD_NUMBERED_ARRAY(texCoords[4],TEXCOORD4);
830 LOAD_NUMBERED_ARRAY(texCoords[5],TEXCOORD5);
831 LOAD_NUMBERED_ARRAY(texCoords[6],TEXCOORD6);
832 LOAD_NUMBERED_ARRAY(texCoords[7],TEXCOORD7);
833 #if 0 /* TODO: Samplers may allow for more texture coords */
834 LOAD_NUMBERED_ARRAY(texCoords[8],TEXCOORD8);
835 LOAD_NUMBERED_ARRAY(texCoords[9],TEXCOORD9);
836 LOAD_NUMBERED_ARRAY(texCoords[10],TEXCOORD10);
837 LOAD_NUMBERED_ARRAY(texCoords[11],TEXCOORD11);
838 LOAD_NUMBERED_ARRAY(texCoords[12],TEXCOORD12);
839 LOAD_NUMBERED_ARRAY(texCoords[13],TEXCOORD13);
840 LOAD_NUMBERED_ARRAY(texCoords[14],TEXCOORD14);
841 LOAD_NUMBERED_ARRAY(texCoords[15],TEXCOORD15);
843 LOAD_NUMBERED_ARRAY(position,POSITIONT);
845 LOAD_NUMBERED_ARRAY(tangent,TANGENT);
846 LOAD_NUMBERED_ARRAY(binormal,BINORMAL);
847 LOAD_NUMBERED_ARRAY(tessFactor,TESSFACTOR);
848 LOAD_NUMBERED_ARRAY(position2,POSITION2);
849 /* there can be lots of position arrays */
850 LOAD_NUMBERED_POSITION_ARRAY(0);
851 LOAD_NUMBERED_POSITION_ARRAY(1);
852 LOAD_NUMBERED_POSITION_ARRAY(2);
853 LOAD_NUMBERED_POSITION_ARRAY(3);
854 LOAD_NUMBERED_POSITION_ARRAY(4);
855 LOAD_NUMBERED_POSITION_ARRAY(5);
856 LOAD_NUMBERED_POSITION_ARRAY(6);
857 LOAD_NUMBERED_POSITION_ARRAY(7);
858 LOAD_NUMBERED_ARRAY(position2,POSITIONT2);
859 LOAD_NUMBERED_ARRAY(normal2,NORMAL2);
860 LOAD_NUMBERED_ARRAY(fog,FOG);
861 LOAD_NUMBERED_ARRAY(depth,DEPTH);
862 LOAD_NUMBERED_ARRAY(sample,SAMPLE);
864 #undef LOAD_NUMBERED_ARRAY
867 static void loadVertexData(IWineD3DDevice *iface, Direct3DVertexStridedData *sd) {
868 unsigned int textureNo = 0;
869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
871 TRACE("Using fast vertex array code\n");
872 /* Blend Data ---------------------------------------------- */
873 if ((sd->u.s.blendWeights.lpData != NULL) ||
874 (sd->u.s.blendMatrixIndices.lpData != NULL)) {
877 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
880 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
881 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
884 TRACE("Blend %d %p %ld\n", WINED3D_ATR_SIZE(blendWeights), sd->u.s.blendWeights.lpData, sd->u.s.blendWeights.dwStride);
885 /* FIXME("TODO\n");*/
886 /* Note dwType == float3 or float4 == 2 or 3 */
889 /* with this on, the normals appear to be being modified,
890 but the vertices aren't being translated as they should be
891 Maybe the world matrix aren't being setup properly? */
892 glVertexBlendARB(WINED3D_ATR_SIZE(blendWeights) + 1);
896 VTRACE(("glWeightPointerARB(%ld, GL_FLOAT, %ld, %p)\n",
897 WINED3D_ATR_SIZE(blendWeights) ,
898 sd->u.s.blendWeights.dwStride,
899 sd->u.s.blendWeights.lpData));
901 GL_EXTCALL(glWeightPointerARB)(WINED3D_ATR_SIZE(blendWeights), WINED3D_ATR_GLTYPE(blendWeights),
902 sd->u.s.blendWeights.dwStride,
903 sd->u.s.blendWeights.lpData);
905 checkGLcall("glWeightPointerARB");
907 if(sd->u.s.blendMatrixIndices.lpData != NULL){
908 static BOOL showfixme = TRUE;
910 FIXME("blendMatrixIndices support\n");
917 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
918 /* FIXME("TODO\n");*/
921 GL_EXTCALL(glVertexWeightPointerEXT)(WINED3D_ATR_SIZE(blendWeights), WINED3D_ATR_GLTYPE(blendWeights),
922 sd->u.s.blendWeights.dwStride,
923 sd->u.s.blendWeights.lpData);
924 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
925 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
926 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
930 /* TODO: support blends in fixupVertices */
931 FIXME("unsupported blending in openGl\n");
934 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
935 #if 0 /* TODO: Vertex blending */
936 glDisable(GL_VERTEX_BLEND_ARB);
938 TRACE("ARB_VERTEX_BLEND\n");
939 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
940 TRACE(" EXT_VERTEX_WEIGHTING\n");
941 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
942 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
947 #if 0 /* FOG ----------------------------------------------*/
948 if (sd->u.s.fog.lpData != NULL) {
950 if (GL_SUPPORT(EXT_FOG_COORD) {
951 glEnableClientState(GL_FOG_COORD_EXT);
952 (GL_EXTCALL)(FogCoordPointerEXT)(WINED3D_ATR_GLTYPE(fog),
953 sd->u.s.fog.dwStride,
956 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
957 /* FIXME: fixme once */
958 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
961 if (GL_SUPPRT(EXT_FOR_COORD) {
962 /* make sure fog is disabled */
963 glDisableClientState(GL_FOG_COORD_EXT);
968 #if 0 /* tangents ----------------------------------------------*/
969 if (sd->u.s.tangent.lpData != NULL || sd->u.s.binormal.lpData != NULL) {
971 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
972 if (sd->u.s.tangent.lpData != NULL) {
973 glEnable(GL_TANGENT_ARRAY_EXT);
974 (GL_EXTCALL)(TangentPointerEXT)(WINED3D_ATR_GLTYPE(tangent),
975 sd->u.s.tangent.dwStride,
976 sd->u.s.tangent.lpData);
978 glDisable(GL_TANGENT_ARRAY_EXT);
980 if (sd->u.s.binormal.lpData != NULL) {
981 glEnable(GL_BINORMAL_ARRAY_EXT);
982 (GL_EXTCALL)(BinormalPointerEXT)(WINED3D_ATR_GLTYPE(binormal),
983 sd->u.s.binormal.dwStride,
984 sd->u.s.binormal.lpData);
986 glDisable(GL_BINORMAL_ARRAY_EXT);
990 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
991 /* FIXME: fixme once */
992 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
995 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
996 /* make sure fog is disabled */
997 glDisable(GL_TANGENT_ARRAY_EXT);
998 glDisable(GL_BINORMAL_ARRAY_EXT);
1003 /* Point Size ----------------------------------------------*/
1004 if (sd->u.s.pSize.lpData != NULL) {
1006 /* no such functionality in the fixed function GL pipeline */
1007 TRACE("Cannot change ptSize here in openGl\n");
1008 /* TODO: Implement this function in using shaders if they are available */
1012 /* Vertex Pointers -----------------------------------------*/
1013 if (sd->u.s.position.lpData != NULL) {
1014 /* Note dwType == float3 or float4 == 2 or 3 */
1015 VTRACE(("glVertexPointer(%ld, GL_FLOAT, %ld, %p)\n",
1016 sd->u.s.position.dwStride,
1017 sd->u.s.position.dwType + 1,
1018 sd->u.s.position.lpData));
1020 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
1021 handling for rhw mode should not impact screen position whereas in GL it does.
1022 This may result in very slightly distored textures in rhw mode, but
1023 a very minimal different. There's always the other option of
1024 fixing the view matrix to prevent w from having any effect */
1025 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(position),3) */, WINED3D_ATR_GLTYPE(position),
1026 sd->u.s.position.dwStride, sd->u.s.position.lpData);
1027 checkGLcall("glVertexPointer(...)");
1028 glEnableClientState(GL_VERTEX_ARRAY);
1029 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
1032 glDisableClientState(GL_VERTEX_ARRAY);
1033 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
1036 /* Normals -------------------------------------------------*/
1037 if (sd->u.s.normal.lpData != NULL) {
1038 /* Note dwType == float3 or float4 == 2 or 3 */
1039 VTRACE(("glNormalPointer(GL_FLOAT, %ld, %p)\n",
1040 sd->u.s.normal.dwStride,
1041 sd->u.s.normal.lpData));
1042 glNormalPointer(WINED3D_ATR_GLTYPE(normal),
1043 sd->u.s.normal.dwStride,
1044 sd->u.s.normal.lpData);
1045 checkGLcall("glNormalPointer(...)");
1046 glEnableClientState(GL_NORMAL_ARRAY);
1047 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
1050 glDisableClientState(GL_NORMAL_ARRAY);
1051 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
1052 glNormal3f(0, 0, 1);
1053 checkGLcall("glNormal3f(0, 0, 1)");
1056 /* Diffuse Colour --------------------------------------------*/
1057 /* WARNING: Data here MUST be in RGBA format, so cannot */
1058 /* go directly into fast mode from app pgm, because */
1059 /* directx requires data in BGRA format. */
1060 /* currently fixupVertices swizels the format, but this isn't */
1061 /* very practical when using VBOS */
1062 /* NOTE: Unless we write a vertex shader to swizel the colour */
1063 /* , or the user doesn't care and wants the speed advantage */
1065 if (sd->u.s.diffuse.lpData != NULL) {
1066 /* Note dwType == float3 or float4 == 2 or 3 */
1067 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1068 sd->u.s.diffuse.dwStride,
1069 sd->u.s.diffuse.lpData));
1071 glColorPointer(4, GL_UNSIGNED_BYTE,
1072 sd->u.s.diffuse.dwStride,
1073 sd->u.s.diffuse.lpData);
1074 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
1075 glEnableClientState(GL_COLOR_ARRAY);
1076 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
1079 glDisableClientState(GL_COLOR_ARRAY);
1080 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1081 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1082 checkGLcall("glColor4f(1, 1, 1, 1)");
1085 /* Specular Colour ------------------------------------------*/
1086 if (sd->u.s.specular.lpData != NULL) {
1087 TRACE("setting specular colour\n");
1088 /* Note dwType == float3 or float4 == 2 or 3 */
1089 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %ld, %p)\n",
1090 sd->u.s.specular.dwStride,
1091 sd->u.s.specular.lpData));
1092 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1093 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1094 sd->u.s.specular.dwStride,
1095 sd->u.s.specular.lpData);
1096 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1097 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1098 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1101 /* Missing specular color is not critical, no warnings */
1102 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1106 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1108 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1109 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1110 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1111 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1114 /* Missing specular color is not critical, no warnings */
1115 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1119 /* Texture coords -------------------------------------------*/
1121 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1123 /* Select the correct texture stage */
1124 GLCLIENTACTIVETEXTURE(textureNo);
1125 if (This->stateBlock->textures[textureNo] != NULL) {
1126 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1127 TRACE("Setting up texture %u, cordindx %u, data %p\n", textureNo, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1128 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1129 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1130 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1131 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
1135 if (coordIdx >= MAX_TEXTURES) {
1136 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1137 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1138 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
1140 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1141 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1142 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1143 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
1147 /* The coords to supply depend completely on the fvf / vertex shader */
1148 glTexCoordPointer(WINED3D_ATR_SIZE(texCoords[coordIdx]), WINED3D_ATR_GLTYPE(texCoords[coordIdx]), sd->u.s.texCoords[coordIdx].dwStride, sd->u.s.texCoords[coordIdx].lpData);
1149 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1153 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1154 GLMULTITEXCOORD4F(textureNo, 0, 0, 0, 1);
1159 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1160 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1163 if (idxData != NULL /* This crashes sometimes!*/) {
1164 TRACE("(%p) : glElements(%x, %d, %ld, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1165 idxData = idxData == (void *)-1 ? NULL : idxData;
1168 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1169 glEnableClientState(GL_INDEX_ARRAY);
1171 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1172 (const char *)idxData+(idxSize * startIdx));
1173 #else /* using drawRangeElements may be faster */
1175 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1176 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1177 (const char *)idxData+(idxSize * startIdx));
1179 checkGLcall("glDrawRangeElements");
1183 /* Note first is now zero as we shuffled along earlier */
1184 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1185 glDrawArrays(glPrimitiveType, 0, numberOfVertices);
1186 checkGLcall("glDrawArrays");
1194 * Actually draw using the supplied information.
1195 * Slower GL version which extracts info about each vertex in turn
1198 static void drawStridedSlow(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
1199 UINT NumVertexes, GLenum glPrimType,
1200 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1202 unsigned int textureNo = 0;
1203 const short *pIdxBufS = NULL;
1204 const long *pIdxBufL = NULL;
1205 LONG SkipnStrides = 0;
1207 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1208 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1209 float rhw = 0.0f; /* rhw */
1210 float ptSize = 0.0f; /* Point size */
1211 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1212 DWORD specularColor = 0; /* Specular Color */
1213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1215 TRACE("Using slow vertex array code\n");
1217 /* Variable Initialization */
1218 if (idxData != NULL) {
1219 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1220 else pIdxBufL = (const long *) idxData;
1223 /* Start drawing in GL */
1224 VTRACE(("glBegin(%x)\n", glPrimType));
1225 glBegin(glPrimType);
1227 /* For each primitive */
1228 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1230 /* Initialize diffuse color */
1231 diffuseColor = 0xFFFFFFFF;
1233 /* For indexed data, we need to go a few more strides in */
1234 if (idxData != NULL) {
1236 /* Indexed so work out the number of strides to skip */
1238 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1239 SkipnStrides = pIdxBufS[startIdx + vx_index];
1241 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1242 SkipnStrides = pIdxBufL[startIdx + vx_index];
1246 /* Position Information ------------------ */
1247 if (sd->u.s.position.lpData != NULL) {
1249 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1254 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1256 /* RHW follows, only if transformed, ie 4 floats were provided */
1257 if (sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4) {
1258 rhw = ptrToCoords[3];
1259 VTRACE(("rhw=%f\n", rhw));
1263 /* Blending data -------------------------- */
1264 if (sd->u.s.blendWeights.lpData != NULL) {
1265 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1266 FIXME("Blending not supported yet\n");
1268 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1269 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1273 /* Vertex Normal Data (untransformed only)- */
1274 if (sd->u.s.normal.lpData != NULL) {
1276 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1277 nx = ptrToCoords[0];
1278 ny = ptrToCoords[1];
1279 nz = ptrToCoords[2];
1280 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1283 /* Point Size ----------------------------- */
1284 if (sd->u.s.pSize.lpData != NULL) {
1286 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1287 ptSize = ptrToCoords[0];
1288 VTRACE(("ptSize=%f\n", ptSize));
1289 FIXME("No support for ptSize yet\n");
1292 /* Diffuse -------------------------------- */
1293 if (sd->u.s.diffuse.lpData != NULL) {
1295 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1296 diffuseColor = ptrToCoords[0];
1297 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1300 /* Specular -------------------------------- */
1301 if (sd->u.s.specular.lpData != NULL) {
1303 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1304 specularColor = ptrToCoords[0];
1305 VTRACE(("specularColor=%lx\n", specularColor));
1308 /* Texture coords --------------------------- */
1309 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1311 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1312 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1316 /* Query tex coords */
1317 if (This->stateBlock->textures[textureNo] != NULL) {
1319 int coordIdx = This->stateBlock->textureState[textureNo][D3DTSS_TEXCOORDINDEX];
1320 float *ptrToCoords = NULL;
1321 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1324 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1326 } else if (coordIdx < 0) {
1327 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1331 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1332 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1333 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1337 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == D3DDECLTYPE_FLOAT1 etc */
1339 /* The coords to supply depend completely on the fvf / vertex shader */
1340 switch (coordsToUse) {
1341 case 4: q = ptrToCoords[3]; /* drop through */
1342 case 3: r = ptrToCoords[2]; /* drop through */
1343 case 2: t = ptrToCoords[1]; /* drop through */
1344 case 1: s = ptrToCoords[0];
1347 /* Projected is more 'fun' - Move the last coord to the 'q'
1348 parameter (see comments under D3DTSS_TEXTURETRANSFORMFLAGS */
1349 if ((This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) &&
1350 (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED)) {
1352 if (This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
1353 switch (coordsToUse) {
1354 case 0: /* Drop Through */
1356 FIXME("D3DTTFF_PROJECTED but only zero or one coordinate?\n");
1368 case 4: /* Nop here */
1371 FIXME("Unexpected D3DTSS_TEXTURETRANSFORMFLAGS value of %ld\n",
1372 This->stateBlock->textureState[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED);
1377 switch (coordsToUse) { /* Supply the provided texture coords */
1378 case D3DTTFF_COUNT1:
1379 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1380 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1381 GLMULTITEXCOORD1F(textureNo, s);
1386 case D3DTTFF_COUNT2:
1387 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1388 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1389 GLMULTITEXCOORD2F(textureNo, s, t);
1394 case D3DTTFF_COUNT3:
1395 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1396 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1397 GLMULTITEXCOORD3F(textureNo, s, t, r);
1399 glTexCoord3f(s, t, r);
1402 case D3DTTFF_COUNT4:
1403 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1404 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1405 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
1407 glTexCoord4f(s, t, r, q);
1411 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1415 } /* End of textures */
1417 /* Diffuse -------------------------------- */
1418 if (sd->u.s.diffuse.lpData != NULL) {
1419 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1420 D3DCOLOR_B_G(diffuseColor),
1421 D3DCOLOR_B_B(diffuseColor),
1422 D3DCOLOR_B_A(diffuseColor));
1423 VTRACE(("glColor4ub: r,g,b,a=%u,%u,%u,%u\n",
1424 D3DCOLOR_B_R(diffuseColor),
1425 D3DCOLOR_B_G(diffuseColor),
1426 D3DCOLOR_B_B(diffuseColor),
1427 D3DCOLOR_B_A(diffuseColor)));
1429 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1432 /* Specular ------------------------------- */
1433 if (sd->u.s.specular.lpData != NULL) {
1434 VTRACE(("glSecondaryColor4ub: r,g,b=%u,%u,%u\n",
1435 D3DCOLOR_B_R(specularColor),
1436 D3DCOLOR_B_G(specularColor),
1437 D3DCOLOR_B_B(specularColor)));
1438 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1439 GL_EXTCALL(glSecondaryColor3ubEXT)(
1440 D3DCOLOR_B_R(specularColor),
1441 D3DCOLOR_B_G(specularColor),
1442 D3DCOLOR_B_B(specularColor));
1444 /* Do not worry if specular colour missing and disable request */
1445 VTRACE(("Specular color extensions not supplied\n"));
1448 if (vx_index == 0) {
1449 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1450 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1452 /* Do not worry if specular colour missing and disable request */
1453 VTRACE(("Specular color extensions not supplied\n"));
1458 /* Normal -------------------------------- */
1459 if (sd->u.s.normal.lpData != NULL) {
1460 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1461 glNormal3f(nx, ny, nz);
1463 if (vx_index == 0) glNormal3f(0, 0, 1);
1466 /* Position -------------------------------- */
1467 if (sd->u.s.position.lpData != NULL) {
1468 if (1.0f == rhw || ((rhw < 0.0001f) && (rhw > -0.0001f))) {
1469 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1470 glVertex3f(x, y, z);
1472 GLfloat w = 1.0 / rhw;
1473 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1474 glVertex4f(x*w, y*w, z*w, w);
1478 /* For non indexed mode, step onto next parts */
1479 if (idxData == NULL) {
1485 checkGLcall("glEnd and previous calls");
1488 #if 0 /* TODO: Software/Hardware vertex blending support */
1490 * Draw with emulated vertex shaders
1491 * Note: strided data is uninitialized, as we need to pass the vertex
1492 * shader directly as ordering irs yet
1494 void drawStridedSoftwareVS(IWineD3DDevice *iface, Direct3DVertexStridedData *sd,
1495 int PrimitiveType, ULONG NumPrimitives,
1496 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1498 unsigned int textureNo = 0;
1499 GLenum glPrimType = GL_POINTS;
1500 int NumVertexes = NumPrimitives;
1501 const short *pIdxBufS = NULL;
1502 const long *pIdxBufL = NULL;
1503 LONG SkipnStrides = 0;
1505 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1506 float rhw = 0.0f; /* rhw */
1507 float ptSize = 0.0f; /* Point size */
1508 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1509 int numcoords[8]; /* Number of coords */
1510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1512 IDirect3DVertexShaderImpl* vertexShader = NULL;
1514 TRACE("Using slow software vertex shader code\n");
1516 /* Variable Initialization */
1517 if (idxData != NULL) {
1518 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1519 else pIdxBufL = (const long *) idxData;
1522 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1523 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1525 /* Retrieve the VS information */
1526 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1528 /* Start drawing in GL */
1529 VTRACE(("glBegin(%x)\n", glPrimType));
1530 glBegin(glPrimType);
1532 /* For each primitive */
1533 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1535 /* For indexed data, we need to go a few more strides in */
1536 if (idxData != NULL) {
1538 /* Indexed so work out the number of strides to skip */
1540 VTRACE(("Idx for vertex %ld = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1541 SkipnStrides = pIdxBufS[startIdx+vx_index];
1543 VTRACE(("Idx for vertex %ld = %ld\n", vx_index, pIdxBufL[startIdx+vx_index]));
1544 SkipnStrides = pIdxBufL[startIdx+vx_index];
1548 /* Fill the vertex shader input */
1549 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1551 /* Initialize the output fields to the same defaults as it would normally have */
1552 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1553 vertexShader->output.oD[0].x = 1.0;
1554 vertexShader->output.oD[0].y = 1.0;
1555 vertexShader->output.oD[0].z = 1.0;
1556 vertexShader->output.oD[0].w = 1.0;
1558 /* Now execute the vertex shader */
1559 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1562 TRACE_VECTOR(vertexShader->output.oPos);
1563 TRACE_VECTOR(vertexShader->output.oD[0]);
1564 TRACE_VECTOR(vertexShader->output.oD[1]);
1565 TRACE_VECTOR(vertexShader->output.oT[0]);
1566 TRACE_VECTOR(vertexShader->output.oT[1]);
1567 TRACE_VECTOR(vertexShader->input.V[0]);
1568 TRACE_VECTOR(vertexShader->data->C[0]);
1569 TRACE_VECTOR(vertexShader->data->C[1]);
1570 TRACE_VECTOR(vertexShader->data->C[2]);
1571 TRACE_VECTOR(vertexShader->data->C[3]);
1572 TRACE_VECTOR(vertexShader->data->C[4]);
1573 TRACE_VECTOR(vertexShader->data->C[5]);
1574 TRACE_VECTOR(vertexShader->data->C[6]);
1575 TRACE_VECTOR(vertexShader->data->C[7]);
1578 /* Extract out the output */
1579 /* FIXME: Fog coords? */
1580 x = vertexShader->output.oPos.x;
1581 y = vertexShader->output.oPos.y;
1582 z = vertexShader->output.oPos.z;
1583 rhw = vertexShader->output.oPos.w;
1584 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1586 /** Update textures coords using vertexShader->output.oT[0->7] */
1587 memset(texcoords, 0x00, sizeof(texcoords));
1588 memset(numcoords, 0x00, sizeof(numcoords));
1589 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1590 if (This->stateBlock->textures[textureNo] != NULL) {
1591 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1592 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1593 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1594 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1595 if (This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] != D3DTTFF_DISABLE) {
1596 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][D3DTSS_TEXTURETRANSFORMFLAGS] & ~D3DTTFF_PROJECTED;
1598 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1599 case D3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1600 case D3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1601 default: numcoords[textureNo] = 4;
1605 numcoords[textureNo] = 0;
1609 /* Draw using this information */
1612 TRUE, 0.0f, 0.0f, 1.0f,
1613 TRUE, (float*) &vertexShader->output.oD[0],
1614 TRUE, (float*) &vertexShader->output.oD[1],
1615 FALSE, ptSize, /* FIXME: Change back when supported */
1616 texcoords, numcoords);
1618 /* For non indexed mode, step onto next parts */
1619 if (idxData == NULL) {
1623 } /* for each vertex */
1626 checkGLcall("glEnd and previous calls");
1631 void inline drawPrimitiveDrawStrided(IWineD3DDevice *iface, BOOL useVertexShaderFunction, int useHW, Direct3DVertexStridedData *dataLocations,
1632 UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idxData, short idxSize, int minIndex, long StartIdx) {
1633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1635 /* Now draw the graphics to the screen */
1636 if (FALSE /* disable software vs for now */ && useVertexShaderFunction && !useHW) {
1637 FIXME("drawing using software vertex shaders (line %d)\n", __LINE__);
1638 /* Ideally, we should have software FV and hardware VS, possibly
1639 depending on the device type? */
1640 #if 0 /* TODO: vertex and pixel shaders */
1641 drawStridedSoftwareVS(iface, dataLocations, PrimitiveType, NumPrimitives,
1642 idxData, idxSize, minIndex, StartIdx);
1647 /* TODO: Work out if fixup are required at all (this can be a flag against the vertex declaration) */
1648 int startStride = idxData == NULL ? 0 : idxData == (void *) -1 ? 0 :(idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1649 int endStride = startStride;
1650 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n", startStride, endStride, numberOfIndicies, numberOfvertices);
1652 #if 0 /* TODO: Vertex fixups (diffuse and specular) */
1653 if (idxData != NULL) { /* index data isn't linear, so lookup the real start and end strides */
1656 unsigned short *index = (unsigned short *)idxData;
1658 for (t = 0 ; t < numberOfIndicies; t++) {
1659 if (startStride > *index)
1660 startStride = *index;
1661 if (endStride < *index)
1665 } else { /* idxSize == 4 */
1666 unsigned int *index = (unsigned int *)idxData;
1668 for (t = 0 ; t < numberOfIndicies; t++) {
1669 if (startStride > *index)
1670 startStride = *index;
1671 if (endStride < *index)
1677 endStride += numberOfvertices -1;
1680 TRACE("end Start stride %d, end stride %d, number of indices%d, number of vertices%d\n", startStride, endStride, numberOfIndicies, numberOfvertices);
1681 /* pre-transform verticex */
1682 /* TODO: Caching, VBO's etc.. */
1684 /* Generate some fixme's if unsupported functionality is being used */
1685 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1686 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1687 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1688 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1690 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1691 FIXME("Tweening is only valid with vertex shaders\n");
1693 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1694 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1696 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1697 FIXME("Extended attributes are only valid with vertex shaders\n");
1699 #undef BUFFER_OR_DATA
1701 #if 0/* TODO: Vertex fixups (diffuse and specular) */
1702 fixupVertices(This, dataLocations, &transformedDataLocations, 1 + endStride - startStride, startStride);
1705 /* vertex shaders */
1707 /* If the only vertex data used by the shader is supported by OpenGL then*/
1708 if ((!useVertexShaderFunction && dataLocations->u.s.pSize.lpData == NULL
1709 && dataLocations->u.s.diffuse.lpData == NULL && dataLocations->u.s.specular.lpData == NULL)
1710 || (useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->namedArrays && !((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays)) {
1712 /* Load the vertex data using named arrays */
1713 TRACE("(%p) Loading vertex data\n", This);
1714 loadVertexData(iface, dataLocations);
1716 } else /* Otherwise */
1717 if(useVertexShaderFunction && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays) {
1719 /* load the array data using ordinal mapping */
1720 loadNumberedArrays(iface, dataLocations, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->arrayUsageMap);
1722 } else { /* If this happens we must drawStridedSlow later on */
1723 TRACE("Not loading vertex data\n");
1726 TRACE("Loaded arrays\n");
1728 if (useVertexShaderFunction) {
1732 FIXME("Using vertex shader\n");
1734 /* Bind the vertex program */
1735 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->prgId));
1736 checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1738 /* and enable gl vertex shaders */
1739 glEnable(GL_VERTEX_PROGRAM_ARB);
1740 checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1741 TRACE_(d3d_shader)("(%p) bound program %u and enabled vertex program ARB\n", This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->prgId);
1743 /* Update the constants */
1744 for (i = 0; i < WINED3D_VSHADER_MAX_CONSTANTS; i++) {
1745 /* TODO: add support for Integer and Boolean constants */
1746 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, i, &This->stateBlock->vertexShaderConstantF[i * 4]));
1747 TRACE_(d3d_shader)("Loading constants %u = %f %f %f %f\n",i, This->stateBlock->vertexShaderConstantF[i *4 ], This->stateBlock->vertexShaderConstantF[i * 4 + 1], This->stateBlock->vertexShaderConstantF[i *4 + 2], This->stateBlock->vertexShaderConstantF[i * 4 + 3]);
1748 checkGLcall("glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB");
1750 /* TODO: Vertex Shader 8 constants*/
1752 /* always draw strided fast if a vertex shader is being used */
1753 drawStridedFast(iface, numberOfIndicies, glPrimType,
1754 idxData, idxSize, minIndex, StartIdx);
1756 /* check for any errors */
1757 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
1759 FIXME("HW VertexShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
1762 /* disable any attribs */
1763 if(((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->declaredArrays) {
1766 /* Leave all the attribs disabled */
1767 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
1768 /* MESA does not support it right not */
1769 if (glGetError() != GL_NO_ERROR)
1771 for (i = 0; i < maxAttribs; i++) {
1772 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
1773 checkGLcall("glDisableVertexAttribArrayARB(reg);");
1778 glDisable(GL_VERTEX_PROGRAM_ARB);
1781 /* DirectX colours are in a different format to opengl colours
1782 so if diffuse or specular are used then we need to use drawStridedSlow
1783 to correct the colours */
1784 if ((dataLocations->u.s.pSize.lpData != NULL)
1785 || (dataLocations->u.s.diffuse.lpData != NULL)
1786 || (dataLocations->u.s.specular.lpData != NULL)) {
1787 /* TODO: replace drawStridedSlow with veretx fixups */
1790 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType,
1791 idxData, idxSize, minIndex, StartIdx) ;
1794 * drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType,
1795 * idxData, idxSize, minIndex, StartIdx);
1799 /* OpenGL can manage everything in hardware so we can use drawStridedFast */
1800 drawStridedFast(iface, numberOfIndicies, glPrimType,
1801 idxData, idxSize, minIndex, StartIdx);
1807 void inline drawPrimitiveTraceDataLocations(Direct3DVertexStridedData *dataLocations,DWORD fvf) {
1809 /* Dump out what parts we have supplied */
1810 TRACE("Strided Data (from FVF/VS): %lx\n", fvf);
1811 TRACE_STRIDED((dataLocations), position);
1812 TRACE_STRIDED((dataLocations), blendWeights);
1813 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1814 TRACE_STRIDED((dataLocations), normal);
1815 TRACE_STRIDED((dataLocations), pSize);
1816 TRACE_STRIDED((dataLocations), diffuse);
1817 TRACE_STRIDED((dataLocations), specular);
1818 TRACE_STRIDED((dataLocations), texCoords[0]);
1819 TRACE_STRIDED((dataLocations), texCoords[1]);
1820 TRACE_STRIDED((dataLocations), texCoords[2]);
1821 TRACE_STRIDED((dataLocations), texCoords[3]);
1822 TRACE_STRIDED((dataLocations), texCoords[4]);
1823 TRACE_STRIDED((dataLocations), texCoords[5]);
1824 TRACE_STRIDED((dataLocations), texCoords[6]);
1825 TRACE_STRIDED((dataLocations), texCoords[7]);
1826 TRACE_STRIDED((dataLocations), position2);
1827 TRACE_STRIDED((dataLocations), normal2);
1828 TRACE_STRIDED((dataLocations), tangent);
1829 TRACE_STRIDED((dataLocations), binormal);
1830 TRACE_STRIDED((dataLocations), tessFactor);
1831 TRACE_STRIDED((dataLocations), fog);
1832 TRACE_STRIDED((dataLocations), depth);
1833 TRACE_STRIDED((dataLocations), sample);
1839 /* uploads textures and setup texture states ready for rendering */
1840 void inline drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
1844 * OK, here we clear down any old junk iect in the context
1845 * enable the new texture and apply any state changes:
1847 * Loop through all textures
1848 * select texture unit
1849 * if there is a texture bound to that unit then..
1850 * disable all textures types on that unit
1851 * enable and bind the texture that is bound to that unit.
1852 * otherwise disable all texture types on that unit.
1854 /* upload the textures */
1855 for (i = 0; i< GL_LIMITS(textures); ++i) {
1856 /* Bind the texture to the stage here */
1857 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1860 /* This isn't so much a warn as a message to the user about lack of hardware support */
1861 WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1864 /* don't bother with textures that have a colorop of disable */
1865 if (This->stateBlock->textureState[i][WINED3DTSS_COLOROP] != D3DTOP_DISABLE) {
1866 if (This->stateBlock->textures[i] != NULL) {
1868 glDisable(GL_TEXTURE_1D);
1869 This->stateBlock->textureDimensions[i] = IWineD3DBaseTexture_GetTextureDimensions(This->stateBlock->textures[i]);
1870 /* disable all texture states that aren't the selected textures' dimension */
1871 switch(This->stateBlock->textureDimensions[i]) {
1873 glDisable(GL_TEXTURE_3D);
1874 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1877 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1878 glDisable(GL_TEXTURE_2D);
1880 case GLTEXTURECUBEMAP:
1881 glDisable(GL_TEXTURE_2D);
1882 glDisable(GL_TEXTURE_3D);
1885 /* imply GL_SUPPORT(NV_TEXTURE_SHADER) when setting texture_shader_active */
1886 if (This->texture_shader_active && This->stateBlock->textureDimensions[i] == GL_TEXTURE_2D) {
1887 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
1889 glEnable(This->stateBlock->textureDimensions[i]);
1891 /* Load up the texture now */
1892 IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) This->stateBlock->textures[i]);
1893 IWineD3DDevice_SetupTextureStates((IWineD3DDevice *)This, i, REAPPLY_ALPHAOP);
1894 /* this is a stub function representing the state blocks
1895 * being separated here we are only updating the texture
1896 * state changes, other objects and units get updated when
1897 * they change (or need to be updated), e.g. states that
1898 * relate to a context member line the texture unit are
1899 * only updated when the context needs updating
1901 /* Tell the abse texture to sync it's states */
1902 IWineD3DBaseTexture_ApplyStateChanges(This->stateBlock->textures[i], This->stateBlock->textureState[i], This->stateBlock->samplerState[i]);
1905 /* Bind a default texture if no texture has been set, but colour-op is enabled */
1907 glDisable(GL_TEXTURE_2D);
1908 glDisable(GL_TEXTURE_3D);
1909 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1910 glEnable(GL_TEXTURE_1D);
1911 This->stateBlock->textureDimensions[i] = GL_TEXTURE_1D;
1912 glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[i]);
1914 /** these ops apply to the texture unit, so they are preserved between texture changes, but for now brute force and reapply all
1915 dx9_1pass_emboss_bump_mapping and dx9_2pass_emboss_bump_mapping are good texts to make sure the states are being applied when needed **/
1916 set_tex_op((IWineD3DDevice *)This, FALSE, i, This->stateBlock->textureState[i][WINED3DTSS_COLOROP],
1917 This->stateBlock->textureState[i][WINED3DTSS_COLORARG1],
1918 This->stateBlock->textureState[i][WINED3DTSS_COLORARG2],
1919 This->stateBlock->textureState[i][WINED3DTSS_COLORARG0]);
1921 set_tex_op((IWineD3DDevice *)This, TRUE, i, This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP],
1922 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1],
1923 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2],
1924 This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0]);
1927 /* no colorop so disable all the texture states */
1928 glDisable(GL_TEXTURE_1D);
1929 glDisable(GL_TEXTURE_2D);
1930 glDisable(GL_TEXTURE_3D);
1931 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1938 /* Routine common to the draw primitive and draw indexed primitive routines */
1939 void drawPrimitive(IWineD3DDevice *iface,
1943 long StartVertexIndex,
1944 UINT numberOfVertices,
1947 const void *idxData,
1952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1953 BOOL useVertexShaderFunction = FALSE;
1954 BOOL isLightingOn = FALSE;
1955 Direct3DVertexStridedData dataLocations;
1958 if (This->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE
1959 &&((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->function != NULL
1960 && GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
1961 useVertexShaderFunction = TRUE;
1963 useVertexShaderFunction = FALSE;
1966 if (This->stateBlock->vertexDecl == NULL) {
1967 /* Work out what the FVF should look like */
1968 rc = initializeFVF(iface, &fvf);
1971 TRACE("(%p) : using vertex declaration %p\n", iface, This->stateBlock->vertexDecl);
1974 /* Ok, we will be updating the screen from here onwards so grab the lock */
1977 #if 0 /* TODO: vertex and pixel shaders */
1978 /* If we will be using a pixel, do some initialization for it */
1979 if ((pixel_shader = PIXEL_SHADER(This->stateBlock->PixelShader))) {
1980 TRACE("drawing with pixel shader handle %p\n", pixel_shader);
1981 memset(&pixel_shader->input, 0, sizeof(PSHADERINPUTDATA8));
1983 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId));
1984 checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixel_shader->prgId);");
1985 glEnable(GL_FRAGMENT_PROGRAM_ARB);
1986 checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1988 /* init Constants */
1989 if (This->stateBlock->Changed.pixelShaderConstant) {
1990 TRACE_(d3d_shader)("pixel shader initializing constants %p\n",pixel_shader);
1991 IDirect3DPixelShaderImpl_SetConstantF(pixel_shader, 0, (CONST FLOAT*) &This->stateBlock->pixelShaderConstant[0], 8);
1993 /* Update the constants */
1994 for (i = 0; i < D3D8_PSHADER_MAX_CONSTANTS; ++i) {
1995 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, (GLfloat *)&This->stateBlock->pixelShaderConstant[i]));
1996 checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB");
1999 #endif /* TODO: vertex and pixel shaders */
2001 /* Initialize all values to null */
2002 memset(&dataLocations, 0x00, sizeof(dataLocations));
2003 /* convert the FVF or vertexDeclaration into a strided stream (this should be done when the fvf or declaration is created) */
2005 if (This->stateBlock->vertexDecl != NULL) {
2006 TRACE("================ Vertex Declaration ===================\n");
2007 primitiveDeclarationConvertToStridedData(iface, &dataLocations, StartVertexIndex, &fvf);
2009 TRACE("================ FVF ===================\n");
2010 primitiveConvertToStridedData(iface, &dataLocations, StartVertexIndex);
2013 /* write out some debug information*/
2014 drawPrimitiveTraceDataLocations(&dataLocations, fvf);
2016 /* Setup transform matrices and sort out */
2018 /* Lighting is not completely bypassed with ATI drivers although it should be. Mesa is ok from this respect...
2019 So make sure lighting is disabled. */
2020 isLightingOn = glIsEnabled(GL_LIGHTING);
2021 glDisable(GL_LIGHTING);
2022 checkGLcall("glDisable(GL_LIGHTING);");
2023 TRACE("Disabled lighting as no normals supplied, old state = %d\n", isLightingOn);
2025 isLightingOn = primitiveInitState(iface,
2026 fvf & D3DFVF_XYZRHW,
2027 !(fvf & D3DFVF_NORMAL),
2028 useVertexShaderFunction);
2031 /* Now initialize the materials state */
2032 init_materials(iface, (dataLocations.u.s.diffuse.lpData != NULL));
2034 drawPrimitiveUploadTextures(This);
2039 /* Ok, Work out which primitive is requested and how many vertexes that
2041 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
2042 #if 0 /* debugging code... just information not an error */
2043 if(numberOfVertices != 0 && numberOfVertices != calculatedNumberOfindices){
2044 FIXME("Number of vertices %u and Caculated number of indicies %u differ\n", numberOfVertices, calculatedNumberOfindices);
2047 if (numberOfVertices == 0 )
2048 numberOfVertices = calculatedNumberOfindices;
2049 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, useHW, &dataLocations, numberOfVertices, calculatedNumberOfindices, glPrimType, idxData, idxSize, minIndex, StartIdx);
2052 /* If vertex shaders or no normals, restore previous lighting state */
2053 if (useVertexShaderFunction || !(fvf & D3DFVF_NORMAL)) {
2054 if (isLightingOn) glEnable(GL_LIGHTING);
2055 else glDisable(GL_LIGHTING);
2056 TRACE("Restored lighting to original state\n");
2059 #if 0 /* TODO: vertex and pixel shaders */
2064 glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &errPos );
2066 FIXME("HW PixelShader Error at position: %d\n%s\n", errPos, glGetString( GL_PROGRAM_ERROR_STRING_ARB) );
2068 glDisable(GL_FRAGMENT_PROGRAM_ARB);
2072 /* Finshed updating the screen, restore lock */
2074 TRACE("Done all gl drawing\n");
2077 #ifdef SHOW_FRAME_MAKEUP
2079 static long int primCounter = 0;
2080 /* NOTE: set primCounter to the value reported by drawprim
2081 before you want to to write frame makeup to /tmp */
2082 if (primCounter >= 0) {
2085 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, D3DLOCK_READONLY);
2086 sprintf(buffer, "/tmp/backbuffer_%ld.tga", primCounter);
2087 TRACE("Saving screenshot %s\n", buffer);
2088 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
2089 IWineD3DSurface_UnlockRect(This->renderTarget);
2091 #ifdef SHOW_TEXTURE_MAKEUP
2093 IWineD3DSurface *pSur;
2095 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
2096 if (This->stateBlock->textures[textureNo] != NULL) {
2097 sprintf(buffer, "/tmp/texture_%p_%ld_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
2098 TRACE("Saving texture %s\n", buffer);
2099 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == D3DRTYPE_TEXTURE) {
2100 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
2101 IWineD3DSurface_SaveSnapshot(pSur, buffer);
2102 IWineD3DSurface_Release(pSur);
2104 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
2111 TRACE("drawprim #%ld\n", primCounter);