wined3d: Break the lighting state out of the vertex decl.
[wine.git] / dlls / wined3d / drawprim.c
blob487a418da30c32e680c049bc0d6451840a80037a
1 /*
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
8 * Copyright 2006 Henri Verbeet
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "config.h"
26 #include "wined3d_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
29 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
30 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
32 #include <stdio.h>
34 #if 0 /* TODO */
35 extern IWineD3DVertexShaderImpl* VertexShaders[64];
36 extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64];
37 extern IWineD3DPixelShaderImpl* PixelShaders[64];
39 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
40 #endif
42 /* Issues the glBegin call for gl given the primitive type and count */
43 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
44 DWORD NumPrimitives,
45 GLenum *primType)
47 DWORD NumVertexes = NumPrimitives;
49 switch (PrimitiveType) {
50 case WINED3DPT_POINTLIST:
51 TRACE("POINTS\n");
52 *primType = GL_POINTS;
53 NumVertexes = NumPrimitives;
54 break;
56 case WINED3DPT_LINELIST:
57 TRACE("LINES\n");
58 *primType = GL_LINES;
59 NumVertexes = NumPrimitives * 2;
60 break;
62 case WINED3DPT_LINESTRIP:
63 TRACE("LINE_STRIP\n");
64 *primType = GL_LINE_STRIP;
65 NumVertexes = NumPrimitives + 1;
66 break;
68 case WINED3DPT_TRIANGLELIST:
69 TRACE("TRIANGLES\n");
70 *primType = GL_TRIANGLES;
71 NumVertexes = NumPrimitives * 3;
72 break;
74 case WINED3DPT_TRIANGLESTRIP:
75 TRACE("TRIANGLE_STRIP\n");
76 *primType = GL_TRIANGLE_STRIP;
77 NumVertexes = NumPrimitives + 2;
78 break;
80 case WINED3DPT_TRIANGLEFAN:
81 TRACE("TRIANGLE_FAN\n");
82 *primType = GL_TRIANGLE_FAN;
83 NumVertexes = NumPrimitives + 2;
84 break;
86 default:
87 FIXME("Unhandled primitive\n");
88 *primType = GL_POINTS;
89 break;
91 return NumVertexes;
94 /* Ensure the appropriate material states are set up - only change
95 state if really required */
96 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
98 BOOL requires_material_reset = FALSE;
99 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
101 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
102 /* If we have not set up the material color tracking, do it now as required */
103 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
104 checkGLcall("glDisable GL_COLOR_MATERIAL");
105 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
106 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
107 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
108 glEnable(GL_COLOR_MATERIAL);
109 checkGLcall("glEnable GL_COLOR_MATERIAL");
110 This->tracking_color = IS_TRACKING;
111 requires_material_reset = TRUE; /* Restore material settings as will be used */
113 } else if ((This->tracking_color == IS_TRACKING && !isDiffuseSupplied) ||
114 (This->tracking_color == NEEDS_TRACKING && !isDiffuseSupplied)) {
115 /* If we are tracking the current color but one isn't supplied, don't! */
116 glDisable(GL_COLOR_MATERIAL);
117 checkGLcall("glDisable GL_COLOR_MATERIAL");
118 This->tracking_color = NEEDS_TRACKING;
119 requires_material_reset = TRUE; /* Restore material settings as will be used */
121 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
122 /* No need to reset material colors since no change to gl_color_material */
123 requires_material_reset = FALSE;
125 } else if (This->tracking_color == NEEDS_DISABLE) {
126 glDisable(GL_COLOR_MATERIAL);
127 checkGLcall("glDisable GL_COLOR_MATERIAL");
128 This->tracking_color = DISABLED_TRACKING;
129 requires_material_reset = TRUE; /* Restore material settings as will be used */
132 /* Reset the material colors which may have been tracking the color*/
133 if (requires_material_reset) {
134 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
135 checkGLcall("glMaterialfv");
136 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
137 checkGLcall("glMaterialfv");
138 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
139 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
140 checkGLcall("glMaterialfv");
141 } else {
142 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
143 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
144 checkGLcall("glMaterialfv");
146 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
147 checkGLcall("glMaterialfv");
152 static const GLfloat invymat[16] = {
153 1.0f, 0.0f, 0.0f, 0.0f,
154 0.0f, -1.0f, 0.0f, 0.0f,
155 0.0f, 0.0f, 1.0f, 0.0f,
156 0.0f, 0.0f, 0.0f, 1.0f};
158 void d3ddevice_set_ortho(IWineD3DDeviceImpl *This) {
159 /* If the last draw was transformed as well, no need to reapply all the matrixes */
160 if ( (!This->last_was_rhw) || (This->viewport_changed) ) {
162 double X, Y, height, width, minZ, maxZ;
163 This->last_was_rhw = TRUE;
164 This->viewport_changed = FALSE;
166 /* Transformed already into viewport coordinates, so we do not need transform
167 matrices. Reset all matrices to identity and leave the default matrix in world
168 mode. */
169 glMatrixMode(GL_MODELVIEW);
170 checkGLcall("glMatrixMode(GL_MODELVIEW)");
171 glLoadIdentity();
172 checkGLcall("glLoadIdentity");
174 glMatrixMode(GL_PROJECTION);
175 checkGLcall("glMatrixMode(GL_PROJECTION)");
176 glLoadIdentity();
177 checkGLcall("glLoadIdentity");
179 /* Set up the viewport to be full viewport */
180 X = This->stateBlock->viewport.X;
181 Y = This->stateBlock->viewport.Y;
182 height = This->stateBlock->viewport.Height;
183 width = This->stateBlock->viewport.Width;
184 minZ = This->stateBlock->viewport.MinZ;
185 maxZ = This->stateBlock->viewport.MaxZ;
186 if(!This->untransformed) {
187 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ);
188 glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ);
189 } else {
190 TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0);
191 glOrtho(X, X + width, Y + height, Y, 1.0, -1.0);
193 checkGLcall("glOrtho");
195 /* Window Coord 0 is the middle of the first pixel, so translate by half
196 a pixel (See comment above glTranslate below) */
197 glTranslatef(0.375, 0.375, 0);
198 checkGLcall("glTranslatef(0.375, 0.375, 0)");
199 /* D3D texture coordinates are flipped compared to OpenGL ones, so
200 * render everything upside down when rendering offscreen. */
201 if (This->render_offscreen) {
202 glMultMatrixf(invymat);
203 checkGLcall("glMultMatrixf(invymat)");
206 /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */
207 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != WINED3DFOG_NONE) {
208 if(GL_SUPPORT(EXT_FOG_COORD)) {
209 glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
210 checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)");
211 glFogi(GL_FOG_MODE, GL_LINEAR);
212 checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
213 /* The dx fog range in this case is fixed to 0 - 255,
214 * but in GL it still depends on the fog start and end (according to the ext)
215 * Use this to turn around the fog as it's needed. That prevents some
216 * calculations during drawing :-)
218 glFogf(GL_FOG_START, (float) 0xff);
219 checkGLcall("glFogfv GL_FOG_END");
220 glFogf(GL_FOG_END, 0.0);
221 checkGLcall("glFogfv GL_FOG_START");
222 } else {
223 /* Disable GL fog, handle this in software in drawStridedSlow */
224 glDisable(GL_FOG);
225 checkGLcall("glDisable(GL_FOG)");
231 static BOOL fixed_get_input(
232 BYTE usage, BYTE usage_idx,
233 unsigned int* regnum) {
235 *regnum = -1;
237 /* Those positions must have the order in the
238 * named part of the strided data */
240 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
241 *regnum = 0;
242 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
243 *regnum = 1;
244 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
245 *regnum = 2;
246 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
247 *regnum = 3;
248 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
249 *regnum = 4;
250 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
251 *regnum = 5;
252 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
253 *regnum = 6;
254 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
255 *regnum = 7 + usage_idx;
256 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
257 *regnum = 7 + WINED3DDP_MAXTEXCOORD;
258 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
259 *regnum = 8 + WINED3DDP_MAXTEXCOORD;
260 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
261 *regnum = 9 + WINED3DDP_MAXTEXCOORD;
262 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
263 *regnum = 10 + WINED3DDP_MAXTEXCOORD;
264 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
265 *regnum = 11 + WINED3DDP_MAXTEXCOORD;
266 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
267 *regnum = 12 + WINED3DDP_MAXTEXCOORD;
268 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
269 *regnum = 13 + WINED3DDP_MAXTEXCOORD;
270 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
271 *regnum = 14 + WINED3DDP_MAXTEXCOORD;
273 if (*regnum < 0) {
274 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
275 debug_d3ddeclusage(usage), usage_idx);
276 return FALSE;
278 return TRUE;
281 void primitiveDeclarationConvertToStridedData(
282 IWineD3DDevice *iface,
283 BOOL useVertexShaderFunction,
284 WineDirect3DVertexStridedData *strided,
285 BOOL *fixup) {
287 /* We need to deal with frequency data!*/
289 BYTE *data = NULL;
290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
291 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
292 int i;
293 WINED3DVERTEXELEMENT *element;
294 DWORD stride;
295 int reg;
297 /* Locate the vertex declaration */
298 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
299 TRACE("Using vertex declaration from shader\n");
300 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
301 } else {
302 TRACE("Using vertex declaration\n");
303 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
306 /* Translate the declaration into strided data */
307 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
308 GLint streamVBO = 0;
309 BOOL stride_used;
310 unsigned int idx;
312 element = vertexDeclaration->pDeclarationWine + i;
313 TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
314 element, i + 1, vertexDeclaration->declarationWNumElements - 1);
316 if (This->stateBlock->streamSource[element->Stream] == NULL)
317 continue;
319 if (This->stateBlock->streamIsUP) {
320 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
321 streamVBO = 0;
322 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
323 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
324 } else {
325 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
326 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
327 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
328 if(fixup) {
329 if( streamVBO != 0) *fixup = TRUE;
330 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
333 stride = This->stateBlock->streamStride[element->Stream];
334 data += element->Offset;
335 reg = element->Reg;
337 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
339 if (useVertexShaderFunction)
340 stride_used = vshader_get_input(This->stateBlock->vertexShader,
341 element->Usage, element->UsageIndex, &idx);
342 else
343 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
345 if (stride_used) {
346 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
347 "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
348 useVertexShaderFunction? "shader": "fixed function", idx,
349 debug_d3ddeclusage(element->Usage), element->UsageIndex,
350 element->Stream, element->Offset, stride, streamVBO);
352 strided->u.input[idx].lpData = data;
353 strided->u.input[idx].dwType = element->Type;
354 strided->u.input[idx].dwStride = stride;
355 strided->u.input[idx].VBO = streamVBO;
356 if (!useVertexShaderFunction) {
357 if (element->Usage == D3DDECLUSAGE_POSITION)
358 strided->u.s.position_transformed = FALSE;
359 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
360 strided->u.s.position_transformed = TRUE;
366 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
367 int numBlends;
368 int numTextures;
369 int textureNo;
370 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
371 int numCoords[8]; /* Holding place for WINED3DFVF_TEXTUREFORMATx */
373 /* Either 3 or 4 floats depending on the FVF */
374 /* FIXME: Can blending data be in a different stream to the position data?
375 and if so using the fixed pipeline how do we handle it */
376 if (thisFVF & WINED3DFVF_POSITION_MASK) {
377 strided->u.s.position.lpData = data;
378 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
379 strided->u.s.position.dwStride = stride;
380 strided->u.s.position.VBO = streamVBO;
381 data += 3 * sizeof(float);
382 if (thisFVF & WINED3DFVF_XYZRHW) {
383 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
384 strided->u.s.position_transformed = TRUE;
385 data += sizeof(float);
386 } else
387 strided->u.s.position_transformed = FALSE;
390 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
391 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
392 numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
393 if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
395 if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
396 TRACE("Setting blend Weights to %p\n", data);
397 strided->u.s.blendWeights.lpData = data;
398 strided->u.s.blendWeights.dwType = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
399 strided->u.s.blendWeights.dwStride = stride;
400 strided->u.s.blendWeights.VBO = streamVBO;
401 data += numBlends * sizeof(FLOAT);
403 if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
404 strided->u.s.blendMatrixIndices.lpData = data;
405 strided->u.s.blendMatrixIndices.dwType = WINED3DDECLTYPE_UBYTE4;
406 strided->u.s.blendMatrixIndices.dwStride= stride;
407 strided->u.s.blendMatrixIndices.VBO = streamVBO;
408 data += sizeof(DWORD);
412 /* Normal is always 3 floats */
413 if (thisFVF & WINED3DFVF_NORMAL) {
414 strided->u.s.normal.lpData = data;
415 strided->u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
416 strided->u.s.normal.dwStride = stride;
417 strided->u.s.normal.VBO = streamVBO;
418 data += 3 * sizeof(FLOAT);
421 /* Pointsize is a single float */
422 if (thisFVF & WINED3DFVF_PSIZE) {
423 strided->u.s.pSize.lpData = data;
424 strided->u.s.pSize.dwType = WINED3DDECLTYPE_FLOAT1;
425 strided->u.s.pSize.dwStride = stride;
426 strided->u.s.pSize.VBO = streamVBO;
427 data += sizeof(FLOAT);
430 /* Diffuse is 4 unsigned bytes */
431 if (thisFVF & WINED3DFVF_DIFFUSE) {
432 strided->u.s.diffuse.lpData = data;
433 strided->u.s.diffuse.dwType = WINED3DDECLTYPE_SHORT4;
434 strided->u.s.diffuse.dwStride = stride;
435 strided->u.s.diffuse.VBO = streamVBO;
436 data += sizeof(DWORD);
439 /* Specular is 4 unsigned bytes */
440 if (thisFVF & WINED3DFVF_SPECULAR) {
441 strided->u.s.specular.lpData = data;
442 strided->u.s.specular.dwType = WINED3DDECLTYPE_SHORT4;
443 strided->u.s.specular.dwStride = stride;
444 strided->u.s.specular.VBO = streamVBO;
445 data += sizeof(DWORD);
448 /* Texture coords */
449 numTextures = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
450 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
452 /* numTextures indicates the number of texture coordinates supplied */
453 /* However, the first set may not be for stage 0 texture - it all */
454 /* depends on WINED3DTSS_TEXCOORDINDEX. */
455 /* The number of bytes for each coordinate set is based off */
456 /* WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
458 /* So, for each supplied texture extract the coords */
459 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
461 strided->u.s.texCoords[textureNo].lpData = data;
462 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT1;
463 strided->u.s.texCoords[textureNo].dwStride = stride;
464 strided->u.s.texCoords[textureNo].VBO = streamVBO;
465 numCoords[textureNo] = coordIdxInfo & 0x03;
467 /* Always one set */
468 data += sizeof(float);
469 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
470 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
471 data += sizeof(float);
472 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
473 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
474 data += sizeof(float);
475 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
476 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
477 data += sizeof(float);
481 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
485 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, BOOL *fixup) {
487 short LoopThroughTo = 0;
488 short nStream;
489 GLint streamVBO = 0;
491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
493 /* OK, Now to setup the data locations
494 For the non-created vertex shaders, the VertexShader var holds the real
495 FVF and only stream 0 matters
496 For the created vertex shaders, there is an FVF per stream */
497 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
498 LoopThroughTo = MAX_STREAMS;
499 } else {
500 LoopThroughTo = 1;
503 /* Work through stream by stream */
504 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
505 DWORD stride = This->stateBlock->streamStride[nStream];
506 BYTE *data = NULL;
507 DWORD thisFVF = 0;
509 /* Skip empty streams */
510 if (This->stateBlock->streamSource[nStream] == NULL) continue;
512 /* Retrieve appropriate FVF */
513 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
514 thisFVF = This->stateBlock->fvf;
515 /* Handle memory passed directly as well as vertex buffers */
516 if (This->stateBlock->streamIsUP) {
517 streamVBO = 0;
518 data = (BYTE *)This->stateBlock->streamSource[nStream];
519 } else {
520 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
521 /* GetMemory binds the VBO */
522 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
523 if(fixup) {
524 if(streamVBO != 0 ) *fixup = TRUE;
527 } else {
528 #if 0 /* TODO: Vertex shader support */
529 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
530 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
531 #endif
533 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
534 if (thisFVF == 0) continue;
536 /* Now convert the stream into pointers */
537 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
541 #if 0 /* TODO: Software Shaders */
542 /* Draw a single vertex using this information */
543 static void draw_vertex(IWineD3DDevice *iface, /* interface */
544 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
545 BOOL isNormal, float nx, float ny, float nz, /* normal */
546 BOOL isDiffuse, float *dRGBA, /* 1st colors */
547 BOOL isSpecular, float *sRGB, /* 2ndry colors */
548 BOOL isPtSize, float ptSize, /* pointSize */
549 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
551 unsigned int textureNo;
552 float s, t, r, q;
553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
555 /* Diffuse -------------------------------- */
556 if (isDiffuse) {
557 glColor4fv(dRGBA);
558 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
561 /* Specular Colour ------------------------------------------*/
562 if (isSpecular) {
563 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
564 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
565 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
566 } else {
567 VTRACE(("Specular color extensions not supplied\n"));
571 /* Normal -------------------------------- */
572 if (isNormal) {
573 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
574 glNormal3f(nx, ny, nz);
577 /* Point Size ----------------------------------------------*/
578 if (isPtSize) {
580 /* no such functionality in the fixed function GL pipeline */
581 FIXME("Cannot change ptSize here in openGl\n");
584 /* Texture coords --------------------------- */
585 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
587 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
588 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
589 continue ;
592 /* Query tex coords */
593 if (This->stateBlock->textures[textureNo] != NULL) {
595 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
596 if (coordIdx >= MAX_TEXTURES) {
597 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
598 continue;
599 } else if (numcoords[coordIdx] == 0) {
600 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
601 continue;
602 } else {
604 /* Initialize vars */
605 s = 0.0f;
606 t = 0.0f;
607 r = 0.0f;
608 q = 0.0f;
610 switch (numcoords[coordIdx]) {
611 case 4: q = texcoords[coordIdx].w; /* drop through */
612 case 3: r = texcoords[coordIdx].z; /* drop through */
613 case 2: t = texcoords[coordIdx].y; /* drop through */
614 case 1: s = texcoords[coordIdx].x;
617 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
618 case WINED3DTTFF_COUNT1:
619 VTRACE(("tex:%d, s=%f\n", textureNo, s));
620 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
621 GLMULTITEXCOORD1F(textureNo, s);
622 } else {
623 glTexCoord1f(s);
625 break;
626 case WINED3DTTFF_COUNT2:
627 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
628 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
629 GLMULTITEXCOORD2F(textureNo, s, t);
630 } else {
631 glTexCoord2f(s, t);
633 break;
634 case WINED3DTTFF_COUNT3:
635 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
636 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
637 GLMULTITEXCOORD3F(textureNo, s, t, r);
638 } else {
639 glTexCoord3f(s, t, r);
641 break;
642 case WINED3DTTFF_COUNT4:
643 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
644 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
645 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
646 } else {
647 glTexCoord4f(s, t, r, q);
649 break;
650 default:
651 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
655 } /* End of textures */
657 /* Position -------------------------------- */
658 if (isXYZ) {
659 if (1.0f == rhw || rhw < 0.00001f) {
660 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
661 glVertex3f(x, y, z);
662 } else {
663 /* Cannot optimize by dividing through by rhw as rhw is required
664 later for perspective in the GL pipeline for vertex shaders */
665 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
666 glVertex4f(x,y,z,rhw);
670 #endif /* TODO: Software shaders */
672 /* This should match any arrays loaded in loadNumberedArrays. */
673 /* TODO: Only load / unload arrays if we have to. */
674 static void unloadNumberedArrays(IWineD3DDevice *iface) {
675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
677 /* disable any attribs (this is the same for both GLSL and ARB modes) */
678 GLint maxAttribs;
679 int i;
681 /* Leave all the attribs disabled */
682 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs);
683 /* MESA does not support it right not */
684 if (glGetError() != GL_NO_ERROR)
685 maxAttribs = 16;
686 for (i = 0; i < maxAttribs; ++i) {
687 GL_EXTCALL(glDisableVertexAttribArrayARB(i));
688 checkGLcall("glDisableVertexAttribArrayARB(reg);");
692 /* TODO: Only load / unload arrays if we have to. */
693 static void loadNumberedArrays(
694 IWineD3DDevice *iface,
695 IWineD3DVertexShader *shader,
696 WineDirect3DVertexStridedData *strided) {
698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
699 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
700 int i;
702 for (i = 0; i < MAX_ATTRIBS; i++) {
704 if (!strided->u.input[i].lpData && !strided->u.input[i].VBO)
705 continue;
707 TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO);
709 if(curVBO != strided->u.input[i].VBO) {
710 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO));
711 checkGLcall("glBindBufferARB");
712 curVBO = strided->u.input[i].VBO;
714 GL_EXTCALL(glVertexAttribPointerARB(i,
715 WINED3D_ATR_SIZE(strided->u.input[i].dwType),
716 WINED3D_ATR_GLTYPE(strided->u.input[i].dwType),
717 WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType),
718 strided->u.input[i].dwStride,
719 strided->u.input[i].lpData + This->stateBlock->baseVertexIndex * strided->u.input[i].dwStride));
720 GL_EXTCALL(glEnableVertexAttribArrayARB(i));
724 /* This should match any arrays loaded in loadVertexData. */
725 /* TODO: Only load / unload arrays if we have to. */
726 static void unloadVertexData(IWineD3DDevice *iface) {
727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
728 int texture_idx;
730 glDisableClientState(GL_VERTEX_ARRAY);
731 glDisableClientState(GL_NORMAL_ARRAY);
732 glDisableClientState(GL_COLOR_ARRAY);
733 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
734 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
736 for (texture_idx = 0; texture_idx < GL_LIMITS(textures); ++texture_idx) {
737 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
738 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
742 /* TODO: Only load / unload arrays if we have to. */
743 static void loadVertexData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd) {
744 unsigned int textureNo = 0;
745 unsigned int texture_idx = 0;
746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
747 GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0;
749 TRACE("Using fast vertex array code\n");
750 /* Blend Data ---------------------------------------------- */
751 if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) ||
752 (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) {
755 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
757 #if 1
758 glEnableClientState(GL_WEIGHT_ARRAY_ARB);
759 checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)");
760 #endif
762 TRACE("Blend %d %p %d\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
763 sd->u.s.blendWeights.lpData + This->stateBlock->baseVertexIndex * sd->u.s.blendWeights.dwStride, sd->u.s.blendWeights.dwStride);
764 /* FIXME("TODO\n");*/
765 /* Note dwType == float3 or float4 == 2 or 3 */
767 #if 0
768 /* with this on, the normals appear to be being modified,
769 but the vertices aren't being translated as they should be
770 Maybe the world matrix aren't being setup properly? */
771 glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1);
772 #endif
775 VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %d, %p)\n",
776 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) ,
777 sd->u.s.blendWeights.dwStride,
778 sd->u.s.blendWeights.lpData + This->stateBlock->baseVertexIndex * sd->u.s.blendWeights.dwStride));
780 if(curVBO != sd->u.s.blendWeights.VBO) {
781 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO));
782 checkGLcall("glBindBufferARB");
783 curVBO = sd->u.s.blendWeights.VBO;
786 GL_EXTCALL(glWeightPointerARB)(
787 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
788 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
789 sd->u.s.blendWeights.dwStride,
790 sd->u.s.blendWeights.lpData + This->stateBlock->baseVertexIndex * sd->u.s.blendWeights.dwStride);
792 checkGLcall("glWeightPointerARB");
794 if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){
795 static BOOL showfixme = TRUE;
796 if(showfixme){
797 FIXME("blendMatrixIndices support\n");
798 showfixme = FALSE;
802 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
803 /* FIXME("TODO\n");*/
804 #if 0
806 GL_EXTCALL(glVertexWeightPointerEXT)(
807 WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType),
808 WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType),
809 sd->u.s.blendWeights.dwStride,
810 sd->u.s.blendWeights.lpData + This->stateBlock->baseVertexIndex * sd->u.s.blendWeights.dwStride);
811 checkGLcall("glVertexWeightPointerEXT(numBlends, ...)");
812 glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
813 checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
814 #endif
816 } else {
817 /* TODO: support blends in fixupVertices */
818 FIXME("unsupported blending in openGl\n");
820 } else {
821 if (GL_SUPPORT(ARB_VERTEX_BLEND)) {
822 #if 0 /* TODO: Vertex blending */
823 glDisable(GL_VERTEX_BLEND_ARB);
824 #endif
825 TRACE("ARB_VERTEX_BLEND\n");
826 } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) {
827 TRACE(" EXT_VERTEX_WEIGHTING\n");
828 glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT);
829 checkGLcall("glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)");
834 #if 0 /* FOG ----------------------------------------------*/
835 if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) {
836 /* TODO: fog*/
837 if (GL_SUPPORT(EXT_FOG_COORD) {
838 glEnableClientState(GL_FOG_COORDINATE_EXT);
839 (GL_EXTCALL)(FogCoordPointerEXT)(
840 WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType),
841 sd->u.s.fog.dwStride,
842 sd->u.s.fog.lpData + This->stateBlock->baseVertexIndex * sd->u.s.fog.dwStride);
843 } else {
844 /* don't bother falling back to 'slow' as we don't support software FOG yet. */
845 /* FIXME: fixme once */
846 TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n");
848 } else {
849 if (GL_SUPPRT(EXT_FOR_COORD) {
850 /* make sure fog is disabled */
851 glDisableClientState(GL_FOG_COORDINATE_EXT);
854 #endif
856 #if 0 /* tangents ----------------------------------------------*/
857 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO ||
858 sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
859 /* TODO: tangents*/
860 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
861 if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) {
862 glEnable(GL_TANGENT_ARRAY_EXT);
863 (GL_EXTCALL)(TangentPointerEXT)(
864 WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType),
865 sd->u.s.tangent.dwStride,
866 sd->u.s.tangent.lpData + This->stateBlock->baseVertexIndex * sd->u.s.tangent.dwStride);
867 } else {
868 glDisable(GL_TANGENT_ARRAY_EXT);
870 if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) {
871 glEnable(GL_BINORMAL_ARRAY_EXT);
872 (GL_EXTCALL)(BinormalPointerEXT)(
873 WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType),
874 sd->u.s.binormal.dwStride,
875 sd->u.s.binormal.lpData + This->stateBlock->baseVertexIndex * sd->u.s.binormal.dwStride);
876 } else{
877 glDisable(GL_BINORMAL_ARRAY_EXT);
880 } else {
881 /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */
882 /* FIXME: fixme once */
883 TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n");
885 } else {
886 if (GL_SUPPORT(EXT_COORDINATE_FRAME) {
887 /* make sure fog is disabled */
888 glDisable(GL_TANGENT_ARRAY_EXT);
889 glDisable(GL_BINORMAL_ARRAY_EXT);
892 #endif
894 /* Point Size ----------------------------------------------*/
895 if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) {
897 /* no such functionality in the fixed function GL pipeline */
898 TRACE("Cannot change ptSize here in openGl\n");
899 /* TODO: Implement this function in using shaders if they are available */
903 /* Vertex Pointers -----------------------------------------*/
904 if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) {
905 /* Note dwType == float3 or float4 == 2 or 3 */
906 VTRACE(("glVertexPointer(%d, GL_FLOAT, %d, %p)\n",
907 sd->u.s.position.dwStride,
908 sd->u.s.position.dwType + 1,
909 sd->u.s.position.lpData));
911 if(curVBO != sd->u.s.position.VBO) {
912 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO));
913 checkGLcall("glBindBufferARB");
914 curVBO = sd->u.s.position.VBO;
917 /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord
918 handling for rhw mode should not impact screen position whereas in GL it does.
919 This may result in very slightly distored textures in rhw mode, but
920 a very minimal different. There's always the other option of
921 fixing the view matrix to prevent w from having any effect
923 This only applies to user pointer sources, in VBOs the vertices are fixed up
925 if(sd->u.s.position.VBO == 0) {
926 glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */,
927 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
928 sd->u.s.position.dwStride, sd->u.s.position.lpData + This->stateBlock->baseVertexIndex * sd->u.s.position.dwStride);
929 } else {
930 glVertexPointer(
931 WINED3D_ATR_SIZE(sd->u.s.position.dwType),
932 WINED3D_ATR_GLTYPE(sd->u.s.position.dwType),
933 sd->u.s.position.dwStride, sd->u.s.position.lpData + This->stateBlock->baseVertexIndex * sd->u.s.position.dwStride);
935 checkGLcall("glVertexPointer(...)");
936 glEnableClientState(GL_VERTEX_ARRAY);
937 checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)");
939 } else {
940 glDisableClientState(GL_VERTEX_ARRAY);
941 checkGLcall("glDisableClientState(GL_VERTEX_ARRAY)");
944 /* Normals -------------------------------------------------*/
945 if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) {
946 /* Note dwType == float3 or float4 == 2 or 3 */
947 VTRACE(("glNormalPointer(GL_FLOAT, %d, %p)\n",
948 sd->u.s.normal.dwStride,
949 sd->u.s.normal.lpData));
950 if(curVBO != sd->u.s.normal.VBO) {
951 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO));
952 checkGLcall("glBindBufferARB");
953 curVBO = sd->u.s.normal.VBO;
955 glNormalPointer(
956 WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType),
957 sd->u.s.normal.dwStride,
958 sd->u.s.normal.lpData + This->stateBlock->baseVertexIndex * sd->u.s.normal.dwStride);
959 checkGLcall("glNormalPointer(...)");
960 glEnableClientState(GL_NORMAL_ARRAY);
961 checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)");
963 } else {
964 glDisableClientState(GL_NORMAL_ARRAY);
965 checkGLcall("glDisableClientState(GL_NORMAL_ARRAY)");
966 glNormal3f(0, 0, 1);
967 checkGLcall("glNormal3f(0, 0, 1)");
970 /* Diffuse Colour --------------------------------------------*/
971 /* WARNING: Data here MUST be in RGBA format, so cannot */
972 /* go directly into fast mode from app pgm, because */
973 /* directx requires data in BGRA format. */
974 /* currently fixupVertices swizels the format, but this isn't */
975 /* very practical when using VBOS */
976 /* NOTE: Unless we write a vertex shader to swizel the colour */
977 /* , or the user doesn't care and wants the speed advantage */
979 if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) {
980 /* Note dwType == float3 or float4 == 2 or 3 */
981 VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
982 sd->u.s.diffuse.dwStride,
983 sd->u.s.diffuse.lpData));
985 if(curVBO != sd->u.s.diffuse.VBO) {
986 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO));
987 checkGLcall("glBindBufferARB");
988 curVBO = sd->u.s.diffuse.VBO;
990 glColorPointer(4, GL_UNSIGNED_BYTE,
991 sd->u.s.diffuse.dwStride,
992 sd->u.s.diffuse.lpData + This->stateBlock->baseVertexIndex * sd->u.s.diffuse.dwStride);
993 checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)");
994 glEnableClientState(GL_COLOR_ARRAY);
995 checkGLcall("glEnableClientState(GL_COLOR_ARRAY)");
997 } else {
998 glDisableClientState(GL_COLOR_ARRAY);
999 checkGLcall("glDisableClientState(GL_COLOR_ARRAY)");
1000 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1001 checkGLcall("glColor4f(1, 1, 1, 1)");
1004 /* Specular Colour ------------------------------------------*/
1005 if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) {
1006 TRACE("setting specular colour\n");
1007 /* Note dwType == float3 or float4 == 2 or 3 */
1008 VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n",
1009 sd->u.s.specular.dwStride,
1010 sd->u.s.specular.lpData));
1011 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1012 if(curVBO != sd->u.s.specular.VBO) {
1013 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO));
1014 checkGLcall("glBindBufferARB");
1015 curVBO = sd->u.s.specular.VBO;
1017 GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE,
1018 sd->u.s.specular.dwStride,
1019 sd->u.s.specular.lpData + This->stateBlock->baseVertexIndex * sd->u.s.specular.dwStride);
1020 vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)");
1021 glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1022 vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1023 } else {
1025 /* Missing specular color is not critical, no warnings */
1026 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1029 } else {
1030 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1032 glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT);
1033 checkGLcall("glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)");
1034 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1035 checkGLcall("glSecondaryColor3fEXT(0, 0, 0)");
1036 } else {
1038 /* Missing specular color is not critical, no warnings */
1039 VTRACE(("Specular colour is not supported in this GL implementation\n"));
1043 /* Texture coords -------------------------------------------*/
1045 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1046 /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */
1047 /* Abort if we don't support the extension. */
1048 if (!GL_SUPPORT(ARB_MULTITEXTURE)) {
1049 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1050 continue;
1053 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/ TRUE) {
1054 /* Select the correct texture stage */
1055 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx));
1058 if (This->stateBlock->textures[textureNo] != NULL) {
1059 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1061 if (coordIdx >= MAX_TEXTURES) {
1062 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1063 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1064 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1066 } else if (sd->u.s.texCoords[coordIdx].lpData == NULL && sd->u.s.texCoords[coordIdx].VBO == 0) {
1067 VTRACE(("Bound texture but no texture coordinates supplied, so skipping\n"));
1068 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1069 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, 0, 0, 0, 1));
1071 } else {
1072 TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n",
1073 textureNo, texture_idx, coordIdx, sd->u.s.texCoords[coordIdx].lpData);
1074 if(curVBO != sd->u.s.texCoords[coordIdx].VBO) {
1075 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO));
1076 checkGLcall("glBindBufferARB");
1077 curVBO = sd->u.s.texCoords[coordIdx].VBO;
1079 /* The coords to supply depend completely on the fvf / vertex shader */
1080 glTexCoordPointer(
1081 WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType),
1082 WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType),
1083 sd->u.s.texCoords[coordIdx].dwStride,
1084 sd->u.s.texCoords[coordIdx].lpData + This->stateBlock->baseVertexIndex * sd->u.s.texCoords[coordIdx].dwStride);
1085 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1087 } else if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1088 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1089 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1091 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/ TRUE) ++texture_idx;
1093 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
1094 for (textureNo = texture_idx; textureNo < GL_LIMITS(textures); ++textureNo) {
1095 GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + textureNo));
1096 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1097 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1));
1102 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
1103 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
1104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1106 if (idxData != NULL /* This crashes sometimes!*/) {
1107 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
1108 idxData = idxData == (void *)-1 ? NULL : idxData;
1109 #if 1
1110 #if 0
1111 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
1112 glEnableClientState(GL_INDEX_ARRAY);
1113 #endif
1114 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1115 (const char *)idxData+(idxSize * startIdx));
1116 #else /* using drawRangeElements may be faster */
1118 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
1119 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
1120 (const char *)idxData+(idxSize * startIdx));
1121 #endif
1122 checkGLcall("glDrawRangeElements");
1124 } else {
1126 /* Note first is now zero as we shuffled along earlier */
1127 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
1128 glDrawArrays(glPrimitiveType, startVertex, numberOfVertices);
1129 checkGLcall("glDrawArrays");
1133 return;
1137 * Actually draw using the supplied information.
1138 * Slower GL version which extracts info about each vertex in turn
1141 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1142 UINT NumVertexes, GLenum glPrimType,
1143 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
1145 unsigned int textureNo = 0;
1146 unsigned int texture_idx = 0;
1147 const short *pIdxBufS = NULL;
1148 const long *pIdxBufL = NULL;
1149 LONG vx_index;
1150 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1151 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
1152 float rhw = 0.0f; /* rhw */
1153 float ptSize = 0.0f; /* Point size */
1154 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
1155 DWORD specularColor = 0; /* Specular Color */
1156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1157 LONG SkipnStrides = startVertex + This->stateBlock->baseVertexIndex;
1159 TRACE("Using slow vertex array code\n");
1161 /* Variable Initialization */
1162 if (idxData != NULL) {
1163 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1164 else pIdxBufL = (const long *) idxData;
1167 /* Start drawing in GL */
1168 VTRACE(("glBegin(%x)\n", glPrimType));
1169 glBegin(glPrimType);
1171 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
1172 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
1175 /* For each primitive */
1176 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1178 /* Initialize diffuse color */
1179 diffuseColor = 0xFFFFFFFF;
1181 /* For indexed data, we need to go a few more strides in */
1182 if (idxData != NULL) {
1184 /* Indexed so work out the number of strides to skip */
1185 if (idxSize == 2) {
1186 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1187 SkipnStrides = pIdxBufS[startIdx + vx_index] + This->stateBlock->baseVertexIndex;
1188 } else {
1189 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1190 SkipnStrides = pIdxBufL[startIdx + vx_index] + This->stateBlock->baseVertexIndex;
1194 /* Position Information ------------------ */
1195 if (sd->u.s.position.lpData != NULL) {
1197 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
1198 x = ptrToCoords[0];
1199 y = ptrToCoords[1];
1200 z = ptrToCoords[2];
1201 rhw = 1.0;
1202 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
1204 /* RHW follows, only if transformed, ie 4 floats were provided */
1205 if (sd->u.s.position_transformed) {
1206 rhw = ptrToCoords[3];
1207 VTRACE(("rhw=%f\n", rhw));
1211 /* Blending data -------------------------- */
1212 if (sd->u.s.blendWeights.lpData != NULL) {
1213 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
1214 FIXME("Blending not supported yet\n");
1216 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
1217 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
1221 /* Vertex Normal Data (untransformed only)- */
1222 if (sd->u.s.normal.lpData != NULL) {
1224 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
1225 nx = ptrToCoords[0];
1226 ny = ptrToCoords[1];
1227 nz = ptrToCoords[2];
1228 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
1231 /* Point Size ----------------------------- */
1232 if (sd->u.s.pSize.lpData != NULL) {
1234 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
1235 ptSize = ptrToCoords[0];
1236 VTRACE(("ptSize=%f\n", ptSize));
1237 FIXME("No support for ptSize yet\n");
1240 /* Diffuse -------------------------------- */
1241 if (sd->u.s.diffuse.lpData != NULL) {
1243 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
1244 diffuseColor = ptrToCoords[0];
1245 VTRACE(("diffuseColor=%lx\n", diffuseColor));
1248 /* Specular -------------------------------- */
1249 if (sd->u.s.specular.lpData != NULL) {
1251 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
1252 specularColor = ptrToCoords[0];
1253 VTRACE(("specularColor=%lx\n", specularColor));
1256 /* Texture coords --------------------------- */
1257 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
1259 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
1260 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1261 continue ;
1264 /* Query tex coords */
1265 if (This->stateBlock->textures[textureNo] != NULL) {
1267 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
1268 float *ptrToCoords = NULL;
1269 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
1271 if (coordIdx > 7) {
1272 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
1273 ++texture_idx;
1274 continue;
1275 } else if (coordIdx < 0) {
1276 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
1277 ++texture_idx;
1278 continue;
1281 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
1282 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
1283 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
1284 ++texture_idx;
1285 continue;
1286 } else {
1288 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
1290 /* The coords to supply depend completely on the fvf / vertex shader */
1291 switch (coordsToUse) {
1292 case 4: q = ptrToCoords[3]; /* drop through */
1293 case 3: r = ptrToCoords[2]; /* drop through */
1294 case 2: t = ptrToCoords[1]; /* drop through */
1295 case 1: s = ptrToCoords[0];
1298 /* Projected is more 'fun' - Move the last coord to the 'q'
1299 parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
1300 if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
1301 (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
1303 if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
1304 switch (coordsToUse) {
1305 case 0: /* Drop Through */
1306 case 1:
1307 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
1308 break;
1309 case 2:
1310 q = t;
1311 t = 0.0;
1312 coordsToUse = 4;
1313 break;
1314 case 3:
1315 q = r;
1316 r = 0.0;
1317 coordsToUse = 4;
1318 break;
1319 case 4: /* Nop here */
1320 break;
1321 default:
1322 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
1323 This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
1328 switch (coordsToUse) { /* Supply the provided texture coords */
1329 case WINED3DTTFF_COUNT1:
1330 VTRACE(("tex:%d, s=%f\n", textureNo, s));
1331 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1332 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
1333 } else {
1334 glTexCoord1f(s);
1336 break;
1337 case WINED3DTTFF_COUNT2:
1338 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
1339 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1340 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
1341 } else {
1342 glTexCoord2f(s, t);
1344 break;
1345 case WINED3DTTFF_COUNT3:
1346 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
1347 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1348 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
1349 } else {
1350 glTexCoord3f(s, t, r);
1352 break;
1353 case WINED3DTTFF_COUNT4:
1354 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
1355 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1356 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
1357 } else {
1358 glTexCoord4f(s, t, r, q);
1360 break;
1361 default:
1362 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
1366 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/TRUE) ++texture_idx;
1367 } /* End of textures */
1369 /* Diffuse -------------------------------- */
1370 if (sd->u.s.diffuse.lpData != NULL) {
1371 glColor4ub(D3DCOLOR_B_R(diffuseColor),
1372 D3DCOLOR_B_G(diffuseColor),
1373 D3DCOLOR_B_B(diffuseColor),
1374 D3DCOLOR_B_A(diffuseColor));
1375 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
1376 D3DCOLOR_B_R(diffuseColor),
1377 D3DCOLOR_B_G(diffuseColor),
1378 D3DCOLOR_B_B(diffuseColor),
1379 D3DCOLOR_B_A(diffuseColor)));
1380 } else {
1381 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1384 /* Specular ------------------------------- */
1385 if (sd->u.s.specular.lpData != NULL) {
1386 /* special case where the fog density is stored in the diffuse alpha channel */
1387 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
1388 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
1389 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
1390 if(GL_SUPPORT(EXT_FOG_COORD)) {
1391 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
1392 } else {
1393 static BOOL warned = FALSE;
1394 if(!warned) {
1395 /* TODO: Use the fog table code from old ddraw */
1396 FIXME("Implement fog for transformed vertices in software\n");
1397 warned = TRUE;
1402 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
1403 D3DCOLOR_B_R(specularColor),
1404 D3DCOLOR_B_G(specularColor),
1405 D3DCOLOR_B_B(specularColor)));
1406 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1407 GL_EXTCALL(glSecondaryColor3ubEXT)(
1408 D3DCOLOR_B_R(specularColor),
1409 D3DCOLOR_B_G(specularColor),
1410 D3DCOLOR_B_B(specularColor));
1411 } else {
1412 /* Do not worry if specular colour missing and disable request */
1413 VTRACE(("Specular color extensions not supplied\n"));
1415 } else {
1416 if (vx_index == 0) {
1417 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
1418 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
1419 } else {
1420 /* Do not worry if specular colour missing and disable request */
1421 VTRACE(("Specular color extensions not supplied\n"));
1426 /* Normal -------------------------------- */
1427 if (sd->u.s.normal.lpData != NULL) {
1428 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
1429 glNormal3f(nx, ny, nz);
1430 } else {
1431 if (vx_index == 0) glNormal3f(0, 0, 1);
1434 /* Position -------------------------------- */
1435 if (sd->u.s.position.lpData != NULL) {
1436 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
1437 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
1438 glVertex3f(x, y, z);
1439 } else {
1440 GLfloat w = 1.0 / rhw;
1441 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
1442 glVertex4f(x*w, y*w, z*w, w);
1446 /* For non indexed mode, step onto next parts */
1447 if (idxData == NULL) {
1448 ++SkipnStrides;
1452 glEnd();
1453 checkGLcall("glEnd and previous calls");
1456 #if 0 /* TODO: Software/Hardware vertex blending support */
1458 * Draw with emulated vertex shaders
1459 * Note: strided data is uninitialized, as we need to pass the vertex
1460 * shader directly as ordering irs yet
1462 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
1463 int PrimitiveType, ULONG NumPrimitives,
1464 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
1466 unsigned int textureNo = 0;
1467 GLenum glPrimType = GL_POINTS;
1468 int NumVertexes = NumPrimitives;
1469 const short *pIdxBufS = NULL;
1470 const long *pIdxBufL = NULL;
1471 LONG SkipnStrides = 0;
1472 LONG vx_index;
1473 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
1474 float rhw = 0.0f; /* rhw */
1475 float ptSize = 0.0f; /* Point size */
1476 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
1477 int numcoords[8]; /* Number of coords */
1478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1480 IDirect3DVertexShaderImpl* vertexShader = NULL;
1482 TRACE("Using slow software vertex shader code\n");
1484 /* Variable Initialization */
1485 if (idxData != NULL) {
1486 if (idxSize == 2) pIdxBufS = (const short *) idxData;
1487 else pIdxBufL = (const long *) idxData;
1490 /* Ok, Work out which primitive is requested and how many vertexes that will be */
1491 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1493 /* Retrieve the VS information */
1494 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
1496 /* Start drawing in GL */
1497 VTRACE(("glBegin(%x)\n", glPrimType));
1498 glBegin(glPrimType);
1500 /* For each primitive */
1501 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
1503 /* For indexed data, we need to go a few more strides in */
1504 if (idxData != NULL) {
1506 /* Indexed so work out the number of strides to skip */
1507 if (idxSize == 2) {
1508 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1509 SkipnStrides = pIdxBufS[startIdx+vx_index];
1510 } else {
1511 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1512 SkipnStrides = pIdxBufL[startIdx+vx_index];
1516 /* Fill the vertex shader input */
1517 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1519 /* Initialize the output fields to the same defaults as it would normally have */
1520 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1521 vertexShader->output.oD[0].x = 1.0;
1522 vertexShader->output.oD[0].y = 1.0;
1523 vertexShader->output.oD[0].z = 1.0;
1524 vertexShader->output.oD[0].w = 1.0;
1526 /* Now execute the vertex shader */
1527 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1530 TRACE_VECTOR(vertexShader->output.oPos);
1531 TRACE_VECTOR(vertexShader->output.oD[0]);
1532 TRACE_VECTOR(vertexShader->output.oD[1]);
1533 TRACE_VECTOR(vertexShader->output.oT[0]);
1534 TRACE_VECTOR(vertexShader->output.oT[1]);
1535 TRACE_VECTOR(vertexShader->input.V[0]);
1536 TRACE_VECTOR(vertexShader->data->C[0]);
1537 TRACE_VECTOR(vertexShader->data->C[1]);
1538 TRACE_VECTOR(vertexShader->data->C[2]);
1539 TRACE_VECTOR(vertexShader->data->C[3]);
1540 TRACE_VECTOR(vertexShader->data->C[4]);
1541 TRACE_VECTOR(vertexShader->data->C[5]);
1542 TRACE_VECTOR(vertexShader->data->C[6]);
1543 TRACE_VECTOR(vertexShader->data->C[7]);
1546 /* Extract out the output */
1547 /* FIXME: Fog coords? */
1548 x = vertexShader->output.oPos.x;
1549 y = vertexShader->output.oPos.y;
1550 z = vertexShader->output.oPos.z;
1551 rhw = vertexShader->output.oPos.w;
1552 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1554 /** Update textures coords using vertexShader->output.oT[0->7] */
1555 memset(texcoords, 0x00, sizeof(texcoords));
1556 memset(numcoords, 0x00, sizeof(numcoords));
1557 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1558 if (This->stateBlock->textures[textureNo] != NULL) {
1559 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1560 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1561 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1562 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1563 if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1564 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1565 } else {
1566 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1567 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1568 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1569 default: numcoords[textureNo] = 4;
1572 } else {
1573 numcoords[textureNo] = 0;
1577 /* Draw using this information */
1578 draw_vertex(iface,
1579 TRUE, x, y, z, rhw,
1580 TRUE, 0.0f, 0.0f, 1.0f,
1581 TRUE, (float*) &vertexShader->output.oD[0],
1582 TRUE, (float*) &vertexShader->output.oD[1],
1583 FALSE, ptSize, /* FIXME: Change back when supported */
1584 texcoords, numcoords);
1586 /* For non indexed mode, step onto next parts */
1587 if (idxData == NULL) {
1588 ++SkipnStrides;
1591 } /* for each vertex */
1593 glEnd();
1594 checkGLcall("glEnd and previous calls");
1597 #endif
1599 inline static void drawPrimitiveDrawStrided(
1600 IWineD3DDevice *iface,
1601 BOOL useVertexShaderFunction,
1602 BOOL usePixelShaderFunction,
1603 WineDirect3DVertexStridedData *dataLocations,
1604 ULONG baseVIndex,
1605 UINT numberOfvertices,
1606 UINT numberOfIndicies,
1607 GLenum glPrimType,
1608 const void *idxData,
1609 short idxSize,
1610 int minIndex,
1611 long StartIdx,
1612 BOOL fixup) {
1614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1615 BOOL useDrawStridedSlow;
1617 int startStride = idxData == NULL ? 0 :
1618 idxData == (void *) -1 ? 0 :
1619 (idxSize == 2 ? *(((const short *) idxData) + StartIdx) : *((const int *) idxData) + StartIdx);
1620 int endStride = startStride;
1621 TRACE("begin Start stride %d, end stride %d, number of indices%d, number of vertices%d\n",
1622 startStride, endStride, numberOfIndicies, numberOfvertices);
1624 /* Generate some fixme's if unsupported functionality is being used */
1625 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1626 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1627 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1628 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1630 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1631 FIXME("Tweening is only valid with vertex shaders\n");
1633 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1634 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1636 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1637 FIXME("Extended attributes are only valid with vertex shaders\n");
1639 #undef BUFFER_OR_DATA
1641 /* Fixed pipeline, no fixups required - load arrays */
1642 if (!useVertexShaderFunction &&
1643 ((dataLocations->u.s.pSize.lpData == NULL &&
1644 dataLocations->u.s.diffuse.lpData == NULL &&
1645 dataLocations->u.s.specular.lpData == NULL) ||
1646 fixup) ) {
1648 /* Load the vertex data using named arrays */
1649 TRACE("(%p) Loading vertex data\n", This);
1650 loadVertexData(iface, dataLocations);
1651 useDrawStridedSlow = FALSE;
1653 /* Shader pipeline - load attribute arrays */
1654 } else if(useVertexShaderFunction) {
1656 loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
1657 useDrawStridedSlow = FALSE;
1659 /* We compile the shader here because we need the vertex declaration
1660 * in order to determine if we need to do any swizzling for D3DCOLOR
1661 * registers. If the shader is already compiled this call will do nothing. */
1662 IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
1663 /* Draw vertex by vertex */
1664 } else {
1665 TRACE("Not loading vertex data\n");
1666 useDrawStridedSlow = TRUE;
1669 /* Make any shaders active */
1670 This->shader_backend->shader_select(iface, usePixelShaderFunction, useVertexShaderFunction);
1672 /* Load any global constants/uniforms that may have been set by the application */
1673 This->shader_backend->shader_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1675 /* Draw vertex-by-vertex */
1676 if (useDrawStridedSlow)
1677 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1678 else
1679 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1681 /* Cleanup any shaders */
1682 This->shader_backend->shader_cleanup(usePixelShaderFunction, useVertexShaderFunction);
1684 /* Unload vertex data */
1685 if (useVertexShaderFunction) {
1686 unloadNumberedArrays(iface);
1687 } else {
1688 unloadVertexData(iface);
1692 inline void drawPrimitiveTraceDataLocations(
1693 WineDirect3DVertexStridedData *dataLocations) {
1695 /* Dump out what parts we have supplied */
1696 TRACE("Strided Data:\n");
1697 TRACE_STRIDED((dataLocations), position);
1698 TRACE_STRIDED((dataLocations), blendWeights);
1699 TRACE_STRIDED((dataLocations), blendMatrixIndices);
1700 TRACE_STRIDED((dataLocations), normal);
1701 TRACE_STRIDED((dataLocations), pSize);
1702 TRACE_STRIDED((dataLocations), diffuse);
1703 TRACE_STRIDED((dataLocations), specular);
1704 TRACE_STRIDED((dataLocations), texCoords[0]);
1705 TRACE_STRIDED((dataLocations), texCoords[1]);
1706 TRACE_STRIDED((dataLocations), texCoords[2]);
1707 TRACE_STRIDED((dataLocations), texCoords[3]);
1708 TRACE_STRIDED((dataLocations), texCoords[4]);
1709 TRACE_STRIDED((dataLocations), texCoords[5]);
1710 TRACE_STRIDED((dataLocations), texCoords[6]);
1711 TRACE_STRIDED((dataLocations), texCoords[7]);
1712 TRACE_STRIDED((dataLocations), position2);
1713 TRACE_STRIDED((dataLocations), normal2);
1714 TRACE_STRIDED((dataLocations), tangent);
1715 TRACE_STRIDED((dataLocations), binormal);
1716 TRACE_STRIDED((dataLocations), tessFactor);
1717 TRACE_STRIDED((dataLocations), fog);
1718 TRACE_STRIDED((dataLocations), depth);
1719 TRACE_STRIDED((dataLocations), sample);
1721 return;
1725 static void check_fbo_status(IWineD3DDevice *iface) {
1726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1728 GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
1729 switch(status) {
1730 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
1731 default: TRACE("FBO status %#x.\n", status); break;
1735 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
1736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1737 GLint old_binding = 0;
1739 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
1741 glDisable(GL_CULL_FACE);
1742 glDisable(GL_BLEND);
1743 glDisable(GL_ALPHA_TEST);
1744 glDisable(GL_STENCIL_TEST);
1745 glEnable(GL_DEPTH_TEST);
1746 glDepthFunc(GL_ALWAYS);
1748 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1749 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1750 glBindTexture(GL_TEXTURE_2D, texture);
1751 glEnable(GL_TEXTURE_2D);
1753 This->shader_backend->shader_select_depth_blt(iface);
1755 glBegin(GL_TRIANGLE_STRIP);
1756 glVertex2f(-1.0f, -1.0f);
1757 glVertex2f(1.0f, -1.0f);
1758 glVertex2f(-1.0f, 1.0f);
1759 glVertex2f(1.0f, 1.0f);
1760 glEnd();
1762 glBindTexture(GL_TEXTURE_2D, old_binding);
1764 glPopAttrib();
1767 static void depth_copy(IWineD3DDevice *iface) {
1768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1769 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
1771 /* Only copy the depth buffer if there is one. */
1772 if (!depth_stencil) return;
1774 /* TODO: Make this work for modes other than FBO */
1775 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
1777 if (This->render_offscreen) {
1778 static GLuint tmp_texture = 0;
1779 GLint old_binding = 0;
1781 TRACE("Copying onscreen depth buffer to offscreen surface\n");
1783 if (!tmp_texture) {
1784 glGenTextures(1, &tmp_texture);
1787 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
1788 * directly on the FBO texture. That's because we need to flip. */
1789 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1790 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1791 glBindTexture(GL_TEXTURE_2D, tmp_texture);
1792 glCopyTexImage2D(depth_stencil->glDescription.target,
1793 depth_stencil->glDescription.level,
1794 depth_stencil->glDescription.glFormatInternal,
1797 depth_stencil->currentDesc.Width,
1798 depth_stencil->currentDesc.Height,
1800 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1801 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1802 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
1803 glBindTexture(GL_TEXTURE_2D, old_binding);
1805 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
1806 checkGLcall("glBindFramebuffer()");
1807 depth_blt(iface, tmp_texture);
1808 checkGLcall("depth_blt");
1809 } else {
1810 TRACE("Copying offscreen surface to onscreen depth buffer\n");
1812 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1813 checkGLcall("glBindFramebuffer()");
1814 depth_blt(iface, depth_stencil->glDescription.textureName);
1815 checkGLcall("depth_blt");
1819 /* Routine common to the draw primitive and draw indexed primitive routines */
1820 void drawPrimitive(IWineD3DDevice *iface,
1821 int PrimitiveType,
1822 long NumPrimitives,
1823 /* for Indexed: */
1824 long StartVertexIndex,
1825 UINT numberOfVertices,
1826 long StartIdx,
1827 short idxSize,
1828 const void *idxData,
1829 int minIndex) {
1831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1832 BOOL useVertexShaderFunction = FALSE;
1833 BOOL usePixelShaderFunction = FALSE;
1834 IWineD3DSwapChainImpl *swapchain;
1835 int i;
1836 BOOL fixup;
1837 DWORD dirtyState, idx;
1838 BYTE shift;
1840 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
1841 * here simply check whether a shader was set, or the user disabled shaders */
1842 if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
1843 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
1844 useVertexShaderFunction = TRUE;
1846 if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
1847 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
1848 usePixelShaderFunction = TRUE;
1850 /* Invalidate the back buffer memory so LockRect will read it the next time */
1851 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
1852 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
1853 if(swapchain) {
1854 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
1855 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1859 /* Ok, we will be updating the screen from here onwards so grab the lock */
1860 ENTER_GL();
1862 /* Apply dirty states */
1863 for(i=0; i < This->numDirtyEntries; i++) {
1864 dirtyState = This->dirtyArray[i];
1865 idx = dirtyState >> 5;
1866 shift = dirtyState & 0x1f;
1867 This->isStateDirty[idx] &= ~(1 << shift);
1868 StateTable[dirtyState].apply(dirtyState, This->stateBlock);
1870 This->numDirtyEntries = 0; /* This makes the whole list clean */
1871 fixup = This->streamFixedUp;
1873 if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1874 check_fbo_status(iface);
1877 if (This->depth_copy_state == WINED3D_DCS_COPY) {
1878 depth_copy(iface);
1880 This->depth_copy_state = WINED3D_DCS_INITIAL;
1882 /* Now initialize the materials state */
1883 init_materials(iface, (This->strided_streams.u.s.diffuse.lpData != NULL || This->strided_streams.u.s.diffuse.VBO != 0));
1886 GLenum glPrimType;
1887 /* Ok, Work out which primitive is requested and how many vertexes that
1888 will be */
1889 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1890 if (numberOfVertices == 0 )
1891 numberOfVertices = calculatedNumberOfindices;
1893 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
1894 &This->strided_streams, StartVertexIndex, numberOfVertices, calculatedNumberOfindices, glPrimType,
1895 idxData, idxSize, minIndex, StartIdx, fixup);
1898 /* Finshed updating the screen, restore lock */
1899 LEAVE_GL();
1900 TRACE("Done all gl drawing\n");
1902 /* Diagnostics */
1903 #ifdef SHOW_FRAME_MAKEUP
1905 static long int primCounter = 0;
1906 /* NOTE: set primCounter to the value reported by drawprim
1907 before you want to to write frame makeup to /tmp */
1908 if (primCounter >= 0) {
1909 WINED3DLOCKED_RECT r;
1910 char buffer[80];
1911 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
1912 sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
1913 TRACE("Saving screenshot %s\n", buffer);
1914 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
1915 IWineD3DSurface_UnlockRect(This->renderTarget);
1917 #ifdef SHOW_TEXTURE_MAKEUP
1919 IWineD3DSurface *pSur;
1920 int textureNo;
1921 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1922 if (This->stateBlock->textures[textureNo] != NULL) {
1923 sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
1924 TRACE("Saving texture %s\n", buffer);
1925 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
1926 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
1927 IWineD3DSurface_SaveSnapshot(pSur, buffer);
1928 IWineD3DSurface_Release(pSur);
1929 } else {
1930 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
1935 #endif
1937 TRACE("drawprim #%d\n", primCounter);
1938 ++primCounter;
1940 #endif