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
9 * Copyright 2007 Stefan Dösinger for CodeWeavers
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wined3d_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw
);
30 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
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 */
42 /* Issues the glBegin call for gl given the primitive type and count */
43 static DWORD
primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType
,
47 DWORD NumVertexes
= NumPrimitives
;
49 switch (PrimitiveType
) {
50 case WINED3DPT_POINTLIST
:
52 *primType
= GL_POINTS
;
53 NumVertexes
= NumPrimitives
;
56 case WINED3DPT_LINELIST
:
59 NumVertexes
= NumPrimitives
* 2;
62 case WINED3DPT_LINESTRIP
:
63 TRACE("LINE_STRIP\n");
64 *primType
= GL_LINE_STRIP
;
65 NumVertexes
= NumPrimitives
+ 1;
68 case WINED3DPT_TRIANGLELIST
:
70 *primType
= GL_TRIANGLES
;
71 NumVertexes
= NumPrimitives
* 3;
74 case WINED3DPT_TRIANGLESTRIP
:
75 TRACE("TRIANGLE_STRIP\n");
76 *primType
= GL_TRIANGLE_STRIP
;
77 NumVertexes
= NumPrimitives
+ 2;
80 case WINED3DPT_TRIANGLEFAN
:
81 TRACE("TRIANGLE_FAN\n");
82 *primType
= GL_TRIANGLE_FAN
;
83 NumVertexes
= NumPrimitives
+ 2;
87 FIXME("Unhandled primitive\n");
88 *primType
= GL_POINTS
;
94 static BOOL
fixed_get_input(
95 BYTE usage
, BYTE usage_idx
,
96 unsigned int* regnum
) {
100 /* Those positions must have the order in the
101 * named part of the strided data */
103 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
105 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
107 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
109 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
111 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
113 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
115 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
117 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
118 *regnum
= 7 + usage_idx
;
119 else if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 1)
120 *regnum
= 7 + WINED3DDP_MAXTEXCOORD
;
121 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 1)
122 *regnum
= 8 + WINED3DDP_MAXTEXCOORD
;
123 else if (usage
== WINED3DDECLUSAGE_TANGENT
&& usage_idx
== 0)
124 *regnum
= 9 + WINED3DDP_MAXTEXCOORD
;
125 else if (usage
== WINED3DDECLUSAGE_BINORMAL
&& usage_idx
== 0)
126 *regnum
= 10 + WINED3DDP_MAXTEXCOORD
;
127 else if (usage
== WINED3DDECLUSAGE_TESSFACTOR
&& usage_idx
== 0)
128 *regnum
= 11 + WINED3DDP_MAXTEXCOORD
;
129 else if (usage
== WINED3DDECLUSAGE_FOG
&& usage_idx
== 0)
130 *regnum
= 12 + WINED3DDP_MAXTEXCOORD
;
131 else if (usage
== WINED3DDECLUSAGE_DEPTH
&& usage_idx
== 0)
132 *regnum
= 13 + WINED3DDP_MAXTEXCOORD
;
133 else if (usage
== WINED3DDECLUSAGE_SAMPLE
&& usage_idx
== 0)
134 *regnum
= 14 + WINED3DDP_MAXTEXCOORD
;
137 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n",
138 debug_d3ddeclusage(usage
), usage_idx
);
144 void primitiveDeclarationConvertToStridedData(
145 IWineD3DDevice
*iface
,
146 BOOL useVertexShaderFunction
,
147 WineDirect3DVertexStridedData
*strided
,
150 /* We need to deal with frequency data!*/
153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
154 IWineD3DVertexDeclarationImpl
* vertexDeclaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
156 WINED3DVERTEXELEMENT
*element
;
159 char isPreLoaded
[MAX_STREAMS
];
160 DWORD preLoadStreams
[MAX_STREAMS
], numPreloadStreams
= 0;
162 memset(isPreLoaded
, 0, sizeof(isPreLoaded
));
164 /* Check for transformed vertices, disable vertex shader if present */
165 strided
->u
.s
.position_transformed
= FALSE
;
166 for (i
= 0; i
< vertexDeclaration
->declarationWNumElements
- 1; ++i
) {
167 element
= vertexDeclaration
->pDeclarationWine
+ i
;
169 if (element
->Usage
== WINED3DDECLUSAGE_POSITIONT
) {
170 strided
->u
.s
.position_transformed
= TRUE
;
171 useVertexShaderFunction
= FALSE
;
175 /* Translate the declaration into strided data */
176 for (i
= 0 ; i
< vertexDeclaration
->declarationWNumElements
- 1; ++i
) {
181 element
= vertexDeclaration
->pDeclarationWine
+ i
;
182 TRACE("%p Element %p (%d of %d)\n", vertexDeclaration
->pDeclarationWine
,
183 element
, i
+ 1, vertexDeclaration
->declarationWNumElements
- 1);
185 if (This
->stateBlock
->streamSource
[element
->Stream
] == NULL
)
188 if (This
->stateBlock
->streamIsUP
) {
189 TRACE("Stream is up %d, %p\n", element
->Stream
, This
->stateBlock
->streamSource
[element
->Stream
]);
191 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->Stream
];
193 TRACE("Stream isn't up %d, %p\n", element
->Stream
, This
->stateBlock
->streamSource
[element
->Stream
]);
194 if(!isPreLoaded
[element
->Stream
]) {
195 preLoadStreams
[numPreloadStreams
] = element
->Stream
;
197 isPreLoaded
[element
->Stream
] = 1;
199 data
= IWineD3DVertexBufferImpl_GetMemory(This
->stateBlock
->streamSource
[element
->Stream
], 0, &streamVBO
);
201 if( streamVBO
!= 0) *fixup
= TRUE
;
202 else if(*fixup
&& !useVertexShaderFunction
) {
203 /* This may be bad with the fixed function pipeline */
204 FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
208 stride
= This
->stateBlock
->streamStride
[element
->Stream
];
209 data
+= element
->Offset
;
212 TRACE("Offset %d Stream %d UsageIndex %d\n", element
->Offset
, element
->Stream
, element
->UsageIndex
);
214 if (useVertexShaderFunction
)
215 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
216 element
->Usage
, element
->UsageIndex
, &idx
);
218 stride_used
= fixed_get_input(element
->Usage
, element
->UsageIndex
, &idx
);
221 TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, "
222 "stream=%u, offset=%u, stride=%u, VBO=%u]\n",
223 useVertexShaderFunction
? "shader": "fixed function", idx
,
224 debug_d3ddeclusage(element
->Usage
), element
->UsageIndex
,
225 element
->Stream
, element
->Offset
, stride
, streamVBO
);
227 strided
->u
.input
[idx
].lpData
= data
;
228 strided
->u
.input
[idx
].dwType
= element
->Type
;
229 strided
->u
.input
[idx
].dwStride
= stride
;
230 strided
->u
.input
[idx
].VBO
= streamVBO
;
231 strided
->u
.input
[idx
].streamNo
= element
->Stream
;
234 /* Now call PreLoad on all the vertex buffers. In the very rare case
235 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
236 * The vertex buffer can now use the strided structure in the device instead of finding its
239 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
242 for(i
=0; i
< numPreloadStreams
; i
++) {
243 IWineD3DVertexBuffer_PreLoad(This
->stateBlock
->streamSource
[preLoadStreams
[i
]]);
247 void primitiveConvertFVFtoOffset(DWORD thisFVF
, DWORD stride
, BYTE
*data
, WineDirect3DVertexStridedData
*strided
, GLint streamVBO
, UINT streamNo
) {
251 int coordIdxInfo
= 0x00; /* Information on number of coords supplied */
252 int numCoords
[8]; /* Holding place for WINED3DFVF_TEXTUREFORMATx */
254 /* Either 3 or 4 floats depending on the FVF */
255 /* FIXME: Can blending data be in a different stream to the position data?
256 and if so using the fixed pipeline how do we handle it */
257 if (thisFVF
& WINED3DFVF_POSITION_MASK
) {
258 strided
->u
.s
.position
.lpData
= data
;
259 strided
->u
.s
.position
.dwType
= WINED3DDECLTYPE_FLOAT3
;
260 strided
->u
.s
.position
.dwStride
= stride
;
261 strided
->u
.s
.position
.VBO
= streamVBO
;
262 strided
->u
.s
.position
.streamNo
= streamNo
;
263 data
+= 3 * sizeof(float);
264 if (thisFVF
& WINED3DFVF_XYZRHW
) {
265 strided
->u
.s
.position
.dwType
= WINED3DDECLTYPE_FLOAT4
;
266 strided
->u
.s
.position_transformed
= TRUE
;
267 data
+= sizeof(float);
269 strided
->u
.s
.position_transformed
= FALSE
;
272 /* Blending is numBlends * FLOATs followed by a DWORD for UBYTE4 */
273 /** do we have to Check This->stateBlock->renderState[D3DRS_INDEXEDVERTEXBLENDENABLE] ? */
274 numBlends
= 1 + (((thisFVF
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
275 if(thisFVF
& WINED3DFVF_LASTBETA_UBYTE4
) numBlends
--;
277 if ((thisFVF
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
) {
278 TRACE("Setting blend Weights to %p\n", data
);
279 strided
->u
.s
.blendWeights
.lpData
= data
;
280 strided
->u
.s
.blendWeights
.dwType
= WINED3DDECLTYPE_FLOAT1
+ numBlends
- 1;
281 strided
->u
.s
.blendWeights
.dwStride
= stride
;
282 strided
->u
.s
.blendWeights
.VBO
= streamVBO
;
283 strided
->u
.s
.blendWeights
.streamNo
= streamNo
;
284 data
+= numBlends
* sizeof(FLOAT
);
286 if (thisFVF
& WINED3DFVF_LASTBETA_UBYTE4
) {
287 strided
->u
.s
.blendMatrixIndices
.lpData
= data
;
288 strided
->u
.s
.blendMatrixIndices
.dwType
= WINED3DDECLTYPE_UBYTE4
;
289 strided
->u
.s
.blendMatrixIndices
.dwStride
= stride
;
290 strided
->u
.s
.blendMatrixIndices
.VBO
= streamVBO
;
291 strided
->u
.s
.blendMatrixIndices
.streamNo
= streamNo
;
292 data
+= sizeof(DWORD
);
296 /* Normal is always 3 floats */
297 if (thisFVF
& WINED3DFVF_NORMAL
) {
298 strided
->u
.s
.normal
.lpData
= data
;
299 strided
->u
.s
.normal
.dwType
= WINED3DDECLTYPE_FLOAT3
;
300 strided
->u
.s
.normal
.dwStride
= stride
;
301 strided
->u
.s
.normal
.VBO
= streamVBO
;
302 strided
->u
.s
.normal
.streamNo
= streamNo
;
303 data
+= 3 * sizeof(FLOAT
);
306 /* Pointsize is a single float */
307 if (thisFVF
& WINED3DFVF_PSIZE
) {
308 strided
->u
.s
.pSize
.lpData
= data
;
309 strided
->u
.s
.pSize
.dwType
= WINED3DDECLTYPE_FLOAT1
;
310 strided
->u
.s
.pSize
.dwStride
= stride
;
311 strided
->u
.s
.pSize
.VBO
= streamVBO
;
312 strided
->u
.s
.pSize
.streamNo
= streamNo
;
313 data
+= sizeof(FLOAT
);
316 /* Diffuse is 4 unsigned bytes */
317 if (thisFVF
& WINED3DFVF_DIFFUSE
) {
318 strided
->u
.s
.diffuse
.lpData
= data
;
319 strided
->u
.s
.diffuse
.dwType
= WINED3DDECLTYPE_SHORT4
;
320 strided
->u
.s
.diffuse
.dwStride
= stride
;
321 strided
->u
.s
.diffuse
.VBO
= streamVBO
;
322 strided
->u
.s
.diffuse
.streamNo
= streamNo
;
323 data
+= sizeof(DWORD
);
326 /* Specular is 4 unsigned bytes */
327 if (thisFVF
& WINED3DFVF_SPECULAR
) {
328 strided
->u
.s
.specular
.lpData
= data
;
329 strided
->u
.s
.specular
.dwType
= WINED3DDECLTYPE_SHORT4
;
330 strided
->u
.s
.specular
.dwStride
= stride
;
331 strided
->u
.s
.specular
.VBO
= streamVBO
;
332 strided
->u
.s
.specular
.streamNo
= streamNo
;
333 data
+= sizeof(DWORD
);
337 numTextures
= (thisFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
338 coordIdxInfo
= (thisFVF
& 0x00FF0000) >> 16; /* 16 is from definition of WINED3DFVF_TEXCOORDSIZE1, and is 8 (0-7 stages) * 2bits long */
340 /* numTextures indicates the number of texture coordinates supplied */
341 /* However, the first set may not be for stage 0 texture - it all */
342 /* depends on WINED3DTSS_TEXCOORDINDEX. */
343 /* The number of bytes for each coordinate set is based off */
344 /* WINED3DFVF_TEXCOORDSIZEn, which are the bottom 2 bits */
346 /* So, for each supplied texture extract the coords */
347 for (textureNo
= 0; textureNo
< numTextures
; ++textureNo
) {
349 strided
->u
.s
.texCoords
[textureNo
].lpData
= data
;
350 strided
->u
.s
.texCoords
[textureNo
].dwType
= WINED3DDECLTYPE_FLOAT1
;
351 strided
->u
.s
.texCoords
[textureNo
].dwStride
= stride
;
352 strided
->u
.s
.texCoords
[textureNo
].VBO
= streamVBO
;
353 strided
->u
.s
.texCoords
[textureNo
].streamNo
= streamNo
;
354 numCoords
[textureNo
] = coordIdxInfo
& 0x03;
357 data
+= sizeof(float);
358 if (numCoords
[textureNo
] != WINED3DFVF_TEXTUREFORMAT1
) {
359 strided
->u
.s
.texCoords
[textureNo
].dwType
= WINED3DDECLTYPE_FLOAT2
;
360 data
+= sizeof(float);
361 if (numCoords
[textureNo
] != WINED3DFVF_TEXTUREFORMAT2
) {
362 strided
->u
.s
.texCoords
[textureNo
].dwType
= WINED3DDECLTYPE_FLOAT3
;
363 data
+= sizeof(float);
364 if (numCoords
[textureNo
] != WINED3DFVF_TEXTUREFORMAT3
) {
365 strided
->u
.s
.texCoords
[textureNo
].dwType
= WINED3DDECLTYPE_FLOAT4
;
366 data
+= sizeof(float);
370 coordIdxInfo
= coordIdxInfo
>> 2; /* Drop bottom two bits */
374 void primitiveConvertToStridedData(IWineD3DDevice
*iface
, WineDirect3DVertexStridedData
*strided
, BOOL
*fixup
) {
375 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
377 DWORD stride
= This
->stateBlock
->streamStride
[0];
381 /* Retrieve appropriate FVF */
382 thisFVF
= This
->stateBlock
->fvf
;
383 /* Handle memory passed directly as well as vertex buffers */
384 if (This
->stateBlock
->streamIsUP
) {
386 data
= (BYTE
*)This
->stateBlock
->streamSource
[0];
388 /* The for loop should iterate through here only once per stream, so we don't need magic to prevent double loading
391 data
= IWineD3DVertexBufferImpl_GetMemory(This
->stateBlock
->streamSource
[0], 0, &streamVBO
);
393 if(streamVBO
!= 0 ) *fixup
= TRUE
;
396 VTRACE(("FVF for stream 0 is %lx\n", thisFVF
));
398 /* Now convert the stream into pointers */
399 primitiveConvertFVFtoOffset(thisFVF
, stride
, data
, strided
, streamVBO
, 0);
401 /* Now call PreLoad on the vertex buffer. In the very rare case
402 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
403 * The vertex buffer can now use the strided structure in the device instead of finding its
406 if(!This
->stateBlock
->streamIsUP
) {
407 IWineD3DVertexBuffer_PreLoad(This
->stateBlock
->streamSource
[0]);
411 static void drawStridedFast(IWineD3DDevice
*iface
,UINT numberOfVertices
, GLenum glPrimitiveType
,
412 const void *idxData
, short idxSize
, ULONG minIndex
, ULONG startIdx
, ULONG startVertex
) {
413 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
415 if(attribhack
&& This
->stateBlock
->vertexShader
) {
416 if(((IWineD3DVertexShaderImpl
*) This
->stateBlock
->vertexShader
)->semantics_in
[15].usage
!= 0 &&
417 ((IWineD3DVertexShaderImpl
*) This
->stateBlock
->vertexShader
)->semantics_in
[15].reg
!= 0) {
418 /* Background of this hack is that the MacOS opengl implementation crashes(or terminates the app silently) if a vertex
419 * shader using all 16 vertex attributes is used. With this hack the application can conntinue, but some geometry may
420 * be missing. This allows us to run 3DMark2001 with vertex shaders enabled. The dragon in the dragothic test uses 16
423 FIXME("A vertex shader using 16 vertex attributes is used, and the attribute hack is enabled. Not drawing anything\n");
428 if (idxSize
!= 0 /* This crashes sometimes!*/) {
429 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This
, glPrimitiveType
, numberOfVertices
, minIndex
);
430 idxData
= idxData
== (void *)-1 ? NULL
: idxData
;
432 glDrawElements(glPrimitiveType
, numberOfVertices
, idxSize
== 2 ? GL_UNSIGNED_SHORT
: GL_UNSIGNED_INT
,
433 (const char *)idxData
+(idxSize
* startIdx
));
434 #else /* using drawRangeElements may be faster */
436 glDrawRangeElements(glPrimitiveType
, minIndex
, minIndex
+ numberOfVertices
- 1, numberOfVertices
,
437 idxSize
== 2 ? GL_UNSIGNED_SHORT
: GL_UNSIGNED_INT
,
438 (const char *)idxData
+(idxSize
* startIdx
));
440 checkGLcall("glDrawRangeElements");
444 /* Note first is now zero as we shuffled along earlier */
445 TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This
, glPrimitiveType
, numberOfVertices
);
446 glDrawArrays(glPrimitiveType
, startVertex
, numberOfVertices
);
447 checkGLcall("glDrawArrays");
455 * Actually draw using the supplied information.
456 * Slower GL version which extracts info about each vertex in turn
459 static void drawStridedSlow(IWineD3DDevice
*iface
, WineDirect3DVertexStridedData
*sd
,
460 UINT NumVertexes
, GLenum glPrimType
,
461 const void *idxData
, short idxSize
, ULONG minIndex
, ULONG startIdx
, ULONG startVertex
) {
463 unsigned int textureNo
= 0;
464 unsigned int texture_idx
= 0;
465 const WORD
*pIdxBufS
= NULL
;
466 const DWORD
*pIdxBufL
= NULL
;
468 float x
= 0.0f
, y
= 0.0f
, z
= 0.0f
; /* x,y,z coordinates */
469 float rhw
= 0.0f
; /* rhw */
470 DWORD diffuseColor
= 0xFFFFFFFF; /* Diffuse Color */
471 DWORD specularColor
= 0; /* Specular Color */
472 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
473 UINT
*streamOffset
= This
->stateBlock
->streamOffset
;
474 DWORD SkipnStrides
= startVertex
+ This
->stateBlock
->loadBaseVertexIndex
;
476 BYTE
*texCoords
[WINED3DDP_MAXTEXCOORD
];
477 BYTE
*diffuse
= NULL
, *specular
= NULL
, *normal
= NULL
, *position
= NULL
;
479 TRACE("Using slow vertex array code\n");
481 /* Variable Initialization */
483 /* Immediate mode drawing can't make use of indices in a vbo - get the data from the index buffer.
484 * If the index buffer has no vbo(not supported or other reason), or with user pointer drawing
485 * idxData will be != NULL
487 if(idxData
== NULL
) {
488 idxData
= ((IWineD3DIndexBufferImpl
*) This
->stateBlock
->pIndexData
)->resource
.allocatedMemory
;
491 if (idxSize
== 2) pIdxBufS
= (const WORD
*) idxData
;
492 else pIdxBufL
= (const DWORD
*) idxData
;
495 /* Adding the stream offset once is cheaper than doing it every iteration. Do not modify the strided data, it is a pointer
496 * to the strided Data in the device and might be needed intact on the next draw
498 for (textureNo
= 0, texture_idx
= 0; textureNo
< GL_LIMITS(texture_stages
); ++textureNo
) {
499 if(sd
->u
.s
.texCoords
[textureNo
].lpData
) {
500 texCoords
[textureNo
] = sd
->u
.s
.texCoords
[textureNo
].lpData
+ streamOffset
[sd
->u
.s
.texCoords
[textureNo
].streamNo
];
502 texCoords
[textureNo
] = NULL
;
505 if(sd
->u
.s
.diffuse
.lpData
) {
506 diffuse
= sd
->u
.s
.diffuse
.lpData
+ streamOffset
[sd
->u
.s
.diffuse
.streamNo
];
508 if(sd
->u
.s
.specular
.lpData
) {
509 specular
= sd
->u
.s
.specular
.lpData
+ streamOffset
[sd
->u
.s
.specular
.streamNo
];
511 if(sd
->u
.s
.normal
.lpData
) {
512 normal
= sd
->u
.s
.normal
.lpData
+ streamOffset
[sd
->u
.s
.normal
.streamNo
];
514 if(sd
->u
.s
.position
.lpData
) {
515 position
= sd
->u
.s
.position
.lpData
+ streamOffset
[sd
->u
.s
.position
.streamNo
];
518 /* Start drawing in GL */
519 VTRACE(("glBegin(%x)\n", glPrimType
));
522 /* Default settings for data that is not passed */
523 if (sd
->u
.s
.normal
.lpData
== NULL
) {
526 if(sd
->u
.s
.diffuse
.lpData
!= NULL
) {
527 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
529 if(sd
->u
.s
.specular
.lpData
!= NULL
) {
530 if (GL_SUPPORT(EXT_SECONDARY_COLOR
)) {
531 GL_EXTCALL(glSecondaryColor3fEXT
)(0, 0, 0);
535 /* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
536 * Guess it's not necessary(we crash then anyway) and would only eat CPU time
539 /* For each primitive */
540 for (vx_index
= 0; vx_index
< NumVertexes
; ++vx_index
) {
542 /* Initialize diffuse color */
543 diffuseColor
= 0xFFFFFFFF;
545 /* Blending data and Point sizes are not supported by this function. They are not supported by the fixed
546 * function pipeline at all. A Fixme for them is printed after decoding the vertex declaration
549 /* For indexed data, we need to go a few more strides in */
550 if (idxData
!= NULL
) {
552 /* Indexed so work out the number of strides to skip */
554 VTRACE(("Idx for vertex %d = %d\n", vx_index
, pIdxBufS
[startIdx
+vx_index
]));
555 SkipnStrides
= pIdxBufS
[startIdx
+ vx_index
] + This
->stateBlock
->loadBaseVertexIndex
;
557 VTRACE(("Idx for vertex %d = %d\n", vx_index
, pIdxBufL
[startIdx
+vx_index
]));
558 SkipnStrides
= pIdxBufL
[startIdx
+ vx_index
] + This
->stateBlock
->loadBaseVertexIndex
;
562 /* Texture coords --------------------------- */
563 for (textureNo
= 0, texture_idx
= 0; textureNo
< GL_LIMITS(texture_stages
); ++textureNo
) {
565 if (!GL_SUPPORT(ARB_MULTITEXTURE
) && textureNo
> 0) {
566 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
570 /* Query tex coords */
571 if (This
->stateBlock
->textures
[textureNo
] != NULL
) {
573 int coordIdx
= This
->stateBlock
->textureState
[textureNo
][WINED3DTSS_TEXCOORDINDEX
];
574 float *ptrToCoords
= NULL
;
575 float s
= 0.0, t
= 0.0, r
= 0.0, q
= 0.0;
578 VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo
));
581 } else if (coordIdx
< 0) {
582 FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo
, coordIdx
);
587 ptrToCoords
= (float *)(texCoords
[coordIdx
] + (SkipnStrides
* sd
->u
.s
.texCoords
[coordIdx
].dwStride
));
588 if (texCoords
[coordIdx
] == NULL
) {
589 TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo
);
594 int coordsToUse
= sd
->u
.s
.texCoords
[coordIdx
].dwType
+ 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
596 /* The coords to supply depend completely on the fvf / vertex shader */
597 switch (coordsToUse
) {
598 case 4: q
= ptrToCoords
[3]; /* drop through */
599 case 3: r
= ptrToCoords
[2]; /* drop through */
600 case 2: t
= ptrToCoords
[1]; /* drop through */
601 case 1: s
= ptrToCoords
[0];
604 /* Projected is more 'fun' - Move the last coord to the 'q'
605 parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */
606 if ((This
->stateBlock
->textureState
[textureNo
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] != WINED3DTTFF_DISABLE
) &&
607 (This
->stateBlock
->textureState
[textureNo
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] & WINED3DTTFF_PROJECTED
)) {
609 if (This
->stateBlock
->textureState
[textureNo
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] & WINED3DTTFF_PROJECTED
) {
610 switch (coordsToUse
) {
611 case 0: /* Drop Through */
613 FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n");
625 case 4: /* Nop here */
628 FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n",
629 This
->stateBlock
->textureState
[textureNo
][WINED3DTSS_TEXTURETRANSFORMFLAGS
] & WINED3DTTFF_PROJECTED
);
634 switch (coordsToUse
) { /* Supply the provided texture coords */
635 case WINED3DTTFF_COUNT1
:
636 VTRACE(("tex:%d, s=%f\n", textureNo
, s
));
637 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
638 GL_EXTCALL(glMultiTexCoord1fARB(texture_idx
, s
));
643 case WINED3DTTFF_COUNT2
:
644 VTRACE(("tex:%d, s=%f, t=%f\n", textureNo
, s
, t
));
645 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
646 GL_EXTCALL(glMultiTexCoord2fARB(texture_idx
, s
, t
));
651 case WINED3DTTFF_COUNT3
:
652 VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo
, s
, t
, r
));
653 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
654 GL_EXTCALL(glMultiTexCoord3fARB(texture_idx
, s
, t
, r
));
656 glTexCoord3f(s
, t
, r
);
659 case WINED3DTTFF_COUNT4
:
660 VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo
, s
, t
, r
, q
));
661 if (GL_SUPPORT(ARB_MULTITEXTURE
)) {
662 GL_EXTCALL(glMultiTexCoord4fARB(texture_idx
, s
, t
, r
, q
));
664 glTexCoord4f(s
, t
, r
, q
);
668 FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse
);
672 if (/*!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->textures[textureNo]*/TRUE
) ++texture_idx
;
673 } /* End of textures */
675 /* Diffuse -------------------------------- */
677 DWORD
*ptrToCoords
= (DWORD
*)(diffuse
+ (SkipnStrides
* sd
->u
.s
.diffuse
.dwStride
));
678 diffuseColor
= ptrToCoords
[0];
679 VTRACE(("diffuseColor=%lx\n", diffuseColor
));
681 glColor4ub(D3DCOLOR_B_R(diffuseColor
),
682 D3DCOLOR_B_G(diffuseColor
),
683 D3DCOLOR_B_B(diffuseColor
),
684 D3DCOLOR_B_A(diffuseColor
));
685 VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n",
686 D3DCOLOR_B_R(diffuseColor
),
687 D3DCOLOR_B_G(diffuseColor
),
688 D3DCOLOR_B_B(diffuseColor
),
689 D3DCOLOR_B_A(diffuseColor
)));
692 /* Specular ------------------------------- */
694 DWORD
*ptrToCoords
= (DWORD
*)(specular
+ (SkipnStrides
* sd
->u
.s
.specular
.dwStride
));
695 specularColor
= ptrToCoords
[0];
696 VTRACE(("specularColor=%lx\n", specularColor
));
698 /* special case where the fog density is stored in the specular alpha channel */
699 if(This
->stateBlock
->renderState
[WINED3DRS_FOGENABLE
] &&
700 (This
->stateBlock
->renderState
[WINED3DRS_FOGVERTEXMODE
] == WINED3DFOG_NONE
|| sd
->u
.s
.position
.dwType
== WINED3DDECLTYPE_FLOAT4
)&&
701 This
->stateBlock
->renderState
[WINED3DRS_FOGTABLEMODE
] == WINED3DFOG_NONE
) {
702 if(GL_SUPPORT(EXT_FOG_COORD
)) {
703 GL_EXTCALL(glFogCoordfEXT(specularColor
>> 24));
705 static BOOL warned
= FALSE
;
707 /* TODO: Use the fog table code from old ddraw */
708 FIXME("Implement fog for transformed vertices in software\n");
714 VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n",
715 D3DCOLOR_B_R(specularColor
),
716 D3DCOLOR_B_G(specularColor
),
717 D3DCOLOR_B_B(specularColor
)));
718 if (GL_SUPPORT(EXT_SECONDARY_COLOR
)) {
719 GL_EXTCALL(glSecondaryColor3ubEXT
)(
720 D3DCOLOR_B_R(specularColor
),
721 D3DCOLOR_B_G(specularColor
),
722 D3DCOLOR_B_B(specularColor
));
724 /* Do not worry if specular colour missing and disable request */
725 VTRACE(("Specular color extensions not supplied\n"));
729 /* Normal -------------------------------- */
730 if (normal
!= NULL
) {
731 float *ptrToCoords
= (float *)(normal
+ (SkipnStrides
* sd
->u
.s
.normal
.dwStride
));
733 VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", ptrToCoords
[0], ptrToCoords
[1], ptrToCoords
[2]));
734 glNormal3f(ptrToCoords
[0], ptrToCoords
[1], ptrToCoords
[2]);
737 /* Position -------------------------------- */
739 float *ptrToCoords
= (float *)(position
+ (SkipnStrides
* sd
->u
.s
.position
.dwStride
));
744 VTRACE(("x,y,z=%f,%f,%f\n", x
,y
,z
));
746 /* RHW follows, only if transformed, ie 4 floats were provided */
747 if (sd
->u
.s
.position_transformed
) {
748 rhw
= ptrToCoords
[3];
749 VTRACE(("rhw=%f\n", rhw
));
752 if (1.0f
== rhw
|| ((rhw
< eps
) && (rhw
> -eps
))) {
753 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x
,y
,z
));
756 GLfloat w
= 1.0 / rhw
;
757 VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x
,y
,z
,rhw
));
758 glVertex4f(x
*w
, y
*w
, z
*w
, w
);
762 /* For non indexed mode, step onto next parts */
763 if (idxData
== NULL
) {
769 checkGLcall("glEnd and previous calls");
772 static void check_fbo_status(IWineD3DDevice
*iface
) {
773 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
775 GLenum status
= GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT
));
777 case GL_FRAMEBUFFER_COMPLETE_EXT
: TRACE("FBO complete.\n"); break;
778 default: TRACE("FBO status %#x.\n", status
); break;
782 static void depth_blt(IWineD3DDevice
*iface
, GLuint texture
) {
783 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
784 GLint old_binding
= 0;
786 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
);
788 glDisable(GL_CULL_FACE
);
790 glDisable(GL_ALPHA_TEST
);
791 glDisable(GL_STENCIL_TEST
);
792 glEnable(GL_DEPTH_TEST
);
793 glDepthFunc(GL_ALWAYS
);
795 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
796 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
797 glBindTexture(GL_TEXTURE_2D
, texture
);
798 glEnable(GL_TEXTURE_2D
);
800 This
->shader_backend
->shader_select_depth_blt(iface
);
802 glBegin(GL_TRIANGLE_STRIP
);
803 glVertex2f(-1.0f
, -1.0f
);
804 glVertex2f(1.0f
, -1.0f
);
805 glVertex2f(-1.0f
, 1.0f
);
806 glVertex2f(1.0f
, 1.0f
);
809 glBindTexture(GL_TEXTURE_2D
, old_binding
);
813 /* Reselect the old shaders. There doesn't seem to be any glPushAttrib bit for arb shaders,
814 * and this seems easier and more efficient than providing the shader backend with a private
815 * storage to read and restore the old shader settings
817 This
->shader_backend
->shader_select(iface
, use_ps(This
), use_vs(This
));
820 static void depth_copy(IWineD3DDevice
*iface
) {
821 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
822 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*)This
->depthStencilBuffer
;
824 /* Only copy the depth buffer if there is one. */
825 if (!depth_stencil
) return;
827 /* TODO: Make this work for modes other than FBO */
828 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
830 if (This
->render_offscreen
) {
831 static GLuint tmp_texture
= 0;
832 GLint old_binding
= 0;
834 TRACE("Copying onscreen depth buffer to offscreen surface\n");
837 glGenTextures(1, &tmp_texture
);
840 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
841 * directly on the FBO texture. That's because we need to flip. */
842 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
843 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
844 glBindTexture(GL_TEXTURE_2D
, tmp_texture
);
845 glCopyTexImage2D(depth_stencil
->glDescription
.target
,
846 depth_stencil
->glDescription
.level
,
847 depth_stencil
->glDescription
.glFormatInternal
,
850 depth_stencil
->currentDesc
.Width
,
851 depth_stencil
->currentDesc
.Height
,
853 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
854 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
855 glTexParameteri(GL_TEXTURE_2D
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
856 glBindTexture(GL_TEXTURE_2D
, old_binding
);
858 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, This
->fbo
));
859 checkGLcall("glBindFramebuffer()");
860 depth_blt(iface
, tmp_texture
);
861 checkGLcall("depth_blt");
863 TRACE("Copying offscreen surface to onscreen depth buffer\n");
865 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
866 checkGLcall("glBindFramebuffer()");
867 depth_blt(iface
, depth_stencil
->glDescription
.textureName
);
868 checkGLcall("depth_blt");
872 static inline void drawStridedInstanced(IWineD3DDevice
*iface
, WineDirect3DVertexStridedData
*sd
, UINT numberOfVertices
,
873 GLenum glPrimitiveType
, const void *idxData
, short idxSize
, ULONG minIndex
,
874 ULONG startIdx
, ULONG startVertex
) {
875 UINT numInstances
= 0;
876 int numInstancedAttribs
= 0, i
, j
;
877 UINT instancedData
[sizeof(sd
->u
.input
) / sizeof(sd
->u
.input
[0]) /* 16 */];
878 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
879 IWineD3DStateBlockImpl
*stateblock
= This
->stateBlock
;
882 /* This is a nasty thing. MSDN says no hardware supports that and apps have to use software vertex processing.
883 * We don't support this for now
885 * Shouldn't be too hard to support with opengl, in theory just call glDrawArrays instead of drawElements.
886 * But the StreamSourceFreq value has a different meaning in that situation.
888 FIXME("Non-indexed instanced drawing is not supported\n");
892 TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This
, glPrimitiveType
, numberOfVertices
, minIndex
);
893 idxData
= idxData
== (void *)-1 ? NULL
: idxData
;
895 /* First, figure out how many instances we have to draw */
896 for(i
= 0; i
< MAX_STREAMS
; i
++) {
897 /* Look at all non-instanced streams */
898 if(!(stateblock
->streamFlags
[i
] & WINED3DSTREAMSOURCE_INSTANCEDATA
) &&
899 stateblock
->streamSource
[i
]) {
900 int inst
= stateblock
->streamFreq
[i
];
902 if(numInstances
&& inst
!= numInstances
) {
903 ERR("Two streams specify a different number of instances. Got %d, new is %d\n", numInstances
, inst
);
909 for(i
= 0; i
< sizeof(sd
->u
.input
) / sizeof(sd
->u
.input
[0]); i
++) {
910 if(stateblock
->streamFlags
[sd
->u
.input
[i
].streamNo
] & WINED3DSTREAMSOURCE_INSTANCEDATA
) {
911 instancedData
[numInstancedAttribs
] = i
;
912 numInstancedAttribs
++;
916 /* now draw numInstances instances :-) */
917 for(i
= 0; i
< numInstances
; i
++) {
918 /* Specify the instanced attributes using immediate mode calls */
919 for(j
= 0; j
< numInstancedAttribs
; j
++) {
920 BYTE
*ptr
= sd
->u
.input
[instancedData
[j
]].lpData
+
921 sd
->u
.input
[instancedData
[j
]].dwStride
* i
+
922 stateblock
->streamOffset
[sd
->u
.input
[instancedData
[j
]].streamNo
];
923 if(sd
->u
.input
[instancedData
[j
]].VBO
) {
924 IWineD3DVertexBufferImpl
*vb
= (IWineD3DVertexBufferImpl
*) stateblock
->streamSource
[sd
->u
.input
[instancedData
[j
]].streamNo
];
925 ptr
+= (long) vb
->resource
.allocatedMemory
;
928 switch(sd
->u
.input
[instancedData
[j
]].dwType
) {
929 case WINED3DDECLTYPE_FLOAT1
:
930 GL_EXTCALL(glVertexAttrib1fvARB(instancedData
[j
], (float *) ptr
));
932 case WINED3DDECLTYPE_FLOAT2
:
933 GL_EXTCALL(glVertexAttrib2fvARB(instancedData
[j
], (float *) ptr
));
935 case WINED3DDECLTYPE_FLOAT3
:
936 GL_EXTCALL(glVertexAttrib3fvARB(instancedData
[j
], (float *) ptr
));
938 case WINED3DDECLTYPE_FLOAT4
:
939 GL_EXTCALL(glVertexAttrib4fvARB(instancedData
[j
], (float *) ptr
));
942 case WINED3DDECLTYPE_UBYTE4
:
943 GL_EXTCALL(glVertexAttrib4NubvARB(instancedData
[j
], ptr
));
945 case WINED3DDECLTYPE_UBYTE4N
:
946 case WINED3DDECLTYPE_D3DCOLOR
:
947 GL_EXTCALL(glVertexAttrib4NubvARB(instancedData
[j
], ptr
));
950 case WINED3DDECLTYPE_SHORT2
:
951 GL_EXTCALL(glVertexAttrib4svARB(instancedData
[j
], (GLshort
*) ptr
));
953 case WINED3DDECLTYPE_SHORT4
:
954 GL_EXTCALL(glVertexAttrib4svARB(instancedData
[j
], (GLshort
*) ptr
));
957 case WINED3DDECLTYPE_SHORT2N
:
959 GLshort s
[4] = {((short *) ptr
)[0], ((short *) ptr
)[1], 0, 1};
960 GL_EXTCALL(glVertexAttrib4NsvARB(instancedData
[j
], s
));
963 case WINED3DDECLTYPE_USHORT2N
:
965 GLushort s
[4] = {((unsigned short *) ptr
)[0], ((unsigned short *) ptr
)[1], 0, 1};
966 GL_EXTCALL(glVertexAttrib4NusvARB(instancedData
[j
], s
));
969 case WINED3DDECLTYPE_SHORT4N
:
970 GL_EXTCALL(glVertexAttrib4NsvARB(instancedData
[j
], (GLshort
*) ptr
));
972 case WINED3DDECLTYPE_USHORT4N
:
973 GL_EXTCALL(glVertexAttrib4NusvARB(instancedData
[j
], (GLushort
*) ptr
));
976 case WINED3DDECLTYPE_UDEC3
:
977 FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n");
978 /*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */
980 case WINED3DDECLTYPE_DEC3N
:
981 FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n");
982 /*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */
985 case WINED3DDECLTYPE_FLOAT16_2
:
986 /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4
987 * byte float according to the IEEE standard
989 FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_2\n");
991 case WINED3DDECLTYPE_FLOAT16_4
:
992 FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_4\n");
995 case WINED3DDECLTYPE_UNUSED
:
997 ERR("Unexpected declaration in instanced attributes\n");
1002 glDrawElements(glPrimitiveType
, numberOfVertices
, idxSize
== 2 ? GL_UNSIGNED_SHORT
: GL_UNSIGNED_INT
,
1003 (const char *)idxData
+(idxSize
* startIdx
));
1004 checkGLcall("glDrawElements");
1012 void blt_to_drawable(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*surface
) {
1013 struct coords coords
[4];
1016 /* TODO: This could be supported for lazy unlocking */
1017 if(!(surface
->Flags
& SFLAG_INTEXTURE
)) {
1018 /* It is ok at init to be nowhere */
1019 if(!(surface
->Flags
& SFLAG_INSYSMEM
)) {
1020 ERR("Blitting surfaces from sysmem not supported yet\n");
1026 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_BLIT
);
1028 if(surface
->glDescription
.target
== GL_TEXTURE_2D
) {
1029 glBindTexture(GL_TEXTURE_2D
, surface
->glDescription
.textureName
);
1030 checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)");
1032 coords
[0].x
= 0; coords
[0].y
= 0; coords
[0].z
= 0;
1033 coords
[1].x
= 0; coords
[1].y
= 1; coords
[1].z
= 0;
1034 coords
[2].x
= 1; coords
[2].y
= 1; coords
[2].z
= 0;
1035 coords
[3].x
= 1; coords
[3].y
= 0; coords
[3].z
= 0;
1039 /* Must be a cube map */
1040 glDisable(GL_TEXTURE_2D
);
1041 checkGLcall("glDisable(GL_TEXTURE_2D)");
1042 glEnable(GL_TEXTURE_CUBE_MAP_ARB
);
1043 checkGLcall("glEnable(surface->glDescription.target)");
1044 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB
, surface
->glDescription
.textureName
);
1045 checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)");
1047 switch(surface
->glDescription
.target
) {
1048 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
1049 coords
[0].x
= 1; coords
[0].y
= -1; coords
[0].z
= 1;
1050 coords
[1].x
= 1; coords
[1].y
= 1; coords
[1].z
= 1;
1051 coords
[2].x
= 1; coords
[2].y
= 1; coords
[2].z
= -1;
1052 coords
[3].x
= 1; coords
[3].y
= -1; coords
[3].z
= -1;
1055 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
1056 coords
[0].x
= -1; coords
[0].y
= -1; coords
[0].z
= 1;
1057 coords
[1].x
= -1; coords
[1].y
= 1; coords
[1].z
= 1;
1058 coords
[2].x
= -1; coords
[2].y
= 1; coords
[2].z
= -1;
1059 coords
[3].x
= -1; coords
[3].y
= -1; coords
[3].z
= -1;
1062 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
1063 coords
[0].x
= -1; coords
[0].y
= 1; coords
[0].z
= 1;
1064 coords
[1].x
= 1; coords
[1].y
= 1; coords
[1].z
= 1;
1065 coords
[2].x
= 1; coords
[2].y
= 1; coords
[2].z
= -1;
1066 coords
[3].x
= -1; coords
[3].y
= 1; coords
[3].z
= -1;
1069 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
1070 coords
[0].x
= -1; coords
[0].y
= -1; coords
[0].z
= 1;
1071 coords
[1].x
= 1; coords
[1].y
= -1; coords
[1].z
= 1;
1072 coords
[2].x
= 1; coords
[2].y
= -1; coords
[2].z
= -1;
1073 coords
[3].x
= -1; coords
[3].y
= -1; coords
[3].z
= -1;
1076 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
1077 coords
[0].x
= -1; coords
[0].y
= -1; coords
[0].z
= 1;
1078 coords
[1].x
= 1; coords
[1].y
= -1; coords
[1].z
= 1;
1079 coords
[2].x
= 1; coords
[2].y
= -1; coords
[2].z
= 1;
1080 coords
[3].x
= -1; coords
[3].y
= -1; coords
[3].z
= 1;
1083 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
1084 coords
[0].x
= -1; coords
[0].y
= -1; coords
[0].z
= -1;
1085 coords
[1].x
= 1; coords
[1].y
= -1; coords
[1].z
= -1;
1086 coords
[2].x
= 1; coords
[2].y
= -1; coords
[2].z
= -1;
1087 coords
[3].x
= -1; coords
[3].y
= -1; coords
[3].z
= -1;
1090 ERR("Unexpected texture target\n");
1098 if(This
->render_offscreen
) {
1099 coords
[0].y
= coords
[0].y
== 1 ? low_coord
: 1;
1100 coords
[1].y
= coords
[1].y
== 1 ? low_coord
: 1;
1101 coords
[2].y
= coords
[2].y
== 1 ? low_coord
: 1;
1102 coords
[3].y
= coords
[3].y
== 1 ? low_coord
: 1;
1106 glTexCoord3iv((GLint
*) &coords
[0]);
1109 glTexCoord3iv((GLint
*) &coords
[1]);
1110 glVertex2i(0, surface
->pow2Height
);
1112 glTexCoord3iv((GLint
*) &coords
[2]);
1113 glVertex2i(surface
->pow2Width
, surface
->pow2Height
);
1115 glTexCoord3iv((GLint
*) &coords
[3]);
1116 glVertex2i(surface
->pow2Width
, 0);
1118 checkGLcall("glEnd");
1120 if(surface
->glDescription
.target
!= GL_TEXTURE_2D
) {
1121 glEnable(GL_TEXTURE_2D
);
1122 checkGLcall("glEnable(GL_TEXTURE_2D)");
1123 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
1124 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
1129 /* Routine common to the draw primitive and draw indexed primitive routines */
1130 void drawPrimitive(IWineD3DDevice
*iface
,
1134 long StartVertexIndex
,
1135 UINT numberOfVertices
,
1138 const void *idxData
,
1141 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1142 IWineD3DSwapChain
*swapchain
;
1143 IWineD3DBaseTexture
*texture
= NULL
;
1144 IWineD3DSurfaceImpl
*target
;
1147 /* Signals other modules that a drawing is in progress and the stateblock finalized */
1148 This
->isInDraw
= TRUE
;
1150 /* Invalidate the back buffer memory so LockRect will read it the next time */
1151 for(i
= 0; i
< GL_LIMITS(buffers
); i
++) {
1152 target
= (IWineD3DSurfaceImpl
*) This
->render_targets
[i
];
1154 /* TODO: Only do all that if we're going to change anything
1155 * Texture container dirtification does not work quite right yet
1157 if(target
/*&& target->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)*/) {
1162 IWineD3DSurface_GetContainer((IWineD3DSurface
*) target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
1164 /* Need the surface in the drawable! */
1165 if(!(target
->Flags
& SFLAG_INDRAWABLE
) && (swapchain
|| wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)) {
1166 blt_to_drawable(This
, target
);
1170 /* Onscreen target. Invalidate system memory copy and texture copy */
1171 target
->Flags
&= ~(SFLAG_INSYSMEM
| SFLAG_INTEXTURE
);
1172 target
->Flags
|= SFLAG_INDRAWABLE
;
1173 IWineD3DSwapChain_Release(swapchain
);
1174 } else if(wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) {
1175 /* Non-FBO target: Invalidate system copy, texture copy and dirtify the container */
1176 IWineD3DSurface_GetContainer((IWineD3DSurface
*) target
, &IID_IWineD3DBaseTexture
, (void **)&texture
);
1179 IWineD3DBaseTexture_SetDirty(texture
, TRUE
);
1180 IWineD3DTexture_Release(texture
);
1183 target
->Flags
&= ~(SFLAG_INSYSMEM
| SFLAG_INTEXTURE
);
1184 target
->Flags
|= SFLAG_INDRAWABLE
;
1186 /* FBO offscreen target. Invalidate system memory copy */
1187 target
->Flags
&= ~SFLAG_INSYSMEM
;
1190 /* Must be an fbo render target */
1191 target
->Flags
&= ~SFLAG_INSYSMEM
;
1192 target
->Flags
|= SFLAG_INTEXTURE
;
1197 /* Ok, we will be updating the screen from here onwards so grab the lock */
1200 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_DRAWPRIM
);
1202 if (TRACE_ON(d3d_draw
) && wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
1203 check_fbo_status(iface
);
1206 if (This
->depth_copy_state
== WINED3D_DCS_COPY
) {
1209 This
->depth_copy_state
= WINED3D_DCS_INITIAL
;
1213 /* Ok, Work out which primitive is requested and how many vertexes that
1215 UINT calculatedNumberOfindices
= primitiveToGl(PrimitiveType
, NumPrimitives
, &glPrimType
);
1216 if (numberOfVertices
== 0 )
1217 numberOfVertices
= calculatedNumberOfindices
;
1219 if (This
->useDrawStridedSlow
) {
1220 /* Immediate mode drawing */
1221 drawStridedSlow(iface
, &This
->strided_streams
, calculatedNumberOfindices
,
1222 glPrimType
, idxData
, idxSize
, minIndex
, StartIdx
, StartVertexIndex
);
1223 } else if(This
->instancedDraw
) {
1224 /* Instancing emulation with mixing immediate mode and arrays */
1225 drawStridedInstanced(iface
, &This
->strided_streams
, calculatedNumberOfindices
, glPrimType
,
1226 idxData
, idxSize
, minIndex
, StartIdx
, StartVertexIndex
);
1228 /* Simple array draw call */
1229 drawStridedFast(iface
, calculatedNumberOfindices
, glPrimType
,
1230 idxData
, idxSize
, minIndex
, StartIdx
, StartVertexIndex
);
1234 /* Finshed updating the screen, restore lock */
1236 TRACE("Done all gl drawing\n");
1239 #ifdef SHOW_FRAME_MAKEUP
1241 static long int primCounter
= 0;
1242 /* NOTE: set primCounter to the value reported by drawprim
1243 before you want to to write frame makeup to /tmp */
1244 if (primCounter
>= 0) {
1245 WINED3DLOCKED_RECT r
;
1247 IWineD3DSurface_LockRect(This
->renderTarget
, &r
, NULL
, WINED3DLOCK_READONLY
);
1248 sprintf(buffer
, "/tmp/backbuffer_%d.tga", primCounter
);
1249 TRACE("Saving screenshot %s\n", buffer
);
1250 IWineD3DSurface_SaveSnapshot(This
->renderTarget
, buffer
);
1251 IWineD3DSurface_UnlockRect(This
->renderTarget
);
1253 #ifdef SHOW_TEXTURE_MAKEUP
1255 IWineD3DSurface
*pSur
;
1257 for (textureNo
= 0; textureNo
< GL_LIMITS(textures
); ++textureNo
) {
1258 if (This
->stateBlock
->textures
[textureNo
] != NULL
) {
1259 sprintf(buffer
, "/tmp/texture_%p_%d_%d.tga", This
->stateBlock
->textures
[textureNo
], primCounter
, textureNo
);
1260 TRACE("Saving texture %s\n", buffer
);
1261 if (IWineD3DBaseTexture_GetType(This
->stateBlock
->textures
[textureNo
]) == WINED3DRTYPE_TEXTURE
) {
1262 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)This
->stateBlock
->textures
[textureNo
], 0, &pSur
);
1263 IWineD3DSurface_SaveSnapshot(pSur
, buffer
);
1264 IWineD3DSurface_Release(pSur
);
1266 FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This
->stateBlock
->textures
[textureNo
]));
1273 TRACE("drawprim #%d\n", primCounter
);
1278 /* Control goes back to the device, stateblock values may change again */
1279 This
->isInDraw
= FALSE
;