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
26 #include "wined3d_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
29 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
34 extern IWineD3DVertexShaderImpl* VertexShaders[64];
35 extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64];
36 extern IWineD3DPixelShaderImpl* PixelShaders[64];
38 #undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
41 /* Issues the glBegin call for gl given the primitive type and count */
42 static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType,
46 DWORD NumVertexes = NumPrimitives;
48 switch (PrimitiveType) {
49 case WINED3DPT_POINTLIST:
51 *primType = GL_POINTS;
52 NumVertexes = NumPrimitives;
55 case WINED3DPT_LINELIST:
58 NumVertexes = NumPrimitives * 2;
61 case WINED3DPT_LINESTRIP:
62 TRACE("LINE_STRIP\n");
63 *primType = GL_LINE_STRIP;
64 NumVertexes = NumPrimitives + 1;
67 case WINED3DPT_TRIANGLELIST:
69 *primType = GL_TRIANGLES;
70 NumVertexes = NumPrimitives * 3;
73 case WINED3DPT_TRIANGLESTRIP:
74 TRACE("TRIANGLE_STRIP\n");
75 *primType = GL_TRIANGLE_STRIP;
76 NumVertexes = NumPrimitives + 2;
79 case WINED3DPT_TRIANGLEFAN:
80 TRACE("TRIANGLE_FAN\n");
81 *primType = GL_TRIANGLE_FAN;
82 NumVertexes = NumPrimitives + 2;
86 FIXME("Unhandled primitive\n");
87 *primType = GL_POINTS;
93 /* Ensure the appropriate material states are set up - only change
94 state if really required */
95 static void init_materials(IWineD3DDevice *iface, BOOL isDiffuseSupplied) {
97 BOOL requires_material_reset = FALSE;
98 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
100 if (This->tracking_color == NEEDS_TRACKING && isDiffuseSupplied) {
101 /* If we have not set up the material color tracking, do it now as required */
102 glDisable(GL_COLOR_MATERIAL); /* Note: Man pages state must enable AFTER calling glColorMaterial! Required?*/
103 checkGLcall("glDisable GL_COLOR_MATERIAL");
104 TRACE("glColorMaterial Parm=%x\n", This->tracking_parm);
105 glColorMaterial(GL_FRONT_AND_BACK, This->tracking_parm);
106 checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)");
107 glEnable(GL_COLOR_MATERIAL);
108 checkGLcall("glEnable GL_COLOR_MATERIAL");
109 This->tracking_color = IS_TRACKING;
110 requires_material_reset = TRUE; /* Restore material settings as will be used */
112 } else if ((This->tracking_color == IS_TRACKING && !isDiffuseSupplied) ||
113 (This->tracking_color == NEEDS_TRACKING && !isDiffuseSupplied)) {
114 /* If we are tracking the current color but one isn't supplied, don't! */
115 glDisable(GL_COLOR_MATERIAL);
116 checkGLcall("glDisable GL_COLOR_MATERIAL");
117 This->tracking_color = NEEDS_TRACKING;
118 requires_material_reset = TRUE; /* Restore material settings as will be used */
120 } else if (This->tracking_color == IS_TRACKING && isDiffuseSupplied) {
121 /* No need to reset material colors since no change to gl_color_material */
122 requires_material_reset = FALSE;
124 } else if (This->tracking_color == NEEDS_DISABLE) {
125 glDisable(GL_COLOR_MATERIAL);
126 checkGLcall("glDisable GL_COLOR_MATERIAL");
127 This->tracking_color = DISABLED_TRACKING;
128 requires_material_reset = TRUE; /* Restore material settings as will be used */
131 /* Reset the material colors which may have been tracking the color*/
132 if (requires_material_reset) {
133 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->stateBlock->material.Ambient);
134 checkGLcall("glMaterialfv");
135 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->stateBlock->material.Diffuse);
136 checkGLcall("glMaterialfv");
137 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
138 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->stateBlock->material.Specular);
139 checkGLcall("glMaterialfv");
141 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
142 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
143 checkGLcall("glMaterialfv");
145 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->stateBlock->material.Emissive);
146 checkGLcall("glMaterialfv");
151 static const GLfloat invymat[16] = {
152 1.0f, 0.0f, 0.0f, 0.0f,
153 0.0f, -1.0f, 0.0f, 0.0f,
154 0.0f, 0.0f, 1.0f, 0.0f,
155 0.0f, 0.0f, 0.0f, 1.0f};
157 static BOOL fixed_get_input(
158 BYTE usage, BYTE usage_idx,
159 unsigned int* regnum) {
163 /* Those positions must have the order in the
164 * named part of the strided data */
166 if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 0)
168 else if (usage == D3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
170 else if (usage == D3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
172 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 0)
174 else if (usage == D3DDECLUSAGE_PSIZE && usage_idx == 0)
176 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 0)
178 else if (usage == D3DDECLUSAGE_COLOR && usage_idx == 1)
180 else if (usage == D3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
181 *regnum = 7 + usage_idx;
182 else if ((usage == D3DDECLUSAGE_POSITION || usage == D3DDECLUSAGE_POSITIONT) && usage_idx == 1)
183 *regnum = 7 + WINED3DDP_MAXTEXCOORD;
184 else if (usage == D3DDECLUSAGE_NORMAL && usage_idx == 1)
185 *regnum = 8 + WINED3DDP_MAXTEXCOORD;
186 else if (usage == D3DDECLUSAGE_TANGENT && usage_idx == 0)
187 *regnum = 9 + WINED3DDP_MAXTEXCOORD;
188 else if (usage == D3DDECLUSAGE_BINORMAL && usage_idx == 0)
189 *regnum = 10 + WINED3DDP_MAXTEXCOORD;
190 else if (usage == D3DDECLUSAGE_TESSFACTOR && usage_idx == 0)
191 *regnum = 11 + WINED3DDP_MAXTEXCOORD;
192 else if (usage == D3DDECLUSAGE_FOG && usage_idx == 0)
193 *regnum = 12 + WINED3DDP_MAXTEXCOORD;
194 else if (usage == D3DDECLUSAGE_DEPTH && usage_idx == 0)
195 *regnum = 13 + WINED3DDP_MAXTEXCOORD;
196 else if (usage == D3DDECLUSAGE_SAMPLE && usage_idx == 0)
197 *regnum = 14 + WINED3DDP_MAXTEXCOORD;
200 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
201 debug_d3ddeclusage(usage), usage_idx);
207 void primitiveDeclarationConvertToStridedData(
208 IWineD3DDevice *iface,
209 BOOL useVertexShaderFunction,
210 WineDirect3DVertexStridedData *strided,
213 /* We need to deal with frequency data!*/
216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
217 IWineD3DVertexDeclarationImpl* vertexDeclaration = NULL;
219 WINED3DVERTEXELEMENT *element;
223 /* Locate the vertex declaration */
224 if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) {
225 TRACE("Using vertex declaration from shader\n");
226 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration;
228 TRACE("Using vertex declaration\n");
229 vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
232 /* Translate the declaration into strided data */
233 for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
238 element = vertexDeclaration->pDeclarationWine + i;
239 TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine,
240 element, i + 1, vertexDeclaration->declarationWNumElements - 1);
242 if (This->stateBlock->streamSource[element->Stream] == NULL)
245 if (This->stateBlock->streamIsUP) {
246 TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
248 data = (BYTE *)This->stateBlock->streamSource[element->Stream];
249 if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
251 TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]);
252 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]);
253 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
255 if( streamVBO != 0) *fixup = TRUE;
256 else if(*fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
259 stride = This->stateBlock->streamStride[element->Stream];
260 data += element->Offset;
263 TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex);
265 if (useVertexShaderFunction)
266 stride_used = vshader_get_input(This->stateBlock->vertexShader,
267 element->Usage, element->UsageIndex, &idx);
269 stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx);
272 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
273 "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
274 useVertexShaderFunction? "shader": "fixed function", idx,
275 debug_d3ddeclusage(element->Usage), element->UsageIndex,
276 element->Stream, element->Offset, stride, streamVBO);
278 strided->u.input[idx].lpData = data;
279 strided->u.input[idx].dwType = element->Type;
280 strided->u.input[idx].dwStride = stride;
281 strided->u.input[idx].VBO = streamVBO;
282 if (!useVertexShaderFunction) {
283 if (element->Usage == D3DDECLUSAGE_POSITION)
284 strided->u.s.position_transformed = FALSE;
285 else if (element->Usage == D3DDECLUSAGE_POSITIONT)
286 strided->u.s.position_transformed = TRUE;
292 void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) {
296 int coordIdxInfo = 0x00; /* Information on number of coords supplied */
297 int numCoords[8]; /* Holding place for WINED3DFVF_TEXTUREFORMATx */
299 /* Either 3 or 4 floats depending on the FVF */
300 /* FIXME: Can blending data be in a different stream to the position data?
301 and if so using the fixed pipeline how do we handle it */
302 if (thisFVF & WINED3DFVF_POSITION_MASK) {
303 strided->u.s.position.lpData = data;
304 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
305 strided->u.s.position.dwStride = stride;
306 strided->u.s.position.VBO = streamVBO;
307 data += 3 * sizeof(float);
308 if (thisFVF & WINED3DFVF_XYZRHW) {
309 strided->u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
310 strided->u.s.position_transformed = TRUE;
311 data += sizeof(float);
313 strided->u.s.position_transformed = FALSE;
316 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
317 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
318 numBlends = 1 + (((thisFVF & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
319 if(thisFVF & WINED3DFVF_LASTBETA_UBYTE4) numBlends--;
321 if ((thisFVF & WINED3DFVF_XYZB5 ) > WINED3DFVF_XYZRHW) {
322 TRACE("Setting blend Weights to %p\n", data);
323 strided->u.s.blendWeights.lpData = data;
324 strided->u.s.blendWeights.dwType = WINED3DDECLTYPE_FLOAT1 + numBlends - 1;
325 strided->u.s.blendWeights.dwStride = stride;
326 strided->u.s.blendWeights.VBO = streamVBO;
327 data += numBlends * sizeof(FLOAT);
329 if (thisFVF & WINED3DFVF_LASTBETA_UBYTE4) {
330 strided->u.s.blendMatrixIndices.lpData = data;
331 strided->u.s.blendMatrixIndices.dwType = WINED3DDECLTYPE_UBYTE4;
332 strided->u.s.blendMatrixIndices.dwStride= stride;
333 strided->u.s.blendMatrixIndices.VBO = streamVBO;
334 data += sizeof(DWORD);
338 /* Normal is always 3 floats */
339 if (thisFVF & WINED3DFVF_NORMAL) {
340 strided->u.s.normal.lpData = data;
341 strided->u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
342 strided->u.s.normal.dwStride = stride;
343 strided->u.s.normal.VBO = streamVBO;
344 data += 3 * sizeof(FLOAT);
347 /* Pointsize is a single float */
348 if (thisFVF & WINED3DFVF_PSIZE) {
349 strided->u.s.pSize.lpData = data;
350 strided->u.s.pSize.dwType = WINED3DDECLTYPE_FLOAT1;
351 strided->u.s.pSize.dwStride = stride;
352 strided->u.s.pSize.VBO = streamVBO;
353 data += sizeof(FLOAT);
356 /* Diffuse is 4 unsigned bytes */
357 if (thisFVF & WINED3DFVF_DIFFUSE) {
358 strided->u.s.diffuse.lpData = data;
359 strided->u.s.diffuse.dwType = WINED3DDECLTYPE_SHORT4;
360 strided->u.s.diffuse.dwStride = stride;
361 strided->u.s.diffuse.VBO = streamVBO;
362 data += sizeof(DWORD);
365 /* Specular is 4 unsigned bytes */
366 if (thisFVF & WINED3DFVF_SPECULAR) {
367 strided->u.s.specular.lpData = data;
368 strided->u.s.specular.dwType = WINED3DDECLTYPE_SHORT4;
369 strided->u.s.specular.dwStride = stride;
370 strided->u.s.specular.VBO = streamVBO;
371 data += sizeof(DWORD);
375 numTextures = (thisFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
376 coordIdxInfo = (thisFVF & 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
378 /* numTextures indicates the number of texture coordinates supplied */
379 /* However, the first set may not be for stage 0 texture - it all */
380 /* depends on WINED3DTSS_TEXCOORDINDEX. */
381 /* The number of bytes for each coordinate set is based off */
382 /* WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
384 /* So, for each supplied texture extract the coords */
385 for (textureNo = 0; textureNo < numTextures; ++textureNo) {
387 strided->u.s.texCoords[textureNo].lpData = data;
388 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT1;
389 strided->u.s.texCoords[textureNo].dwStride = stride;
390 strided->u.s.texCoords[textureNo].VBO = streamVBO;
391 numCoords[textureNo] = coordIdxInfo & 0x03;
394 data += sizeof(float);
395 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT1) {
396 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT2;
397 data += sizeof(float);
398 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT2) {
399 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT3;
400 data += sizeof(float);
401 if (numCoords[textureNo] != WINED3DFVF_TEXTUREFORMAT3) {
402 strided->u.s.texCoords[textureNo].dwType = WINED3DDECLTYPE_FLOAT4;
403 data += sizeof(float);
407 coordIdxInfo = coordIdxInfo >> 2; /* Drop bottom two bits */
411 void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStridedData *strided, BOOL *fixup) {
413 short LoopThroughTo = 0;
417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 /* OK, Now to setup the data locations
420 For the non-created vertex shaders, the VertexShader var holds the real
421 FVF and only stream 0 matters
422 For the created vertex shaders, there is an FVF per stream */
423 if (!This->stateBlock->streamIsUP && !(This->stateBlock->vertexShader == NULL)) {
424 LoopThroughTo = MAX_STREAMS;
429 /* Work through stream by stream */
430 for (nStream=0; nStream<LoopThroughTo; ++nStream) {
431 DWORD stride = This->stateBlock->streamStride[nStream];
435 /* Skip empty streams */
436 if (This->stateBlock->streamSource[nStream] == NULL) continue;
438 /* Retrieve appropriate FVF */
439 if (LoopThroughTo == 1) { /* Use FVF, not vertex shader */
440 thisFVF = This->stateBlock->fvf;
441 /* Handle memory passed directly as well as vertex buffers */
442 if (This->stateBlock->streamIsUP) {
444 data = (BYTE *)This->stateBlock->streamSource[nStream];
446 IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]);
447 /* GetMemory binds the VBO */
448 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO);
450 if(streamVBO != 0 ) *fixup = TRUE;
454 #if 0 /* TODO: Vertex shader support */
455 thisFVF = This->stateBlock->vertexShaderDecl->fvf[nStream];
456 data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0);
459 VTRACE(("FVF for stream %d is %lx\n", nStream, thisFVF));
460 if (thisFVF == 0) continue;
462 /* Now convert the stream into pointers */
463 primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO);
467 #if 0 /* TODO: Software Shaders */
468 /* Draw a single vertex using this information */
469 static void draw_vertex(IWineD3DDevice *iface, /* interface */
470 BOOL isXYZ, float x, float y, float z, float rhw, /* xyzn position*/
471 BOOL isNormal, float nx, float ny, float nz, /* normal */
472 BOOL isDiffuse, float *dRGBA, /* 1st colors */
473 BOOL isSpecular, float *sRGB, /* 2ndry colors */
474 BOOL isPtSize, float ptSize, /* pointSize */
475 WINED3DVECTOR_4 *texcoords, int *numcoords) /* texture info */
477 unsigned int textureNo;
479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
481 /* Diffuse -------------------------------- */
484 VTRACE(("glColor4f: r,g,b,a=%f,%f,%f,%f\n", dRGBA[0], dRGBA[1], dRGBA[2], dRGBA[3]));
487 /* Specular Colour ------------------------------------------*/
489 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
490 GL_EXTCALL(glSecondaryColor3fvEXT(sRGB));
491 VTRACE(("glSecondaryColor4f: r,g,b=%f,%f,%f\n", sRGB[0], sRGB[1], sRGB[2]));
493 VTRACE(("Specular color extensions not supplied\n"));
497 /* Normal -------------------------------- */
499 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
500 glNormal3f(nx, ny, nz);
503 /* Point Size ----------------------------------------------*/
506 /* no such functionality in the fixed function GL pipeline */
507 FIXME("Cannot change ptSize here in openGl\n");
510 /* Texture coords --------------------------- */
511 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
513 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
514 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
518 /* Query tex coords */
519 if (This->stateBlock->textures[textureNo] != NULL) {
521 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
522 if (coordIdx >= MAX_TEXTURES) {
523 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
525 } else if (numcoords[coordIdx] == 0) {
526 TRACE("tex: %d - Skipping tex coords, as no data supplied or no coords supplied\n", textureNo);
530 /* Initialize vars */
536 switch (numcoords[coordIdx]) {
537 case 4: q = texcoords[coordIdx].w; /* drop through */
538 case 3: r = texcoords[coordIdx].z; /* drop through */
539 case 2: t = texcoords[coordIdx].y; /* drop through */
540 case 1: s = texcoords[coordIdx].x;
543 switch (numcoords[coordIdx]) { /* Supply the provided texture coords */
544 case WINED3DTTFF_COUNT1:
545 VTRACE(("tex:%d, s=%f\n", textureNo, s));
546 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
547 GLMULTITEXCOORD1F(textureNo, s);
552 case WINED3DTTFF_COUNT2:
553 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
554 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
555 GLMULTITEXCOORD2F(textureNo, s, t);
560 case WINED3DTTFF_COUNT3:
561 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
562 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
563 GLMULTITEXCOORD3F(textureNo, s, t, r);
565 glTexCoord3f(s, t, r);
568 case WINED3DTTFF_COUNT4:
569 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
570 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
571 GLMULTITEXCOORD4F(textureNo, s, t, r, q);
573 glTexCoord4f(s, t, r, q);
577 FIXME("Should not get here as numCoords should be 0->4 (%x)!\n", numcoords[coordIdx]);
581 } /* End of textures */
583 /* Position -------------------------------- */
585 if (1.0f == rhw || rhw < 0.00001f) {
586 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
589 /* Cannot optimize by dividing through by rhw as rhw is required
590 later for perspective in the GL pipeline for vertex shaders */
591 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
592 glVertex4f(x,y,z,rhw);
596 #endif /* TODO: Software shaders */
598 static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType,
599 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
602 if (idxData != NULL /* This crashes sometimes!*/) {
603 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex);
604 idxData = idxData == (void *)-1 ? NULL : idxData;
607 glIndexPointer(idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idxSize, startIdx);
608 glEnableClientState(GL_INDEX_ARRAY);
610 glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
611 (const char *)idxData+(idxSize * startIdx));
612 #else /* using drawRangeElements may be faster */
614 glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices,
615 idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
616 (const char *)idxData+(idxSize * startIdx));
618 checkGLcall("glDrawRangeElements");
622 /* Note first is now zero as we shuffled along earlier */
623 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices);
624 glDrawArrays(glPrimitiveType, startVertex, numberOfVertices);
625 checkGLcall("glDrawArrays");
633 * Actually draw using the supplied information.
634 * Slower GL version which extracts info about each vertex in turn
637 static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
638 UINT NumVertexes, GLenum glPrimType,
639 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) {
641 unsigned int textureNo = 0;
642 unsigned int texture_idx = 0;
643 const short *pIdxBufS = NULL;
644 const long *pIdxBufL = NULL;
646 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
647 float nx = 0.0f, ny = 0.0, nz = 0.0f; /* normal x,y,z coordinates */
648 float rhw = 0.0f; /* rhw */
649 float ptSize = 0.0f; /* Point size */
650 DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */
651 DWORD specularColor = 0; /* Specular Color */
652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
653 LONG SkipnStrides = startVertex + This->stateBlock->baseVertexIndex;
655 TRACE("Using slow vertex array code\n");
657 /* Variable Initialization */
658 if (idxData != NULL) {
659 if (idxSize == 2) pIdxBufS = (const short *) idxData;
660 else pIdxBufL = (const long *) idxData;
663 /* Start drawing in GL */
664 VTRACE(("glBegin(%x)\n", glPrimType));
667 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
668 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
671 /* For each primitive */
672 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
674 /* Initialize diffuse color */
675 diffuseColor = 0xFFFFFFFF;
677 /* For indexed data, we need to go a few more strides in */
678 if (idxData != NULL) {
680 /* Indexed so work out the number of strides to skip */
682 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
683 SkipnStrides = pIdxBufS[startIdx + vx_index] + This->stateBlock->baseVertexIndex;
685 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
686 SkipnStrides = pIdxBufL[startIdx + vx_index] + This->stateBlock->baseVertexIndex;
690 /* Position Information ------------------ */
691 if (sd->u.s.position.lpData != NULL) {
693 float *ptrToCoords = (float *)(sd->u.s.position.lpData + (SkipnStrides * sd->u.s.position.dwStride));
698 VTRACE(("x,y,z=%f,%f,%f\n", x,y,z));
700 /* RHW follows, only if transformed, ie 4 floats were provided */
701 if (sd->u.s.position_transformed) {
702 rhw = ptrToCoords[3];
703 VTRACE(("rhw=%f\n", rhw));
707 /* Blending data -------------------------- */
708 if (sd->u.s.blendWeights.lpData != NULL) {
709 /* float *ptrToCoords = (float *)(sd->u.s.blendWeights.lpData + (SkipnStrides * sd->u.s.blendWeights.dwStride)); */
710 FIXME("Blending not supported yet\n");
712 if (sd->u.s.blendMatrixIndices.lpData != NULL) {
713 /*DWORD *ptrToCoords = (DWORD *)(sd->u.s.blendMatrixIndices.lpData + (SkipnStrides * sd->u.s.blendMatrixIndices.dwStride));*/
717 /* Vertex Normal Data (untransformed only)- */
718 if (sd->u.s.normal.lpData != NULL) {
720 float *ptrToCoords = (float *)(sd->u.s.normal.lpData + (SkipnStrides * sd->u.s.normal.dwStride));
724 VTRACE(("nx,ny,nz=%f,%f,%f\n", nx, ny, nz));
727 /* Point Size ----------------------------- */
728 if (sd->u.s.pSize.lpData != NULL) {
730 float *ptrToCoords = (float *)(sd->u.s.pSize.lpData + (SkipnStrides * sd->u.s.pSize.dwStride));
731 ptSize = ptrToCoords[0];
732 VTRACE(("ptSize=%f\n", ptSize));
733 FIXME("No support for ptSize yet\n");
736 /* Diffuse -------------------------------- */
737 if (sd->u.s.diffuse.lpData != NULL) {
739 DWORD *ptrToCoords = (DWORD *)(sd->u.s.diffuse.lpData + (SkipnStrides * sd->u.s.diffuse.dwStride));
740 diffuseColor = ptrToCoords[0];
741 VTRACE(("diffuseColor=%lx\n", diffuseColor));
744 /* Specular -------------------------------- */
745 if (sd->u.s.specular.lpData != NULL) {
747 DWORD *ptrToCoords = (DWORD *)(sd->u.s.specular.lpData + (SkipnStrides * sd->u.s.specular.dwStride));
748 specularColor = ptrToCoords[0];
749 VTRACE(("specularColor=%lx\n", specularColor));
752 /* Texture coords --------------------------- */
753 for (textureNo = 0, texture_idx = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) {
755 if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) {
756 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
760 /* Query tex coords */
761 if (This->stateBlock->textures[textureNo] != NULL) {
763 int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX];
764 float *ptrToCoords = NULL;
765 float s = 0.0, t = 0.0, r = 0.0, q = 0.0;
768 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo));
771 } else if (coordIdx < 0) {
772 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx);
777 ptrToCoords = (float *)(sd->u.s.texCoords[coordIdx].lpData + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride));
778 if (sd->u.s.texCoords[coordIdx].lpData == NULL) {
779 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo);
784 int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
786 /* The coords to supply depend completely on the fvf / vertex shader */
787 switch (coordsToUse) {
788 case 4: q = ptrToCoords[3]; /* drop through */
789 case 3: r = ptrToCoords[2]; /* drop through */
790 case 2: t = ptrToCoords[1]; /* drop through */
791 case 1: s = ptrToCoords[0];
794 /* Projected is more 'fun' - Move the last coord to the 'q'
795 parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
796 if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) &&
797 (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) {
799 if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) {
800 switch (coordsToUse) {
801 case 0: /* Drop Through */
803 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
815 case 4: /* Nop here */
818 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
819 This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED);
824 switch (coordsToUse) { /* Supply the provided texture coords */
825 case WINED3DTTFF_COUNT1:
826 VTRACE(("tex:%d, s=%f\n", textureNo, s));
827 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
828 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx, s));
833 case WINED3DTTFF_COUNT2:
834 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t));
835 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
836 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx, s, t));
841 case WINED3DTTFF_COUNT3:
842 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r));
843 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
844 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx, s, t, r));
846 glTexCoord3f(s, t, r);
849 case WINED3DTTFF_COUNT4:
850 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q));
851 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
852 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx, s, t, r, q));
854 glTexCoord4f(s, t, r, q);
858 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse);
862 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/TRUE) ++texture_idx;
863 } /* End of textures */
865 /* Diffuse -------------------------------- */
866 if (sd->u.s.diffuse.lpData != NULL) {
867 glColor4ub(D3DCOLOR_B_R(diffuseColor),
868 D3DCOLOR_B_G(diffuseColor),
869 D3DCOLOR_B_B(diffuseColor),
870 D3DCOLOR_B_A(diffuseColor));
871 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
872 D3DCOLOR_B_R(diffuseColor),
873 D3DCOLOR_B_G(diffuseColor),
874 D3DCOLOR_B_B(diffuseColor),
875 D3DCOLOR_B_A(diffuseColor)));
877 if (vx_index == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
880 /* Specular ------------------------------- */
881 if (sd->u.s.specular.lpData != NULL) {
882 /* special case where the fog density is stored in the diffuse alpha channel */
883 if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] &&
884 (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&&
885 This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
886 if(GL_SUPPORT(EXT_FOG_COORD)) {
887 GL_EXTCALL(glFogCoordfEXT(specularColor >> 24));
889 static BOOL warned = FALSE;
891 /* TODO: Use the fog table code from old ddraw */
892 FIXME("Implement fog for transformed vertices in software\n");
898 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
899 D3DCOLOR_B_R(specularColor),
900 D3DCOLOR_B_G(specularColor),
901 D3DCOLOR_B_B(specularColor)));
902 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
903 GL_EXTCALL(glSecondaryColor3ubEXT)(
904 D3DCOLOR_B_R(specularColor),
905 D3DCOLOR_B_G(specularColor),
906 D3DCOLOR_B_B(specularColor));
908 /* Do not worry if specular colour missing and disable request */
909 VTRACE(("Specular color extensions not supplied\n"));
913 if (GL_SUPPORT(EXT_SECONDARY_COLOR)) {
914 GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0);
916 /* Do not worry if specular colour missing and disable request */
917 VTRACE(("Specular color extensions not supplied\n"));
922 /* Normal -------------------------------- */
923 if (sd->u.s.normal.lpData != NULL) {
924 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", nx,ny,nz));
925 glNormal3f(nx, ny, nz);
927 if (vx_index == 0) glNormal3f(0, 0, 1);
930 /* Position -------------------------------- */
931 if (sd->u.s.position.lpData != NULL) {
932 if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) {
933 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z));
936 GLfloat w = 1.0 / rhw;
937 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw));
938 glVertex4f(x*w, y*w, z*w, w);
942 /* For non indexed mode, step onto next parts */
943 if (idxData == NULL) {
949 checkGLcall("glEnd and previous calls");
952 #if 0 /* TODO: Software/Hardware vertex blending support */
954 * Draw with emulated vertex shaders
955 * Note: strided data is uninitialized, as we need to pass the vertex
956 * shader directly as ordering irs yet
958 void drawStridedSoftwareVS(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd,
959 int PrimitiveType, ULONG NumPrimitives,
960 const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx) {
962 unsigned int textureNo = 0;
963 GLenum glPrimType = GL_POINTS;
964 int NumVertexes = NumPrimitives;
965 const short *pIdxBufS = NULL;
966 const long *pIdxBufL = NULL;
967 LONG SkipnStrides = 0;
969 float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */
970 float rhw = 0.0f; /* rhw */
971 float ptSize = 0.0f; /* Point size */
972 D3DVECTOR_4 texcoords[8]; /* Texture Coords */
973 int numcoords[8]; /* Number of coords */
974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IDirect3DVertexShaderImpl* vertexShader = NULL;
978 TRACE("Using slow software vertex shader code\n");
980 /* Variable Initialization */
981 if (idxData != NULL) {
982 if (idxSize == 2) pIdxBufS = (const short *) idxData;
983 else pIdxBufL = (const long *) idxData;
986 /* Ok, Work out which primitive is requested and how many vertexes that will be */
987 NumVertexes = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
989 /* Retrieve the VS information */
990 vertexShader = (IWineD3DVertexShaderImp *)This->stateBlock->VertexShader;
992 /* Start drawing in GL */
993 VTRACE(("glBegin(%x)\n", glPrimType));
996 /* For each primitive */
997 for (vx_index = 0; vx_index < NumVertexes; ++vx_index) {
999 /* For indexed data, we need to go a few more strides in */
1000 if (idxData != NULL) {
1002 /* Indexed so work out the number of strides to skip */
1004 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index]));
1005 SkipnStrides = pIdxBufS[startIdx+vx_index];
1007 VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index]));
1008 SkipnStrides = pIdxBufL[startIdx+vx_index];
1012 /* Fill the vertex shader input */
1013 IDirect3DDeviceImpl_FillVertexShaderInputSW(This, vertexShader, SkipnStrides);
1015 /* Initialize the output fields to the same defaults as it would normally have */
1016 memset(&vertexShader->output, 0, sizeof(VSHADEROUTPUTDATA8));
1017 vertexShader->output.oD[0].x = 1.0;
1018 vertexShader->output.oD[0].y = 1.0;
1019 vertexShader->output.oD[0].z = 1.0;
1020 vertexShader->output.oD[0].w = 1.0;
1022 /* Now execute the vertex shader */
1023 IDirect3DVertexShaderImpl_ExecuteSW(vertexShader, &vertexShader->input, &vertexShader->output);
1026 TRACE_VECTOR(vertexShader->output.oPos);
1027 TRACE_VECTOR(vertexShader->output.oD[0]);
1028 TRACE_VECTOR(vertexShader->output.oD[1]);
1029 TRACE_VECTOR(vertexShader->output.oT[0]);
1030 TRACE_VECTOR(vertexShader->output.oT[1]);
1031 TRACE_VECTOR(vertexShader->input.V[0]);
1032 TRACE_VECTOR(vertexShader->data->C[0]);
1033 TRACE_VECTOR(vertexShader->data->C[1]);
1034 TRACE_VECTOR(vertexShader->data->C[2]);
1035 TRACE_VECTOR(vertexShader->data->C[3]);
1036 TRACE_VECTOR(vertexShader->data->C[4]);
1037 TRACE_VECTOR(vertexShader->data->C[5]);
1038 TRACE_VECTOR(vertexShader->data->C[6]);
1039 TRACE_VECTOR(vertexShader->data->C[7]);
1042 /* Extract out the output */
1043 /* FIXME: Fog coords? */
1044 x = vertexShader->output.oPos.x;
1045 y = vertexShader->output.oPos.y;
1046 z = vertexShader->output.oPos.z;
1047 rhw = vertexShader->output.oPos.w;
1048 ptSize = vertexShader->output.oPts.x; /* Fixme - Is this right? */
1050 /** Update textures coords using vertexShader->output.oT[0->7] */
1051 memset(texcoords, 0x00, sizeof(texcoords));
1052 memset(numcoords, 0x00, sizeof(numcoords));
1053 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1054 if (This->stateBlock->textures[textureNo] != NULL) {
1055 texcoords[textureNo].x = vertexShader->output.oT[textureNo].x;
1056 texcoords[textureNo].y = vertexShader->output.oT[textureNo].y;
1057 texcoords[textureNo].z = vertexShader->output.oT[textureNo].z;
1058 texcoords[textureNo].w = vertexShader->output.oT[textureNo].w;
1059 if (This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) {
1060 numcoords[textureNo] = This->stateBlock->texture_state[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & ~WINED3DTTFF_PROJECTED;
1062 switch (IDirect3DBaseTexture8Impl_GetType((LPDIRECT3DBASETEXTURE8) This->stateBlock->textures[textureNo])) {
1063 case WINED3DRTYPE_TEXTURE: numcoords[textureNo] = 2; break;
1064 case WINED3DRTYPE_VOLUMETEXTURE: numcoords[textureNo] = 3; break;
1065 default: numcoords[textureNo] = 4;
1069 numcoords[textureNo] = 0;
1073 /* Draw using this information */
1076 TRUE, 0.0f, 0.0f, 1.0f,
1077 TRUE, (float*) &vertexShader->output.oD[0],
1078 TRUE, (float*) &vertexShader->output.oD[1],
1079 FALSE, ptSize, /* FIXME: Change back when supported */
1080 texcoords, numcoords);
1082 /* For non indexed mode, step onto next parts */
1083 if (idxData == NULL) {
1087 } /* for each vertex */
1090 checkGLcall("glEnd and previous calls");
1095 inline static void drawPrimitiveDrawStrided(
1096 IWineD3DDevice *iface,
1097 BOOL useVertexShaderFunction,
1098 BOOL usePixelShaderFunction,
1099 WineDirect3DVertexStridedData *dataLocations,
1101 UINT numberOfvertices,
1102 UINT numberOfIndicies,
1104 const void *idxData,
1109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1111 /* Generate some fixme's if unsupported functionality is being used */
1112 #define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData
1113 /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */
1114 if (!useVertexShaderFunction && (BUFFER_OR_DATA(blendMatrixIndices) || BUFFER_OR_DATA(blendWeights))) {
1115 FIXME("Blending data is only valid with vertex shaders %p %p\n",dataLocations->u.s.blendWeights.lpData,dataLocations->u.s.blendWeights.lpData);
1117 if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) {
1118 FIXME("Tweening is only valid with vertex shaders\n");
1120 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) {
1121 FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n");
1123 if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) {
1124 FIXME("Extended attributes are only valid with vertex shaders\n");
1126 #undef BUFFER_OR_DATA
1128 /* Make any shaders active */
1129 This->shader_backend->shader_select(iface, usePixelShaderFunction, useVertexShaderFunction);
1131 /* Load any global constants/uniforms that may have been set by the application */
1132 This->shader_backend->shader_load_constants(iface, usePixelShaderFunction, useVertexShaderFunction);
1134 /* Draw vertex-by-vertex */
1135 if (This->useDrawStridedSlow)
1136 drawStridedSlow(iface, dataLocations, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1138 drawStridedFast(iface, numberOfIndicies, glPrimType, idxData, idxSize, minIndex, StartIdx, baseVIndex);
1140 /* Cleanup any shaders */
1141 This->shader_backend->shader_cleanup(usePixelShaderFunction, useVertexShaderFunction);
1144 static void check_fbo_status(IWineD3DDevice *iface) {
1145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1147 GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
1149 case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
1150 default: TRACE("FBO status %#x.\n", status); break;
1154 static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
1155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1156 GLint old_binding = 0;
1158 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
1160 glDisable(GL_CULL_FACE);
1161 glDisable(GL_BLEND);
1162 glDisable(GL_ALPHA_TEST);
1163 glDisable(GL_STENCIL_TEST);
1164 glEnable(GL_DEPTH_TEST);
1165 glDepthFunc(GL_ALWAYS);
1167 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1168 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1169 glBindTexture(GL_TEXTURE_2D, texture);
1170 glEnable(GL_TEXTURE_2D);
1172 This->shader_backend->shader_select_depth_blt(iface);
1174 glBegin(GL_TRIANGLE_STRIP);
1175 glVertex2f(-1.0f, -1.0f);
1176 glVertex2f(1.0f, -1.0f);
1177 glVertex2f(-1.0f, 1.0f);
1178 glVertex2f(1.0f, 1.0f);
1181 glBindTexture(GL_TEXTURE_2D, old_binding);
1186 static void depth_copy(IWineD3DDevice *iface) {
1187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1188 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer;
1190 /* Only copy the depth buffer if there is one. */
1191 if (!depth_stencil) return;
1193 /* TODO: Make this work for modes other than FBO */
1194 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
1196 if (This->render_offscreen) {
1197 static GLuint tmp_texture = 0;
1198 GLint old_binding = 0;
1200 TRACE("Copying onscreen depth buffer to offscreen surface\n");
1203 glGenTextures(1, &tmp_texture);
1206 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
1207 * directly on the FBO texture. That's because we need to flip. */
1208 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1209 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
1210 glBindTexture(GL_TEXTURE_2D, tmp_texture);
1211 glCopyTexImage2D(depth_stencil->glDescription.target,
1212 depth_stencil->glDescription.level,
1213 depth_stencil->glDescription.glFormatInternal,
1216 depth_stencil->currentDesc.Width,
1217 depth_stencil->currentDesc.Height,
1219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1221 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
1222 glBindTexture(GL_TEXTURE_2D, old_binding);
1224 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
1225 checkGLcall("glBindFramebuffer()");
1226 depth_blt(iface, tmp_texture);
1227 checkGLcall("depth_blt");
1229 TRACE("Copying offscreen surface to onscreen depth buffer\n");
1231 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
1232 checkGLcall("glBindFramebuffer()");
1233 depth_blt(iface, depth_stencil->glDescription.textureName);
1234 checkGLcall("depth_blt");
1238 /* Routine common to the draw primitive and draw indexed primitive routines */
1239 void drawPrimitive(IWineD3DDevice *iface,
1243 long StartVertexIndex,
1244 UINT numberOfVertices,
1247 const void *idxData,
1250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1251 BOOL useVertexShaderFunction = FALSE;
1252 BOOL usePixelShaderFunction = FALSE;
1253 IWineD3DSwapChainImpl *swapchain;
1255 DWORD dirtyState, idx;
1258 /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
1259 * here simply check whether a shader was set, or the user disabled shaders */
1260 if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
1261 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL)
1262 useVertexShaderFunction = TRUE;
1264 if (This->ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader &&
1265 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function)
1266 usePixelShaderFunction = TRUE;
1268 /* Invalidate the back buffer memory so LockRect will read it the next time */
1269 for(i = 0; i < IWineD3DDevice_GetNumberOfSwapChains(iface); i++) {
1270 IWineD3DDevice_GetSwapChain(iface, i, (IWineD3DSwapChain **) &swapchain);
1272 if(swapchain->backBuffer) ((IWineD3DSurfaceImpl *) swapchain->backBuffer[0])->Flags |= SFLAG_GLDIRTY;
1273 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1277 /* Ok, we will be updating the screen from here onwards so grab the lock */
1280 /* Apply dirty states */
1281 for(i=0; i < This->numDirtyEntries; i++) {
1282 dirtyState = This->dirtyArray[i];
1283 idx = dirtyState >> 5;
1284 shift = dirtyState & 0x1f;
1285 This->isStateDirty[idx] &= ~(1 << shift);
1286 StateTable[dirtyState].apply(dirtyState, This->stateBlock);
1288 This->numDirtyEntries = 0; /* This makes the whole list clean */
1291 if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1292 check_fbo_status(iface);
1295 if (This->depth_copy_state == WINED3D_DCS_COPY) {
1298 This->depth_copy_state = WINED3D_DCS_INITIAL;
1300 /* Now initialize the materials state */
1301 init_materials(iface, (This->strided_streams.u.s.diffuse.lpData != NULL || This->strided_streams.u.s.diffuse.VBO != 0));
1305 /* Ok, Work out which primitive is requested and how many vertexes that
1307 UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType);
1308 if (numberOfVertices == 0 )
1309 numberOfVertices = calculatedNumberOfindices;
1311 drawPrimitiveDrawStrided(iface, useVertexShaderFunction, usePixelShaderFunction,
1312 &This->strided_streams, StartVertexIndex, numberOfVertices, calculatedNumberOfindices, glPrimType,
1313 idxData, idxSize, minIndex, StartIdx);
1316 /* Finshed updating the screen, restore lock */
1318 TRACE("Done all gl drawing\n");
1321 #ifdef SHOW_FRAME_MAKEUP
1323 static long int primCounter = 0;
1324 /* NOTE: set primCounter to the value reported by drawprim
1325 before you want to to write frame makeup to /tmp */
1326 if (primCounter >= 0) {
1327 WINED3DLOCKED_RECT r;
1329 IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY);
1330 sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter);
1331 TRACE("Saving screenshot %s\n", buffer);
1332 IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer);
1333 IWineD3DSurface_UnlockRect(This->renderTarget);
1335 #ifdef SHOW_TEXTURE_MAKEUP
1337 IWineD3DSurface *pSur;
1339 for (textureNo = 0; textureNo < GL_LIMITS(textures); ++textureNo) {
1340 if (This->stateBlock->textures[textureNo] != NULL) {
1341 sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo);
1342 TRACE("Saving texture %s\n", buffer);
1343 if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) {
1344 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur);
1345 IWineD3DSurface_SaveSnapshot(pSur, buffer);
1346 IWineD3DSurface_Release(pSur);
1348 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]));
1355 TRACE("drawprim #%d\n", primCounter);