2004-12-09 12:42:34 +01:00
/*
* WINED3D draw functions
*
* Copyright 2002 - 2004 Jason Edmeades
* Copyright 2002 - 2004 Raphael Junqueira
2005-07-13 16:15:54 +02:00
* Copyright 2004 Christian Costa
2005-07-11 16:25:54 +02:00
* Copyright 2005 Oliver Stieber
2006-11-17 13:24:04 +01:00
* Copyright 2006 Henri Verbeet
2008-03-29 02:36:13 +01:00
* Copyright 2007 - 2008 Stefan D <EFBFBD> singer for CodeWeavers
2004-12-09 12:42:34 +01:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
2006-05-18 14:49:52 +02:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2004-12-09 12:42:34 +01:00
*/
# include "config.h"
# include "wined3d_private.h"
2005-07-07 22:45:39 +02:00
WINE_DEFAULT_DEBUG_CHANNEL ( d3d_draw ) ;
2007-06-09 14:27:41 +02:00
# define GLINFO_LOCATION This->adapter->gl_info
2004-12-09 12:42:34 +01:00
2005-09-27 12:49:59 +02:00
# include <stdio.h>
2007-12-17 18:18:19 +01:00
# include <math.h>
2005-09-27 12:49:59 +02:00
2004-12-09 12:42:34 +01:00
#if 0 /* TODO */
2005-08-19 12:05:00 +02:00
extern IWineD3DVertexShaderImpl * VertexShaders [ 64 ] ;
extern IWineD3DVertexDeclarationImpl * VertexShaderDeclarations [ 64 ] ;
extern IWineD3DPixelShaderImpl * PixelShaders [ 64 ] ;
2004-12-09 12:42:34 +01:00
# undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */
# endif
/* Issues the glBegin call for gl given the primitive type and count */
2006-10-12 08:23:55 +02:00
static DWORD primitiveToGl ( WINED3DPRIMITIVETYPE PrimitiveType ,
2004-12-09 12:42:34 +01:00
DWORD NumPrimitives ,
GLenum * primType )
{
DWORD NumVertexes = NumPrimitives ;
switch ( PrimitiveType ) {
2006-10-12 08:23:55 +02:00
case WINED3DPT_POINTLIST :
2004-12-09 12:42:34 +01:00
TRACE ( " POINTS \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_POINTS ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives ;
break ;
2006-10-12 08:23:55 +02:00
case WINED3DPT_LINELIST :
2004-12-09 12:42:34 +01:00
TRACE ( " LINES \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_LINES ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives * 2 ;
break ;
2006-10-12 08:23:55 +02:00
case WINED3DPT_LINESTRIP :
2004-12-09 12:42:34 +01:00
TRACE ( " LINE_STRIP \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_LINE_STRIP ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives + 1 ;
break ;
2006-10-12 08:23:55 +02:00
case WINED3DPT_TRIANGLELIST :
2004-12-09 12:42:34 +01:00
TRACE ( " TRIANGLES \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_TRIANGLES ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives * 3 ;
break ;
2006-10-12 08:23:55 +02:00
case WINED3DPT_TRIANGLESTRIP :
2004-12-09 12:42:34 +01:00
TRACE ( " TRIANGLE_STRIP \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_TRIANGLE_STRIP ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives + 2 ;
break ;
2006-10-12 08:23:55 +02:00
case WINED3DPT_TRIANGLEFAN :
2004-12-09 12:42:34 +01:00
TRACE ( " TRIANGLE_FAN \n " ) ;
2005-07-30 21:06:14 +02:00
* primType = GL_TRIANGLE_FAN ;
2004-12-09 12:42:34 +01:00
NumVertexes = NumPrimitives + 2 ;
break ;
default :
FIXME ( " Unhandled primitive \n " ) ;
* primType = GL_POINTS ;
break ;
2005-07-13 16:15:54 +02:00
}
2004-12-09 12:42:34 +01:00
return NumVertexes ;
}
2006-07-07 08:24:24 +02:00
static BOOL fixed_get_input (
BYTE usage , BYTE usage_idx ,
unsigned int * regnum ) {
* regnum = - 1 ;
/* Those positions must have the order in the
* named part of the strided data */
2007-02-13 23:12:14 +01:00
if ( ( usage = = WINED3DDECLUSAGE_POSITION | | usage = = WINED3DDECLUSAGE_POSITIONT ) & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 0 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_BLENDWEIGHT & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 1 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_BLENDINDICES & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 2 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_NORMAL & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 3 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_PSIZE & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 4 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_COLOR & & usage_idx = = 0 )
2006-07-07 08:24:24 +02:00
* regnum = 5 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_COLOR & & usage_idx = = 1 )
2006-07-07 08:24:24 +02:00
* regnum = 6 ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_TEXCOORD & & usage_idx < WINED3DDP_MAXTEXCOORD )
2006-07-07 08:24:24 +02:00
* regnum = 7 + usage_idx ;
2007-02-13 23:12:14 +01:00
else if ( ( usage = = WINED3DDECLUSAGE_POSITION | | usage = = WINED3DDECLUSAGE_POSITIONT ) & & usage_idx = = 1 )
2006-10-12 08:24:43 +02:00
* regnum = 7 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_NORMAL & & usage_idx = = 1 )
2006-10-12 08:24:43 +02:00
* regnum = 8 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_TANGENT & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 9 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_BINORMAL & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 10 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_TESSFACTOR & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 11 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_FOG & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 12 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_DEPTH & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 13 + WINED3DDP_MAXTEXCOORD ;
2007-02-13 23:12:14 +01:00
else if ( usage = = WINED3DDECLUSAGE_SAMPLE & & usage_idx = = 0 )
2006-10-12 08:24:43 +02:00
* regnum = 14 + WINED3DDP_MAXTEXCOORD ;
2006-07-07 08:24:24 +02:00
2007-12-03 20:41:31 +01:00
if ( * regnum = = - 1 ) {
2006-07-07 08:24:24 +02:00
FIXME ( " Unsupported input stream [usage=%s, usage_idx=%u] \n " ,
debug_d3ddeclusage ( usage ) , usage_idx ) ;
return FALSE ;
}
return TRUE ;
}
2006-06-12 08:51:58 +02:00
void primitiveDeclarationConvertToStridedData (
IWineD3DDevice * iface ,
BOOL useVertexShaderFunction ,
WineDirect3DVertexStridedData * strided ,
2006-06-21 15:01:38 +02:00
BOOL * fixup ) {
2006-06-12 08:51:58 +02:00
2005-07-07 22:45:39 +02:00
/* We need to deal with frequency data!*/
BYTE * data = NULL ;
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2007-02-13 23:12:29 +01:00
IWineD3DVertexDeclarationImpl * vertexDeclaration = ( IWineD3DVertexDeclarationImpl * ) This - > stateBlock - > vertexDecl ;
2005-07-07 22:45:39 +02:00
int i ;
2005-12-09 11:23:52 +01:00
WINED3DVERTEXELEMENT * element ;
2005-07-07 22:45:39 +02:00
DWORD stride ;
2007-08-03 19:53:25 +02:00
DWORD numPreloadStreams = This - > stateBlock - > streamIsUP ? 0 : vertexDeclaration - > num_streams ;
DWORD * streams = vertexDeclaration - > streams ;
2005-07-07 22:45:39 +02:00
2007-03-12 23:22:00 +01:00
/* Check for transformed vertices, disable vertex shader if present */
2007-07-30 12:35:33 +02:00
strided - > u . s . position_transformed = vertexDeclaration - > position_transformed ;
if ( vertexDeclaration - > position_transformed ) {
useVertexShaderFunction = FALSE ;
2007-03-12 23:22:00 +01:00
}
2005-12-09 11:23:52 +01:00
/* Translate the declaration into strided data */
for ( i = 0 ; i < vertexDeclaration - > declarationWNumElements - 1 ; + + i ) {
2006-06-21 15:01:38 +02:00
GLint streamVBO = 0 ;
2006-07-07 08:24:24 +02:00
BOOL stride_used ;
unsigned int idx ;
2005-12-09 11:23:52 +01:00
element = vertexDeclaration - > pDeclarationWine + i ;
2006-09-17 22:26:18 +02:00
TRACE ( " %p Element %p (%d of %d) \n " , vertexDeclaration - > pDeclarationWine ,
element , i + 1 , vertexDeclaration - > declarationWNumElements - 1 ) ;
if ( This - > stateBlock - > streamSource [ element - > Stream ] = = NULL )
continue ;
2007-08-25 00:09:33 +02:00
stride = This - > stateBlock - > streamStride [ element - > Stream ] ;
2005-07-07 22:45:39 +02:00
if ( This - > stateBlock - > streamIsUP ) {
TRACE ( " Stream is up %d, %p \n " , element - > Stream , This - > stateBlock - > streamSource [ element - > Stream ] ) ;
2006-06-21 15:01:38 +02:00
streamVBO = 0 ;
2005-07-07 22:45:39 +02:00
data = ( BYTE * ) This - > stateBlock - > streamSource [ element - > Stream ] ;
} else {
2005-07-24 19:11:33 +02:00
TRACE ( " Stream isn't up %d, %p \n " , element - > Stream , This - > stateBlock - > streamSource [ element - > Stream ] ) ;
2006-06-21 15:01:38 +02:00
data = IWineD3DVertexBufferImpl_GetMemory ( This - > stateBlock - > streamSource [ element - > Stream ] , 0 , & streamVBO ) ;
2007-08-25 00:09:33 +02:00
/* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
* ( or rather offsets bigger than the vbo , because the pointer is unsigned ) , so use system memory
* sources . In most sane cases the pointer - offset will still be > 0 , otherwise it will wrap
* around to some big value . Hope that with the indices , the driver wraps it back internally . If
* not , drawStridedSlow is needed , including a vertex buffer path .
*/
if ( This - > stateBlock - > loadBaseVertexIndex < 0 ) {
WARN ( " loadBaseVertexIndex is < 0 (%d), not using vbos \n " , This - > stateBlock - > loadBaseVertexIndex ) ;
streamVBO = 0 ;
data = ( ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ element - > Stream ] ) - > resource . allocatedMemory ;
2007-12-10 23:55:18 +01:00
if ( ( UINT_PTR ) data < - This - > stateBlock - > loadBaseVertexIndex * stride ) {
2007-08-25 00:09:33 +02:00
FIXME ( " System memory vertex data load offset is negative! \n " ) ;
}
}
2006-06-21 15:01:38 +02:00
if ( fixup ) {
if ( streamVBO ! = 0 ) * fixup = TRUE ;
2007-07-09 16:52:09 +02:00
else if ( * fixup & & ! useVertexShaderFunction & &
( element - > Usage = = WINED3DDECLUSAGE_COLOR | |
element - > Usage = = WINED3DDECLUSAGE_POSITIONT ) ) {
2008-05-09 20:57:26 +02:00
static BOOL warned = FALSE ;
if ( ! warned ) {
/* This may be bad with the fixed function pipeline */
FIXME ( " Missing vbo streams with unfixed colors or transformed position, expect problems \n " ) ;
warned = TRUE ;
}
2007-02-20 22:42:34 +01:00
}
2006-06-21 15:01:38 +02:00
}
2005-07-07 22:45:39 +02:00
}
data + = element - > Offset ;
2005-12-09 11:23:52 +01:00
TRACE ( " Offset %d Stream %d UsageIndex %d \n " , element - > Offset , element - > Stream , element - > UsageIndex ) ;
2006-03-22 20:47:54 +01:00
2006-07-07 08:27:38 +02:00
if ( useVertexShaderFunction )
stride_used = vshader_get_input ( This - > stateBlock - > vertexShader ,
element - > Usage , element - > UsageIndex , & idx ) ;
else
stride_used = fixed_get_input ( element - > Usage , element - > UsageIndex , & idx ) ;
2006-07-07 08:24:24 +02:00
if ( stride_used ) {
2007-03-12 23:21:49 +01:00
TRACE ( " Loaded %s array %u [usage=%s, usage_idx=%u, "
2007-07-23 21:35:22 +02:00
" stream=%u, offset=%u, stride=%u, type=%s, VBO=%u] \n " ,
2007-03-12 23:21:49 +01:00
useVertexShaderFunction ? " shader " : " fixed function " , idx ,
debug_d3ddeclusage ( element - > Usage ) , element - > UsageIndex ,
2007-07-23 21:35:22 +02:00
element - > Stream , element - > Offset , stride , debug_d3ddecltype ( element - > Type ) , streamVBO ) ;
2007-03-12 23:21:49 +01:00
strided - > u . input [ idx ] . lpData = data ;
strided - > u . input [ idx ] . dwType = element - > Type ;
strided - > u . input [ idx ] . dwStride = stride ;
strided - > u . input [ idx ] . VBO = streamVBO ;
strided - > u . input [ idx ] . streamNo = element - > Stream ;
2005-07-07 22:45:39 +02:00
}
2007-03-12 23:21:49 +01:00
}
2007-01-06 18:31:43 +01:00
/* Now call PreLoad on all the vertex buffers. In the very rare case
* that the buffers stopps converting PreLoad will dirtify the VDECL again .
* The vertex buffer can now use the strided structure in the device instead of finding its
* own again .
*
* NULL streams won ' t be recorded in the array , UP streams won ' t be either . A stream is only
* once in there .
*/
for ( i = 0 ; i < numPreloadStreams ; i + + ) {
2007-09-19 00:17:06 +02:00
IWineD3DVertexBuffer * vb = This - > stateBlock - > streamSource [ streams [ i ] ] ;
if ( vb ) {
IWineD3DVertexBuffer_PreLoad ( vb ) ;
}
2007-01-06 18:31:43 +01:00
}
2005-07-07 22:45:39 +02:00
}
2005-08-19 12:05:00 +02:00
static void drawStridedFast ( IWineD3DDevice * iface , UINT numberOfVertices , GLenum glPrimitiveType ,
2007-01-02 21:07:39 +01:00
const void * idxData , short idxSize , ULONG minIndex , ULONG startIdx , ULONG startVertex ) {
2005-08-19 12:05:00 +02:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2004-12-09 12:42:34 +01:00
2007-02-19 15:25:32 +01:00
if ( idxSize ! = 0 /* This crashes sometimes!*/ ) {
2006-10-01 05:20:10 +02:00
TRACE ( " (%p) : glElements(%x, %d, %d, ...) \n " , This , glPrimitiveType , numberOfVertices , minIndex ) ;
2005-08-19 12:05:00 +02:00
idxData = idxData = = ( void * ) - 1 ? NULL : idxData ;
# if 1
glDrawElements ( glPrimitiveType , numberOfVertices , idxSize = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ,
( const char * ) idxData + ( idxSize * startIdx ) ) ;
2007-08-10 16:01:12 +02:00
checkGLcall ( " glDrawElements " ) ;
2005-08-19 12:05:00 +02:00
# else /* using drawRangeElements may be faster */
2004-12-09 12:42:34 +01:00
2005-08-19 12:05:00 +02:00
glDrawRangeElements ( glPrimitiveType , minIndex , minIndex + numberOfVertices - 1 , numberOfVertices ,
idxSize = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ,
( const char * ) idxData + ( idxSize * startIdx ) ) ;
2004-12-09 12:42:34 +01:00
checkGLcall ( " glDrawRangeElements " ) ;
2007-08-10 16:01:12 +02:00
# endif
2004-12-09 12:42:34 +01:00
} else {
/* Note first is now zero as we shuffled along earlier */
2005-08-19 12:05:00 +02:00
TRACE ( " (%p) : glDrawArrays(%x, 0, %d) \n " , This , glPrimitiveType , numberOfVertices ) ;
2007-01-02 21:07:39 +01:00
glDrawArrays ( glPrimitiveType , startVertex , numberOfVertices ) ;
2004-12-09 12:42:34 +01:00
checkGLcall ( " glDrawArrays " ) ;
}
2005-08-19 12:05:00 +02:00
return ;
2004-12-09 12:42:34 +01:00
}
2005-07-13 16:15:54 +02:00
/*
2004-12-09 12:42:34 +01:00
* Actually draw using the supplied information .
* Slower GL version which extracts info about each vertex in turn
*/
2007-01-02 21:07:39 +01:00
2006-05-06 16:58:57 +02:00
static void drawStridedSlow ( IWineD3DDevice * iface , WineDirect3DVertexStridedData * sd ,
2005-08-19 12:05:00 +02:00
UINT NumVertexes , GLenum glPrimType ,
2007-01-02 21:07:39 +01:00
const void * idxData , short idxSize , ULONG minIndex , ULONG startIdx , ULONG startVertex ) {
2004-12-09 12:42:34 +01:00
unsigned int textureNo = 0 ;
2007-04-06 14:22:14 +02:00
const WORD * pIdxBufS = NULL ;
const DWORD * pIdxBufL = NULL ;
2004-12-09 12:42:34 +01:00
LONG vx_index ;
DWORD diffuseColor = 0xFFFFFFFF ; /* Diffuse Color */
DWORD specularColor = 0 ; /* Specular Color */
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2007-01-17 00:06:34 +01:00
UINT * streamOffset = This - > stateBlock - > streamOffset ;
2007-08-25 00:09:33 +02:00
long SkipnStrides = startVertex + This - > stateBlock - > loadBaseVertexIndex ;
2007-08-29 21:59:49 +02:00
BOOL pixelShader = use_ps ( This ) ;
2004-12-09 12:42:34 +01:00
2007-01-17 00:06:34 +01:00
BYTE * texCoords [ WINED3DDP_MAXTEXCOORD ] ;
BYTE * diffuse = NULL , * specular = NULL , * normal = NULL , * position = NULL ;
2004-12-09 12:42:34 +01:00
TRACE ( " Using slow vertex array code \n " ) ;
/* Variable Initialization */
2007-02-19 15:25:32 +01:00
if ( idxSize ! = 0 ) {
/* Immediate mode drawing can't make use of indices in a vbo - get the data from the index buffer.
* If the index buffer has no vbo ( not supported or other reason ) , or with user pointer drawing
* idxData will be ! = NULL
*/
if ( idxData = = NULL ) {
idxData = ( ( IWineD3DIndexBufferImpl * ) This - > stateBlock - > pIndexData ) - > resource . allocatedMemory ;
}
2007-04-06 14:22:14 +02:00
if ( idxSize = = 2 ) pIdxBufS = ( const WORD * ) idxData ;
else pIdxBufL = ( const DWORD * ) idxData ;
2004-12-09 12:42:34 +01:00
}
2007-01-17 00:06:34 +01:00
/* Adding the stream offset once is cheaper than doing it every iteration. Do not modify the strided data, it is a pointer
* to the strided Data in the device and might be needed intact on the next draw
*/
2007-06-21 00:01:05 +02:00
for ( textureNo = 0 ; textureNo < GL_LIMITS ( texture_stages ) ; + + textureNo ) {
2007-01-17 00:06:34 +01:00
if ( sd - > u . s . texCoords [ textureNo ] . lpData ) {
texCoords [ textureNo ] = sd - > u . s . texCoords [ textureNo ] . lpData + streamOffset [ sd - > u . s . texCoords [ textureNo ] . streamNo ] ;
} else {
texCoords [ textureNo ] = NULL ;
}
}
if ( sd - > u . s . diffuse . lpData ) {
diffuse = sd - > u . s . diffuse . lpData + streamOffset [ sd - > u . s . diffuse . streamNo ] ;
}
if ( sd - > u . s . specular . lpData ) {
specular = sd - > u . s . specular . lpData + streamOffset [ sd - > u . s . specular . streamNo ] ;
}
if ( sd - > u . s . normal . lpData ) {
normal = sd - > u . s . normal . lpData + streamOffset [ sd - > u . s . normal . streamNo ] ;
}
if ( sd - > u . s . position . lpData ) {
position = sd - > u . s . position . lpData + streamOffset [ sd - > u . s . position . streamNo ] ;
}
2007-12-19 17:10:02 +01:00
/* The texture coordinate types are not so easy to map into a common function signature - we're
* not using the vector functions here
*/
if ( FIXME_ON ( d3d_draw ) ) {
for ( textureNo = 0 ; textureNo < GL_LIMITS ( textures ) ; + + textureNo ) {
DWORD type = sd - > u . s . texCoords [ textureNo ] . dwType ;
if ( sd - > u . s . texCoords [ textureNo ] . lpData & &
type ! = WINED3DDECLTYPE_FLOAT1 & &
type ! = WINED3DDECLTYPE_FLOAT2 & &
type ! = WINED3DDECLTYPE_FLOAT3 & &
type ! = WINED3DDECLTYPE_FLOAT4 ) {
FIXME ( " Implement fixed function texture coordinates from %s \n " , debug_d3ddecltype ( type ) ) ;
}
}
if ( specular & & This - > stateBlock - > renderState [ WINED3DRS_FOGENABLE ] & &
( This - > stateBlock - > renderState [ WINED3DRS_FOGVERTEXMODE ] = = WINED3DFOG_NONE | | sd - > u . s . position_transformed ) & &
This - > stateBlock - > renderState [ WINED3DRS_FOGTABLEMODE ] = = WINED3DFOG_NONE ) {
if ( GL_SUPPORT ( EXT_FOG_COORD ) & & sd - > u . s . specular . dwType ! = WINED3DDECLTYPE_D3DCOLOR ) {
FIXME ( " Implement fog coordinates from %s \n " , debug_d3ddecltype ( sd - > u . s . specular . dwType ) ) ;
}
}
if ( This - > activeContext - > num_untracked_materials & & sd - > u . s . diffuse . dwType ! = WINED3DDECLTYPE_D3DCOLOR ) {
FIXME ( " Implement diffuse color tracking from %s \n " , debug_d3ddecltype ( sd - > u . s . diffuse . dwType ) ) ;
}
}
2004-12-09 12:42:34 +01:00
/* Start drawing in GL */
VTRACE ( ( " glBegin(%x) \n " , glPrimType ) ) ;
glBegin ( glPrimType ) ;
2007-01-16 23:43:28 +01:00
/* Default settings for data that is not passed */
if ( sd - > u . s . normal . lpData = = NULL ) {
2007-08-21 18:05:27 +02:00
glNormal3f ( 0 , 0 , 0 ) ;
2007-01-16 23:43:28 +01:00
}
2007-04-14 02:57:37 +02:00
if ( sd - > u . s . diffuse . lpData = = NULL ) {
2007-01-16 23:43:28 +01:00
glColor4f ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
}
2007-04-14 02:57:37 +02:00
if ( sd - > u . s . specular . lpData = = NULL ) {
2007-01-16 23:43:28 +01:00
if ( GL_SUPPORT ( EXT_SECONDARY_COLOR ) ) {
GL_EXTCALL ( glSecondaryColor3fEXT ) ( 0 , 0 , 0 ) ;
}
}
2006-06-21 15:01:38 +02:00
/* We shouldn't start this function if any VBO is involved. Should I put a safety check here?
* Guess it ' s not necessary ( we crash then anyway ) and would only eat CPU time
*/
2004-12-09 12:42:34 +01:00
/* For each primitive */
2005-07-30 21:06:14 +02:00
for ( vx_index = 0 ; vx_index < NumVertexes ; + + vx_index ) {
2004-12-09 12:42:34 +01:00
/* Initialize diffuse color */
diffuseColor = 0xFFFFFFFF ;
2007-01-16 23:43:28 +01:00
/* Blending data and Point sizes are not supported by this function. They are not supported by the fixed
* function pipeline at all . A Fixme for them is printed after decoding the vertex declaration
*/
2004-12-09 12:42:34 +01:00
/* For indexed data, we need to go a few more strides in */
if ( idxData ! = NULL ) {
/* Indexed so work out the number of strides to skip */
if ( idxSize = = 2 ) {
2006-10-01 05:20:10 +02:00
VTRACE ( ( " Idx for vertex %d = %d \n " , vx_index , pIdxBufS [ startIdx + vx_index ] ) ) ;
2007-01-06 18:19:55 +01:00
SkipnStrides = pIdxBufS [ startIdx + vx_index ] + This - > stateBlock - > loadBaseVertexIndex ;
2004-12-09 12:42:34 +01:00
} else {
2006-10-01 05:20:10 +02:00
VTRACE ( ( " Idx for vertex %d = %d \n " , vx_index , pIdxBufL [ startIdx + vx_index ] ) ) ;
2007-01-06 18:19:55 +01:00
SkipnStrides = pIdxBufL [ startIdx + vx_index ] + This - > stateBlock - > loadBaseVertexIndex ;
2004-12-09 12:42:34 +01:00
}
}
/* Texture coords --------------------------- */
2007-06-21 00:01:05 +02:00
for ( textureNo = 0 ; textureNo < GL_LIMITS ( texture_stages ) ; + + textureNo ) {
2004-12-09 12:42:34 +01:00
if ( ! GL_SUPPORT ( ARB_MULTITEXTURE ) & & textureNo > 0 ) {
FIXME ( " Program using multiple concurrent textures which this opengl implementation doesn't support \n " ) ;
continue ;
}
/* Query tex coords */
2007-08-29 21:59:49 +02:00
if ( This - > stateBlock - > textures [ textureNo ] ! = NULL | | pixelShader ) {
2004-12-09 12:42:34 +01:00
2006-10-11 03:52:50 +02:00
int coordIdx = This - > stateBlock - > textureState [ textureNo ] [ WINED3DTSS_TEXCOORDINDEX ] ;
2007-08-29 21:59:49 +02:00
int texture_idx = This - > texUnitMap [ textureNo ] ;
2005-11-07 12:13:26 +01:00
float * ptrToCoords = NULL ;
2004-12-09 12:42:34 +01:00
float s = 0.0 , t = 0.0 , r = 0.0 , q = 0.0 ;
if ( coordIdx > 7 ) {
VTRACE ( ( " tex: %d - Skip tex coords, as being system generated \n " , textureNo ) ) ;
continue ;
2005-11-07 12:13:26 +01:00
} else if ( coordIdx < 0 ) {
FIXME ( " tex: %d - Coord index %d is less than zero, expect a crash. \n " , textureNo , coordIdx ) ;
continue ;
}
2007-01-17 00:06:34 +01:00
ptrToCoords = ( float * ) ( texCoords [ coordIdx ] + ( SkipnStrides * sd - > u . s . texCoords [ coordIdx ] . dwStride ) ) ;
if ( texCoords [ coordIdx ] = = NULL ) {
2004-12-09 12:42:34 +01:00
TRACE ( " tex: %d - Skipping tex coords, as no data supplied \n " , textureNo ) ;
2007-08-29 21:59:49 +02:00
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
GL_EXTCALL ( glMultiTexCoord4fARB ( GL_TEXTURE0_ARB + texture_idx , 0 , 0 , 0 , 1 ) ) ;
} else {
glTexCoord4f ( 0 , 0 , 0 , 1 ) ;
}
2004-12-09 12:42:34 +01:00
continue ;
} else {
2006-10-11 03:54:22 +02:00
int coordsToUse = sd - > u . s . texCoords [ coordIdx ] . dwType + 1 ; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */
2004-12-09 12:42:34 +01:00
2007-06-21 00:01:05 +02:00
if ( texture_idx = = - 1 ) continue ;
2004-12-09 12:42:34 +01:00
/* The coords to supply depend completely on the fvf / vertex shader */
switch ( coordsToUse ) {
case 4 : q = ptrToCoords [ 3 ] ; /* drop through */
case 3 : r = ptrToCoords [ 2 ] ; /* drop through */
case 2 : t = ptrToCoords [ 1 ] ; /* drop through */
2005-07-13 16:15:54 +02:00
case 1 : s = ptrToCoords [ 0 ] ;
2004-12-09 12:42:34 +01:00
}
switch ( coordsToUse ) { /* Supply the provided texture coords */
2006-10-13 05:36:09 +02:00
case WINED3DTTFF_COUNT1 :
2004-12-09 12:42:34 +01:00
VTRACE ( ( " tex:%d, s=%f \n " , textureNo , s ) ) ;
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
2007-07-24 23:38:31 +02:00
GL_EXTCALL ( glMultiTexCoord1fARB ( GL_TEXTURE0_ARB + texture_idx , s ) ) ;
2004-12-09 12:42:34 +01:00
} else {
glTexCoord1f ( s ) ;
}
break ;
2006-10-13 05:36:09 +02:00
case WINED3DTTFF_COUNT2 :
2004-12-09 12:42:34 +01:00
VTRACE ( ( " tex:%d, s=%f, t=%f \n " , textureNo , s , t ) ) ;
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
2007-07-24 23:38:31 +02:00
GL_EXTCALL ( glMultiTexCoord2fARB ( GL_TEXTURE0_ARB + texture_idx , s , t ) ) ;
2004-12-09 12:42:34 +01:00
} else {
glTexCoord2f ( s , t ) ;
}
break ;
2006-10-13 05:36:09 +02:00
case WINED3DTTFF_COUNT3 :
2004-12-09 12:42:34 +01:00
VTRACE ( ( " tex:%d, s=%f, t=%f, r=%f \n " , textureNo , s , t , r ) ) ;
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
2007-07-24 23:38:31 +02:00
GL_EXTCALL ( glMultiTexCoord3fARB ( GL_TEXTURE0_ARB + texture_idx , s , t , r ) ) ;
2004-12-09 12:42:34 +01:00
} else {
glTexCoord3f ( s , t , r ) ;
}
break ;
2006-10-13 05:36:09 +02:00
case WINED3DTTFF_COUNT4 :
2004-12-09 12:42:34 +01:00
VTRACE ( ( " tex:%d, s=%f, t=%f, r=%f, q=%f \n " , textureNo , s , t , r , q ) ) ;
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) ) {
2007-07-24 23:38:31 +02:00
GL_EXTCALL ( glMultiTexCoord4fARB ( GL_TEXTURE0_ARB + texture_idx , s , t , r , q ) ) ;
2004-12-09 12:42:34 +01:00
} else {
glTexCoord4f ( s , t , r , q ) ;
}
break ;
default :
FIXME ( " Should not get here as coordsToUse is two bits only (%x)! \n " , coordsToUse ) ;
}
}
}
} /* End of textures */
/* Diffuse -------------------------------- */
2007-01-17 00:06:34 +01:00
if ( diffuse ) {
DWORD * ptrToCoords = ( DWORD * ) ( diffuse + ( SkipnStrides * sd - > u . s . diffuse . dwStride ) ) ;
2007-06-20 14:36:32 +02:00
2007-12-19 17:10:02 +01:00
diffuse_funcs [ sd - > u . s . diffuse . dwType ] ( ( void * ) ptrToCoords ) ;
2007-06-20 14:36:32 +02:00
if ( This - > activeContext - > num_untracked_materials ) {
unsigned char i ;
float color [ 4 ] ;
2007-12-19 17:10:02 +01:00
diffuseColor = ptrToCoords [ 0 ] ;
2007-06-20 14:36:32 +02:00
color [ 0 ] = D3DCOLOR_B_R ( diffuseColor ) / 255.0 ;
color [ 1 ] = D3DCOLOR_B_G ( diffuseColor ) / 255.0 ;
color [ 2 ] = D3DCOLOR_B_B ( diffuseColor ) / 255.0 ;
color [ 3 ] = D3DCOLOR_B_A ( diffuseColor ) / 255.0 ;
for ( i = 0 ; i < This - > activeContext - > num_untracked_materials ; i + + ) {
glMaterialfv ( GL_FRONT_AND_BACK , This - > activeContext - > untracked_materials [ i ] , color ) ;
}
}
2004-12-09 12:42:34 +01:00
}
/* Specular ------------------------------- */
2007-01-17 00:06:34 +01:00
if ( specular ) {
DWORD * ptrToCoords = ( DWORD * ) ( specular + ( SkipnStrides * sd - > u . s . specular . dwStride ) ) ;
2007-01-16 23:43:28 +01:00
2007-03-22 17:32:48 +01:00
/* special case where the fog density is stored in the specular alpha channel */
2006-06-12 13:25:10 +02:00
if ( This - > stateBlock - > renderState [ WINED3DRS_FOGENABLE ] & &
2006-10-30 03:41:42 +01:00
( This - > stateBlock - > renderState [ WINED3DRS_FOGVERTEXMODE ] = = WINED3DFOG_NONE | | sd - > u . s . position . dwType = = WINED3DDECLTYPE_FLOAT4 ) & &
This - > stateBlock - > renderState [ WINED3DRS_FOGTABLEMODE ] = = WINED3DFOG_NONE ) {
2006-06-12 13:25:10 +02:00
if ( GL_SUPPORT ( EXT_FOG_COORD ) ) {
2007-12-19 17:10:02 +01:00
specularColor = ptrToCoords [ 0 ] ;
2006-06-12 13:25:10 +02:00
GL_EXTCALL ( glFogCoordfEXT ( specularColor > > 24 ) ) ;
} else {
static BOOL warned = FALSE ;
if ( ! warned ) {
/* TODO: Use the fog table code from old ddraw */
FIXME ( " Implement fog for transformed vertices in software \n " ) ;
warned = TRUE ;
}
}
}
2007-12-19 17:10:02 +01:00
specular_funcs [ sd - > u . s . specular . dwType ] ( ( void * ) ptrToCoords ) ;
2004-12-09 12:42:34 +01:00
}
/* Normal -------------------------------- */
2007-01-17 00:06:34 +01:00
if ( normal ! = NULL ) {
float * ptrToCoords = ( float * ) ( normal + ( SkipnStrides * sd - > u . s . normal . dwStride ) ) ;
2007-12-19 17:10:02 +01:00
normal_funcs [ sd - > u . s . normal . dwType ] ( ptrToCoords ) ;
2004-12-09 12:42:34 +01:00
}
2005-07-13 16:15:54 +02:00
2004-12-09 12:42:34 +01:00
/* Position -------------------------------- */
2007-01-17 00:06:34 +01:00
if ( position ) {
float * ptrToCoords = ( float * ) ( position + ( SkipnStrides * sd - > u . s . position . dwStride ) ) ;
2007-12-19 17:10:02 +01:00
position_funcs [ sd - > u . s . position . dwType ] ( ptrToCoords ) ;
2004-12-09 12:42:34 +01:00
}
/* For non indexed mode, step onto next parts */
if ( idxData = = NULL ) {
2005-07-30 21:06:14 +02:00
+ + SkipnStrides ;
2004-12-09 12:42:34 +01:00
}
}
glEnd ( ) ;
checkGLcall ( " glEnd and previous calls " ) ;
}
2007-12-17 18:18:19 +01:00
static inline void send_attribute ( IWineD3DDeviceImpl * This , const DWORD type , const UINT index , const void * ptr ) {
switch ( type ) {
case WINED3DDECLTYPE_FLOAT1 :
GL_EXTCALL ( glVertexAttrib1fvARB ( index , ( float * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_FLOAT2 :
GL_EXTCALL ( glVertexAttrib2fvARB ( index , ( float * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_FLOAT3 :
GL_EXTCALL ( glVertexAttrib3fvARB ( index , ( float * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_FLOAT4 :
GL_EXTCALL ( glVertexAttrib4fvARB ( index , ( float * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_UBYTE4 :
GL_EXTCALL ( glVertexAttrib4ubvARB ( index , ptr ) ) ;
break ;
case WINED3DDECLTYPE_UBYTE4N :
case WINED3DDECLTYPE_D3DCOLOR :
GL_EXTCALL ( glVertexAttrib4NubvARB ( index , ptr ) ) ;
break ;
case WINED3DDECLTYPE_SHORT2 :
GL_EXTCALL ( glVertexAttrib4svARB ( index , ( GLshort * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_SHORT4 :
GL_EXTCALL ( glVertexAttrib4svARB ( index , ( GLshort * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_SHORT2N :
{
GLshort s [ 4 ] = { ( ( short * ) ptr ) [ 0 ] , ( ( short * ) ptr ) [ 1 ] , 0 , 1 } ;
GL_EXTCALL ( glVertexAttrib4NsvARB ( index , s ) ) ;
break ;
}
case WINED3DDECLTYPE_USHORT2N :
{
GLushort s [ 4 ] = { ( ( unsigned short * ) ptr ) [ 0 ] , ( ( unsigned short * ) ptr ) [ 1 ] , 0 , 1 } ;
GL_EXTCALL ( glVertexAttrib4NusvARB ( index , s ) ) ;
break ;
}
case WINED3DDECLTYPE_SHORT4N :
GL_EXTCALL ( glVertexAttrib4NsvARB ( index , ( GLshort * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_USHORT4N :
GL_EXTCALL ( glVertexAttrib4NusvARB ( index , ( GLushort * ) ptr ) ) ;
break ;
case WINED3DDECLTYPE_UDEC3 :
FIXME ( " Unsure about WINED3DDECLTYPE_UDEC3 \n " ) ;
/*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */
break ;
case WINED3DDECLTYPE_DEC3N :
FIXME ( " Unsure about WINED3DDECLTYPE_DEC3N \n " ) ;
/*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */
break ;
case WINED3DDECLTYPE_FLOAT16_2 :
/* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4
* byte float according to the IEEE standard
*/
if ( GL_SUPPORT ( NV_HALF_FLOAT ) ) {
GL_EXTCALL ( glVertexAttrib2hvNV ( index , ( GLhalfNV * ) ptr ) ) ;
} else {
float x = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 0 ) ;
float y = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 1 ) ;
GL_EXTCALL ( glVertexAttrib2fARB ( index , x , y ) ) ;
}
break ;
case WINED3DDECLTYPE_FLOAT16_4 :
if ( GL_SUPPORT ( NV_HALF_FLOAT ) ) {
GL_EXTCALL ( glVertexAttrib4hvNV ( index , ( GLhalfNV * ) ptr ) ) ;
} else {
float x = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 0 ) ;
float y = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 1 ) ;
float z = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 2 ) ;
float w = float_16_to_32 ( ( ( unsigned short * ) ptr ) + 3 ) ;
GL_EXTCALL ( glVertexAttrib4fARB ( index , x , y , z , w ) ) ;
}
break ;
case WINED3DDECLTYPE_UNUSED :
default :
ERR ( " Unexpected attribute declaration: %d \n " , type ) ;
break ;
}
}
static void drawStridedSlowVs ( IWineD3DDevice * iface , WineDirect3DVertexStridedData * sd , UINT numberOfVertices ,
GLenum glPrimitiveType , const void * idxData , short idxSize , ULONG minIndex , ULONG startIdx ,
ULONG startVertex ) {
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
long SkipnStrides = startVertex + This - > stateBlock - > loadBaseVertexIndex ;
const WORD * pIdxBufS = NULL ;
const DWORD * pIdxBufL = NULL ;
LONG vx_index ;
int i ;
2008-01-23 22:39:59 +01:00
IWineD3DStateBlockImpl * stateblock = This - > stateBlock ;
2007-12-17 18:18:19 +01:00
BYTE * ptr ;
if ( idxSize ! = 0 ) {
/* Immediate mode drawing can't make use of indices in a vbo - get the data from the index buffer.
* If the index buffer has no vbo ( not supported or other reason ) , or with user pointer drawing
* idxData will be ! = NULL
*/
if ( idxData = = NULL ) {
idxData = ( ( IWineD3DIndexBufferImpl * ) stateblock - > pIndexData ) - > resource . allocatedMemory ;
}
if ( idxSize = = 2 ) pIdxBufS = ( const WORD * ) idxData ;
else pIdxBufL = ( const DWORD * ) idxData ;
}
/* Start drawing in GL */
VTRACE ( ( " glBegin(%x) \n " , glPrimType ) ) ;
glBegin ( glPrimitiveType ) ;
for ( vx_index = 0 ; vx_index < numberOfVertices ; + + vx_index ) {
if ( idxData ! = NULL ) {
/* Indexed so work out the number of strides to skip */
if ( idxSize = = 2 ) {
VTRACE ( ( " Idx for vertex %d = %d \n " , vx_index , pIdxBufS [ startIdx + vx_index ] ) ) ;
SkipnStrides = pIdxBufS [ startIdx + vx_index ] + stateblock - > loadBaseVertexIndex ;
} else {
VTRACE ( ( " Idx for vertex %d = %d \n " , vx_index , pIdxBufL [ startIdx + vx_index ] ) ) ;
SkipnStrides = pIdxBufL [ startIdx + vx_index ] + stateblock - > loadBaseVertexIndex ;
}
}
for ( i = MAX_ATTRIBS - 1 ; i > = 0 ; i - - ) {
if ( ! sd - > u . input [ i ] . lpData ) continue ;
ptr = sd - > u . input [ i ] . lpData +
sd - > u . input [ i ] . dwStride * SkipnStrides +
stateblock - > streamOffset [ sd - > u . input [ i ] . streamNo ] ;
send_attribute ( This , sd - > u . input [ i ] . dwType , i , ptr ) ;
}
2007-12-19 16:28:14 +01:00
SkipnStrides + + ;
2007-12-17 18:18:19 +01:00
}
glEnd ( ) ;
}
2008-07-02 23:00:41 +02:00
void depth_blt ( IWineD3DDevice * iface , GLuint texture ) {
2006-11-17 13:24:04 +01:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2006-12-25 17:12:50 +01:00
GLint old_binding = 0 ;
2006-11-17 13:24:04 +01:00
2007-06-05 18:52:15 +02:00
glPushAttrib ( GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ) ;
2006-11-17 13:24:04 +01:00
glDisable ( GL_CULL_FACE ) ;
2007-06-05 18:52:15 +02:00
glEnable ( GL_BLEND ) ;
2006-11-17 13:24:04 +01:00
glDisable ( GL_ALPHA_TEST ) ;
2007-04-10 19:14:10 +02:00
glDisable ( GL_SCISSOR_TEST ) ;
2006-11-17 13:24:04 +01:00
glDisable ( GL_STENCIL_TEST ) ;
glEnable ( GL_DEPTH_TEST ) ;
glDepthFunc ( GL_ALWAYS ) ;
2008-06-25 00:32:00 +02:00
glDepthMask ( GL_TRUE ) ;
2007-06-05 18:52:15 +02:00
glBlendFunc ( GL_ZERO , GL_ONE ) ;
2006-11-17 13:24:04 +01:00
GL_EXTCALL ( glActiveTextureARB ( GL_TEXTURE0_ARB ) ) ;
2006-12-25 17:12:50 +01:00
glGetIntegerv ( GL_TEXTURE_BINDING_2D , & old_binding ) ;
2006-11-17 13:24:04 +01:00
glBindTexture ( GL_TEXTURE_2D , texture ) ;
glEnable ( GL_TEXTURE_2D ) ;
2006-11-27 20:50:43 +01:00
This - > shader_backend - > shader_select_depth_blt ( iface ) ;
2006-11-17 13:24:04 +01:00
glBegin ( GL_TRIANGLE_STRIP ) ;
glVertex2f ( - 1.0f , - 1.0f ) ;
glVertex2f ( 1.0f , - 1.0f ) ;
glVertex2f ( - 1.0f , 1.0f ) ;
glVertex2f ( 1.0f , 1.0f ) ;
glEnd ( ) ;
2006-12-25 17:12:50 +01:00
glBindTexture ( GL_TEXTURE_2D , old_binding ) ;
2006-11-17 13:24:04 +01:00
glPopAttrib ( ) ;
2007-01-06 18:14:12 +01:00
/* Reselect the old shaders. There doesn't seem to be any glPushAttrib bit for arb shaders,
* and this seems easier and more efficient than providing the shader backend with a private
* storage to read and restore the old shader settings
*/
2007-03-12 23:22:00 +01:00
This - > shader_backend - > shader_select ( iface , use_ps ( This ) , use_vs ( This ) ) ;
2006-11-17 13:24:04 +01:00
}
2007-03-12 16:50:54 +01:00
static inline void drawStridedInstanced ( IWineD3DDevice * iface , WineDirect3DVertexStridedData * sd , UINT numberOfVertices ,
2007-02-14 17:56:29 +01:00
GLenum glPrimitiveType , const void * idxData , short idxSize , ULONG minIndex ,
ULONG startIdx , ULONG startVertex ) {
UINT numInstances = 0 ;
int numInstancedAttribs = 0 , i , j ;
UINT instancedData [ sizeof ( sd - > u . input ) / sizeof ( sd - > u . input [ 0 ] ) /* 16 */ ] ;
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
IWineD3DStateBlockImpl * stateblock = This - > stateBlock ;
2007-02-19 15:25:32 +01:00
if ( idxSize = = 0 ) {
2007-02-14 17:56:29 +01:00
/* This is a nasty thing. MSDN says no hardware supports that and apps have to use software vertex processing.
* We don ' t support this for now
*
* Shouldn ' t be too hard to support with opengl , in theory just call glDrawArrays instead of drawElements .
* But the StreamSourceFreq value has a different meaning in that situation .
*/
FIXME ( " Non-indexed instanced drawing is not supported \n " ) ;
return ;
}
TRACE ( " (%p) : glElements(%x, %d, %d, ...) \n " , This , glPrimitiveType , numberOfVertices , minIndex ) ;
idxData = idxData = = ( void * ) - 1 ? NULL : idxData ;
/* First, figure out how many instances we have to draw */
for ( i = 0 ; i < MAX_STREAMS ; i + + ) {
2008-04-06 18:50:52 +02:00
/* Look at the streams and take the first one which matches */
if ( ( ( stateblock - > streamFlags [ i ] & WINED3DSTREAMSOURCE_INSTANCEDATA ) | | ( stateblock - > streamFlags [ i ] & WINED3DSTREAMSOURCE_INDEXEDDATA ) ) & & stateblock - > streamSource [ i ] ) {
2008-04-22 08:18:14 +02:00
/* D3D9 could set streamFreq 0 with (INSTANCEDATA or INDEXEDDATA) and then it is handled as 1. See d3d9/tests/visual.c-> stream_test() */
2008-04-06 18:50:52 +02:00
if ( stateblock - > streamFreq [ i ] = = 0 ) {
numInstances = 1 ;
} else {
numInstances = stateblock - > streamFreq [ i ] ; /* use the specified number of instances from the first matched stream. See d3d9/tests/visual.c-> stream_test() */
2007-02-14 17:56:29 +01:00
}
2008-04-22 08:18:14 +02:00
break ; /* break, because only the first suitable value is interesting */
2007-02-14 17:56:29 +01:00
}
}
for ( i = 0 ; i < sizeof ( sd - > u . input ) / sizeof ( sd - > u . input [ 0 ] ) ; i + + ) {
2007-02-14 23:30:16 +01:00
if ( stateblock - > streamFlags [ sd - > u . input [ i ] . streamNo ] & WINED3DSTREAMSOURCE_INSTANCEDATA ) {
2007-02-14 17:56:29 +01:00
instancedData [ numInstancedAttribs ] = i ;
numInstancedAttribs + + ;
}
}
/* now draw numInstances instances :-) */
for ( i = 0 ; i < numInstances ; i + + ) {
/* Specify the instanced attributes using immediate mode calls */
for ( j = 0 ; j < numInstancedAttribs ; j + + ) {
BYTE * ptr = sd - > u . input [ instancedData [ j ] ] . lpData +
sd - > u . input [ instancedData [ j ] ] . dwStride * i +
stateblock - > streamOffset [ sd - > u . input [ instancedData [ j ] ] . streamNo ] ;
if ( sd - > u . input [ instancedData [ j ] ] . VBO ) {
IWineD3DVertexBufferImpl * vb = ( IWineD3DVertexBufferImpl * ) stateblock - > streamSource [ sd - > u . input [ instancedData [ j ] ] . streamNo ] ;
ptr + = ( long ) vb - > resource . allocatedMemory ;
}
2007-12-17 18:18:19 +01:00
send_attribute ( This , sd - > u . input [ instancedData [ j ] ] . dwType , instancedData [ j ] , ptr ) ;
2007-02-14 17:56:29 +01:00
}
glDrawElements ( glPrimitiveType , numberOfVertices , idxSize = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ,
( const char * ) idxData + ( idxSize * startIdx ) ) ;
checkGLcall ( " glDrawElements " ) ;
}
}
2007-08-23 17:35:10 +02:00
static inline void remove_vbos ( IWineD3DDeviceImpl * This , WineDirect3DVertexStridedData * s ) {
unsigned char i ;
IWineD3DVertexBufferImpl * vb ;
if ( s - > u . s . position . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . position . streamNo ] ;
s - > u . s . position . VBO = 0 ;
s - > u . s . position . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . position . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . blendWeights . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . blendWeights . streamNo ] ;
s - > u . s . blendWeights . VBO = 0 ;
s - > u . s . blendWeights . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . blendWeights . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . blendMatrixIndices . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . blendMatrixIndices . streamNo ] ;
s - > u . s . blendMatrixIndices . VBO = 0 ;
s - > u . s . blendMatrixIndices . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . blendMatrixIndices . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . normal . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . normal . streamNo ] ;
s - > u . s . normal . VBO = 0 ;
s - > u . s . normal . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . normal . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . pSize . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . pSize . streamNo ] ;
s - > u . s . pSize . VBO = 0 ;
s - > u . s . pSize . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . pSize . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . diffuse . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . diffuse . streamNo ] ;
s - > u . s . diffuse . VBO = 0 ;
s - > u . s . diffuse . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . diffuse . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . specular . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . specular . streamNo ] ;
s - > u . s . specular . VBO = 0 ;
s - > u . s . specular . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . specular . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
for ( i = 0 ; i < WINED3DDP_MAXTEXCOORD ; i + + ) {
if ( s - > u . s . texCoords [ i ] . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . texCoords [ i ] . streamNo ] ;
s - > u . s . texCoords [ i ] . VBO = 0 ;
s - > u . s . texCoords [ i ] . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . texCoords [ i ] . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
}
if ( s - > u . s . position2 . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . position2 . streamNo ] ;
s - > u . s . position2 . VBO = 0 ;
s - > u . s . position2 . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . position2 . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . normal2 . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . normal2 . streamNo ] ;
s - > u . s . normal2 . VBO = 0 ;
s - > u . s . normal2 . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . normal2 . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . tangent . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . tangent . streamNo ] ;
s - > u . s . tangent . VBO = 0 ;
s - > u . s . tangent . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . tangent . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . binormal . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . binormal . streamNo ] ;
s - > u . s . binormal . VBO = 0 ;
s - > u . s . binormal . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . binormal . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . tessFactor . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . tessFactor . streamNo ] ;
s - > u . s . tessFactor . VBO = 0 ;
s - > u . s . tessFactor . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . tessFactor . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . fog . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . fog . streamNo ] ;
s - > u . s . fog . VBO = 0 ;
s - > u . s . fog . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . fog . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . depth . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . depth . streamNo ] ;
s - > u . s . depth . VBO = 0 ;
s - > u . s . depth . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . depth . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
if ( s - > u . s . sample . VBO ) {
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ s - > u . s . sample . streamNo ] ;
s - > u . s . sample . VBO = 0 ;
s - > u . s . sample . lpData = ( BYTE * ) ( ( unsigned long ) s - > u . s . sample . lpData + ( unsigned long ) vb - > resource . allocatedMemory ) ;
}
}
2004-12-09 12:42:34 +01:00
/* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive ( IWineD3DDevice * iface ,
2006-05-06 16:58:57 +02:00
int PrimitiveType ,
long NumPrimitives ,
/* for Indexed: */
long StartVertexIndex ,
UINT numberOfVertices ,
long StartIdx ,
short idxSize ,
const void * idxData ,
2007-01-02 21:13:28 +01:00
int minIndex ) {
2004-12-09 12:42:34 +01:00
2005-01-17 14:44:57 +01:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2007-03-06 21:47:45 +01:00
IWineD3DSwapChain * swapchain ;
IWineD3DBaseTexture * texture = NULL ;
IWineD3DSurfaceImpl * target ;
2007-02-12 19:18:36 +01:00
int i ;
2004-12-09 12:42:34 +01:00
2008-03-23 13:53:45 +01:00
if ( NumPrimitives = = 0 ) return ;
2006-06-04 16:42:57 +02:00
/* Invalidate the back buffer memory so LockRect will read it the next time */
2007-02-13 20:21:32 +01:00
for ( i = 0 ; i < GL_LIMITS ( buffers ) ; i + + ) {
2007-03-06 21:47:45 +01:00
target = ( IWineD3DSurfaceImpl * ) This - > render_targets [ i ] ;
2007-03-10 00:55:08 +01:00
2007-03-06 21:47:45 +01:00
/* TODO: Only do all that if we're going to change anything
* Texture container dirtification does not work quite right yet
*/
if ( target /*&& target->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)*/ ) {
swapchain = NULL ;
texture = NULL ;
if ( i = = 0 ) {
IWineD3DSurface_GetContainer ( ( IWineD3DSurface * ) target , & IID_IWineD3DSwapChain , ( void * * ) & swapchain ) ;
2007-03-10 00:55:08 +01:00
/* Need the surface in the drawable! */
2007-11-01 01:38:50 +01:00
IWineD3DSurface_LoadLocation ( ( IWineD3DSurface * ) target , SFLAG_INDRAWABLE , NULL ) ;
2007-03-10 00:55:08 +01:00
2007-10-09 22:17:59 +02:00
/* TODO: Move fbo logic to ModifyLocation */
IWineD3DSurface_ModifyLocation ( ( IWineD3DSurface * ) target , SFLAG_INDRAWABLE , TRUE ) ;
2007-03-06 21:47:45 +01:00
if ( swapchain ) {
/* Onscreen target. Invalidate system memory copy and texture copy */
IWineD3DSwapChain_Release ( swapchain ) ;
} else if ( wined3d_settings . offscreen_rendering_mode ! = ORM_FBO ) {
/* Non-FBO target: Invalidate system copy, texture copy and dirtify the container */
2007-10-09 22:17:59 +02:00
/* TODO: Move container dirtification to ModifyLocation */
2007-03-06 21:47:45 +01:00
IWineD3DSurface_GetContainer ( ( IWineD3DSurface * ) target , & IID_IWineD3DBaseTexture , ( void * * ) & texture ) ;
if ( texture ) {
IWineD3DBaseTexture_SetDirty ( texture , TRUE ) ;
IWineD3DTexture_Release ( texture ) ;
}
} else {
2007-10-09 22:17:59 +02:00
/* FBO offscreen target. Texture == Drawable */
target - > Flags | = SFLAG_INTEXTURE ;
2007-03-06 21:47:45 +01:00
}
} else {
/* Must be an fbo render target */
2007-10-09 22:17:59 +02:00
IWineD3DSurface_ModifyLocation ( ( IWineD3DSurface * ) target , SFLAG_INDRAWABLE , TRUE ) ;
2007-03-06 21:47:45 +01:00
target - > Flags | = SFLAG_INTEXTURE ;
}
2006-06-04 16:42:57 +02:00
}
}
2008-04-07 23:42:39 +02:00
/* Signals other modules that a drawing is in progress and the stateblock finalized */
This - > isInDraw = TRUE ;
2004-12-09 12:42:34 +01:00
/* Ok, we will be updating the screen from here onwards so grab the lock */
2007-04-09 01:53:27 +02:00
if ( wined3d_settings . offscreen_rendering_mode = = ORM_FBO ) {
2007-08-06 16:27:08 +02:00
ENTER_GL ( ) ;
2007-04-09 01:53:27 +02:00
apply_fbo_state ( iface ) ;
2007-08-06 16:27:08 +02:00
LEAVE_GL ( ) ;
2006-12-25 17:12:45 +01:00
}
2007-04-09 01:53:27 +02:00
ActivateContext ( This , This - > render_targets [ 0 ] , CTXUSAGE_DRAWPRIM ) ;
2007-08-06 16:27:08 +02:00
ENTER_GL ( ) ;
2007-04-09 01:53:27 +02:00
2008-07-02 23:00:41 +02:00
if ( This - > stencilBufferTarget ) {
DWORD location = This - > render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN ;
surface_load_ds_location ( This - > stencilBufferTarget , location ) ;
surface_modify_ds_location ( This - > stencilBufferTarget , location ) ;
2006-12-25 17:12:45 +01:00
}
2005-08-19 12:05:00 +02:00
{
GLenum glPrimType ;
2007-06-20 14:36:32 +02:00
BOOL emulation = FALSE ;
WineDirect3DVertexStridedData * strided = & This - > strided_streams ;
WineDirect3DVertexStridedData stridedlcl ;
2005-08-19 12:05:00 +02:00
/* Ok, Work out which primitive is requested and how many vertexes that
will be */
UINT calculatedNumberOfindices = primitiveToGl ( PrimitiveType , NumPrimitives , & glPrimType ) ;
if ( numberOfVertices = = 0 )
numberOfVertices = calculatedNumberOfindices ;
2006-07-04 11:08:39 +02:00
2007-08-14 02:31:10 +02:00
if ( ! use_vs ( This ) ) {
if ( ! This - > strided_streams . u . s . position_transformed & & This - > activeContext - > num_untracked_materials & &
This - > stateBlock - > renderState [ WINED3DRS_LIGHTING ] ) {
2008-04-18 23:42:03 +02:00
static BOOL first = TRUE ;
if ( first ) {
FIXME ( " Using software emulation because not all material properties could be tracked \n " ) ;
first = FALSE ;
} else {
TRACE ( " Using software emulation because not all material properties could be tracked \n " ) ;
}
2007-06-20 14:36:32 +02:00
emulation = TRUE ;
2007-08-14 02:31:10 +02:00
}
else if ( This - > activeContext - > fog_coord & & This - > stateBlock - > renderState [ WINED3DRS_FOGENABLE ] ) {
/* Either write a pipeline replacement shader or convert the specular alpha from unsigned byte
* to a float in the vertex buffer
*/
2008-04-18 23:42:03 +02:00
static BOOL first = TRUE ;
if ( first ) {
FIXME ( " Using software emulation because manual fog coordinates are provided \n " ) ;
first = FALSE ;
} else {
TRACE ( " Using software emulation because manual fog coordinates are provided \n " ) ;
}
2007-08-14 02:31:10 +02:00
emulation = TRUE ;
}
if ( emulation ) {
2007-06-20 14:36:32 +02:00
strided = & stridedlcl ;
memcpy ( & stridedlcl , & This - > strided_streams , sizeof ( stridedlcl ) ) ;
2007-08-23 17:35:10 +02:00
remove_vbos ( This , & stridedlcl ) ;
2007-06-20 14:36:32 +02:00
}
}
if ( This - > useDrawStridedSlow | | emulation ) {
2007-02-14 17:56:29 +01:00
/* Immediate mode drawing */
2007-12-19 17:18:39 +01:00
if ( use_vs ( This ) ) {
2008-04-18 23:42:03 +02:00
static BOOL first = TRUE ;
if ( first ) {
FIXME ( " Using immediate mode with vertex shaders for half float emulation \n " ) ;
first = FALSE ;
} else {
TRACE ( " Using immediate mode with vertex shaders for half float emulation \n " ) ;
}
2007-12-19 17:18:39 +01:00
drawStridedSlowVs ( iface , strided , calculatedNumberOfindices , glPrimType ,
idxData , idxSize , minIndex , StartIdx , StartVertexIndex ) ;
} else {
drawStridedSlow ( iface , strided , calculatedNumberOfindices ,
glPrimType , idxData , idxSize , minIndex , StartIdx , StartVertexIndex ) ;
}
2007-02-14 17:56:29 +01:00
} else if ( This - > instancedDraw ) {
/* Instancing emulation with mixing immediate mode and arrays */
drawStridedInstanced ( iface , & This - > strided_streams , calculatedNumberOfindices , glPrimType ,
idxData , idxSize , minIndex , StartIdx , StartVertexIndex ) ;
2007-12-19 17:18:39 +01:00
} else {
2007-01-06 18:28:42 +01:00
drawStridedFast ( iface , calculatedNumberOfindices , glPrimType ,
idxData , idxSize , minIndex , StartIdx , StartVertexIndex ) ;
2007-02-14 17:56:29 +01:00
}
2004-12-09 12:42:34 +01:00
}
2008-01-09 20:37:05 +01:00
/* Finished updating the screen, restore lock */
2004-12-09 12:42:34 +01:00
LEAVE_GL ( ) ;
TRACE ( " Done all gl drawing \n " ) ;
/* Diagnostics */
2005-09-27 12:49:59 +02:00
# ifdef SHOW_FRAME_MAKEUP
2004-12-09 12:42:34 +01:00
{
2005-09-27 12:49:59 +02:00
static long int primCounter = 0 ;
/* NOTE: set primCounter to the value reported by drawprim
before you want to to write frame makeup to / tmp */
if ( primCounter > = 0 ) {
2006-04-06 19:36:02 +02:00
WINED3DLOCKED_RECT r ;
2004-12-09 12:42:34 +01:00
char buffer [ 80 ] ;
2006-03-08 00:11:28 +01:00
IWineD3DSurface_LockRect ( This - > renderTarget , & r , NULL , WINED3DLOCK_READONLY ) ;
2006-10-01 05:20:10 +02:00
sprintf ( buffer , " /tmp/backbuffer_%d.tga " , primCounter ) ;
2004-12-09 12:42:34 +01:00
TRACE ( " Saving screenshot %s \n " , buffer ) ;
2005-07-30 21:06:14 +02:00
IWineD3DSurface_SaveSnapshot ( This - > renderTarget , buffer ) ;
IWineD3DSurface_UnlockRect ( This - > renderTarget ) ;
2004-12-09 12:42:34 +01:00
2005-09-27 12:49:59 +02:00
# ifdef SHOW_TEXTURE_MAKEUP
2004-12-09 12:42:34 +01:00
{
2005-07-30 21:06:14 +02:00
IWineD3DSurface * pSur ;
2004-12-09 12:42:34 +01:00
int textureNo ;
2007-06-25 22:45:40 +02:00
for ( textureNo = 0 ; textureNo < MAX_COMBINED_SAMPLERS ; + + textureNo ) {
2004-12-09 12:42:34 +01:00
if ( This - > stateBlock - > textures [ textureNo ] ! = NULL ) {
2006-10-01 05:20:10 +02:00
sprintf ( buffer , " /tmp/texture_%p_%d_%d.tga " , This - > stateBlock - > textures [ textureNo ] , primCounter , textureNo ) ;
2005-07-30 21:06:14 +02:00
TRACE ( " Saving texture %s \n " , buffer ) ;
2006-03-09 23:21:16 +01:00
if ( IWineD3DBaseTexture_GetType ( This - > stateBlock - > textures [ textureNo ] ) = = WINED3DRTYPE_TEXTURE ) {
2005-09-27 12:49:59 +02:00
IWineD3DTexture_GetSurfaceLevel ( ( IWineD3DTexture * ) This - > stateBlock - > textures [ textureNo ] , 0 , & pSur ) ;
IWineD3DSurface_SaveSnapshot ( pSur , buffer ) ;
IWineD3DSurface_Release ( pSur ) ;
} else {
FIXME ( " base Texture isn't of type texture %d \n " , IWineD3DBaseTexture_GetType ( This - > stateBlock - > textures [ textureNo ] ) ) ;
}
2004-12-09 12:42:34 +01:00
}
}
}
# endif
}
2006-10-01 05:20:10 +02:00
TRACE ( " drawprim #%d \n " , primCounter ) ;
2005-09-27 12:49:59 +02:00
+ + primCounter ;
2004-12-09 12:42:34 +01:00
}
# endif
2007-01-06 18:41:43 +01:00
/* Control goes back to the device, stateblock values may change again */
This - > isInDraw = FALSE ;
2004-12-09 12:42:34 +01:00
}
2007-07-04 17:57:45 +02:00
static void normalize_normal ( float * n ) {
float length = n [ 0 ] * n [ 0 ] + n [ 1 ] * n [ 1 ] + n [ 2 ] * n [ 2 ] ;
if ( length = = 0.0 ) return ;
length = sqrt ( length ) ;
n [ 0 ] = n [ 0 ] / length ;
n [ 1 ] = n [ 1 ] / length ;
n [ 2 ] = n [ 2 ] / length ;
}
/* Tesselates a high order rectangular patch into single triangles using gl evaluators
*
* The problem is that OpenGL does not offer a direct way to return the tesselated primitives ,
* and they can ' t be sent off for rendering directly either . Tesselating is slow , so we want
2008-01-09 20:37:05 +01:00
* to cache the patches in a vertex buffer . But more importantly , gl can ' t bind generated
2007-07-04 17:57:45 +02:00
* attributes to numbered shader attributes , so we have to store them and rebind them as needed
* in drawprim .
*
* To read back , the opengl feedback mode is used . This creates a proplem because we want
* untransformed , unlit vertices , but feedback runs everything through transform and lighting .
* Thus disable lighting and set identity matrices to get unmodified colors and positions .
* To overcome clipping find the biggest x , y and z values of the vertices in the patch and scale
* them to [ - 1.0 ; + 1.0 ] and set the viewport up to scale them back .
*
* Normals are more tricky : Draw white vertices with 3 directional lights , and calculate the
* resulting colors back to the normals .
*
* NOTE : This function activates a context for blitting , modifies matrices & viewport , but
* does not restore it because normally a draw follows immediately afterwards . The caller is
* responsible of taking care that either the gl states are restored , or the context activated
* for drawing to reset the lastWasBlit flag .
*/
HRESULT tesselate_rectpatch ( IWineD3DDeviceImpl * This ,
struct WineD3DRectPatch * patch ) {
unsigned int i , j , num_quads , out_vertex_size , buffer_size , d3d_out_vertex_size ;
float max_x = 0.0 , max_y = 0.0 , max_z = 0.0 , neg_z = 0.0 ;
WineDirect3DVertexStridedData strided ;
BYTE * data ;
WINED3DRECTPATCH_INFO * info = & patch - > RectPatchInfo ;
DWORD vtxStride ;
GLenum feedback_type ;
GLfloat * feedbuffer ;
/* First, locate the position data. This is provided in a vertex buffer in the stateblock.
* Beware of vbos
*/
memset ( & strided , 0 , sizeof ( strided ) ) ;
primitiveDeclarationConvertToStridedData ( ( IWineD3DDevice * ) This , FALSE , & strided , NULL ) ;
if ( strided . u . s . position . VBO ) {
IWineD3DVertexBufferImpl * vb ;
vb = ( IWineD3DVertexBufferImpl * ) This - > stateBlock - > streamSource [ strided . u . s . position . streamNo ] ;
strided . u . s . position . lpData = ( BYTE * ) ( ( unsigned long ) strided . u . s . position . lpData +
( unsigned long ) vb - > resource . allocatedMemory ) ;
}
vtxStride = strided . u . s . position . dwStride ;
data = strided . u . s . position . lpData +
vtxStride * info - > Stride * info - > StartVertexOffsetHeight +
vtxStride * info - > StartVertexOffsetWidth ;
/* Not entirely sure about what happens with transformed vertices */
if ( strided . u . s . position_transformed ) {
FIXME ( " Transformed position in rectpatch generation \n " ) ;
}
if ( vtxStride % sizeof ( GLfloat ) ) {
/* glMap2f reads vertex sizes in GLfloats, the d3d stride is in bytes.
* I don ' t see how the stride could not be a multiple of 4 , but make sure
* to check it
*/
ERR ( " Vertex stride is not a multiple of sizeof(GLfloat) \n " ) ;
}
if ( info - > Basis ! = WINED3DBASIS_BEZIER ) {
FIXME ( " Basis is %s, how to handle this? \n " , debug_d3dbasis ( info - > Basis ) ) ;
}
if ( info - > Degree ! = WINED3DDEGREE_CUBIC ) {
FIXME ( " Degree is %s, how to handle this? \n " , debug_d3ddegree ( info - > Degree ) ) ;
}
/* First, get the boundary cube of the input data */
for ( j = 0 ; j < info - > Height ; j + + ) {
for ( i = 0 ; i < info - > Width ; i + + ) {
float * v = ( float * ) ( data + vtxStride * i + vtxStride * info - > Stride * j ) ;
if ( fabs ( v [ 0 ] ) > max_x ) max_x = fabs ( v [ 0 ] ) ;
if ( fabs ( v [ 1 ] ) > max_y ) max_y = fabs ( v [ 1 ] ) ;
if ( fabs ( v [ 2 ] ) > max_z ) max_z = fabs ( v [ 2 ] ) ;
if ( v [ 2 ] < neg_z ) neg_z = v [ 2 ] ;
}
}
/* This needs some improvements in the vertex decl code */
FIXME ( " Cannot find data to generate. Only generating position and normals \n " ) ;
patch - > has_normals = TRUE ;
patch - > has_texcoords = FALSE ;
/* Simply activate the context for blitting. This disables all the things we don't want and
2007-07-31 18:57:34 +02:00
* takes care of dirtifying . Dirtifying is preferred over pushing / popping , since drawing the
* patch ( as opposed to normal draws ) will most likely need different changes anyway
2007-07-04 17:57:45 +02:00
*/
ActivateContext ( This , This - > lastActiveRenderTarget , CTXUSAGE_BLIT ) ;
2007-08-06 16:27:08 +02:00
ENTER_GL ( ) ;
2007-07-04 17:57:45 +02:00
glMatrixMode ( GL_PROJECTION ) ;
checkGLcall ( " glMatrixMode(GL_PROJECTION) " ) ;
glLoadIdentity ( ) ;
checkGLcall ( " glLoadIndentity() " ) ;
glScalef ( 1 / ( max_x ) , 1 / ( max_y ) , max_z = = 0 ? 1 : 1 / ( 2 * max_z ) ) ;
glTranslatef ( 0 , 0 , 0.5 ) ;
checkGLcall ( " glScalef " ) ;
glViewport ( - max_x , - max_y , 2 * ( max_x ) , 2 * ( max_y ) ) ;
checkGLcall ( " glViewport " ) ;
/* Some states to take care of. If we're in wireframe opengl will produce lines, and confuse
* our feedback buffer parser
*/
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
checkGLcall ( " glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_RENDER ( WINED3DRS_FILLMODE ) ) ;
if ( patch - > has_normals ) {
float black [ 4 ] = { 0 , 0 , 0 , 0 } ;
float red [ 4 ] = { 1 , 0 , 0 , 0 } ;
float green [ 4 ] = { 0 , 1 , 0 , 0 } ;
float blue [ 4 ] = { 0 , 0 , 1 , 0 } ;
float white [ 4 ] = { 1 , 1 , 1 , 1 } ;
glEnable ( GL_LIGHTING ) ;
checkGLcall ( " glEnable(GL_LIGHTING) " ) ;
glLightModelfv ( GL_LIGHT_MODEL_AMBIENT , black ) ;
checkGLcall ( " glLightModel for MODEL_AMBIENT " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_RENDER ( WINED3DRS_AMBIENT ) ) ;
for ( i = 3 ; i < GL_LIMITS ( lights ) ; i + + ) {
glDisable ( GL_LIGHT0 + i ) ;
checkGLcall ( " glDisable(GL_LIGHT0 + i) " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_ACTIVELIGHT ( i ) ) ;
}
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_ACTIVELIGHT ( 0 ) ) ;
glLightfv ( GL_LIGHT0 , GL_DIFFUSE , red ) ;
glLightfv ( GL_LIGHT0 , GL_SPECULAR , black ) ;
glLightfv ( GL_LIGHT0 , GL_AMBIENT , black ) ;
glLightfv ( GL_LIGHT0 , GL_POSITION , red ) ;
glEnable ( GL_LIGHT0 ) ;
checkGLcall ( " Setting up light 1 \n " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_ACTIVELIGHT ( 1 ) ) ;
glLightfv ( GL_LIGHT1 , GL_DIFFUSE , green ) ;
glLightfv ( GL_LIGHT1 , GL_SPECULAR , black ) ;
glLightfv ( GL_LIGHT1 , GL_AMBIENT , black ) ;
glLightfv ( GL_LIGHT1 , GL_POSITION , green ) ;
glEnable ( GL_LIGHT1 ) ;
checkGLcall ( " Setting up light 2 \n " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_ACTIVELIGHT ( 2 ) ) ;
glLightfv ( GL_LIGHT2 , GL_DIFFUSE , blue ) ;
glLightfv ( GL_LIGHT2 , GL_SPECULAR , black ) ;
glLightfv ( GL_LIGHT2 , GL_AMBIENT , black ) ;
glLightfv ( GL_LIGHT2 , GL_POSITION , blue ) ;
glEnable ( GL_LIGHT2 ) ;
checkGLcall ( " Setting up light 3 \n " ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_MATERIAL ) ;
IWineD3DDeviceImpl_MarkStateDirty ( This , STATE_RENDER ( WINED3DRS_COLORVERTEX ) ) ;
glDisable ( GL_COLOR_MATERIAL ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_EMISSION , black ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_SPECULAR , black ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_DIFFUSE , white ) ;
checkGLcall ( " Setting up materials \n " ) ;
}
/* Enable the needed maps.
* GL_MAP2_VERTEX_3 is needed for positional data .
* GL_AUTO_NORMAL to generate normals from the position . Do not use GL_MAP2_NORMAL .
* GL_MAP2_TEXTURE_COORD_4 for texture coords
*/
num_quads = ceilf ( patch - > numSegs [ 0 ] ) * ceilf ( patch - > numSegs [ 1 ] ) ;
out_vertex_size = 3 /* position */ ;
d3d_out_vertex_size = 3 ;
glEnable ( GL_MAP2_VERTEX_3 ) ;
if ( patch - > has_normals & & patch - > has_texcoords ) {
FIXME ( " Texcoords not handled yet \n " ) ;
feedback_type = GL_3D_COLOR_TEXTURE ;
out_vertex_size + = 8 ;
d3d_out_vertex_size + = 7 ;
glEnable ( GL_AUTO_NORMAL ) ;
glEnable ( GL_MAP2_TEXTURE_COORD_4 ) ;
} else if ( patch - > has_texcoords ) {
FIXME ( " Texcoords not handled yet \n " ) ;
feedback_type = GL_3D_COLOR_TEXTURE ;
out_vertex_size + = 7 ;
d3d_out_vertex_size + = 4 ;
glEnable ( GL_MAP2_TEXTURE_COORD_4 ) ;
} else if ( patch - > has_normals ) {
feedback_type = GL_3D_COLOR ;
out_vertex_size + = 4 ;
d3d_out_vertex_size + = 3 ;
glEnable ( GL_AUTO_NORMAL ) ;
} else {
feedback_type = GL_3D ;
}
checkGLcall ( " glEnable vertex attrib generation " ) ;
buffer_size = num_quads * out_vertex_size * 2 /* triangle list */ * 3 /* verts per tri */
+ 4 * num_quads /* 2 triangle markers per quad + num verts in tri */ ;
feedbuffer = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , buffer_size * sizeof ( float ) * 8 ) ;
glMap2f ( GL_MAP2_VERTEX_3 ,
0 , 1 , vtxStride / sizeof ( float ) , info - > Width ,
0 , 1 , info - > Stride * vtxStride / sizeof ( float ) , info - > Height ,
( float * ) data ) ;
checkGLcall ( " glMap2f " ) ;
if ( patch - > has_texcoords ) {
glMap2f ( GL_MAP2_TEXTURE_COORD_4 ,
0 , 1 , vtxStride / sizeof ( float ) , info - > Width ,
0 , 1 , info - > Stride * vtxStride / sizeof ( float ) , info - > Height ,
( float * ) data ) ;
checkGLcall ( " glMap2f " ) ;
}
glMapGrid2f ( ceilf ( patch - > numSegs [ 0 ] ) , 0.0 , 1.0 , ceilf ( patch - > numSegs [ 1 ] ) , 0.0 , 1.0 ) ;
checkGLcall ( " glMapGrid2f " ) ;
glFeedbackBuffer ( buffer_size * 2 , feedback_type , feedbuffer ) ;
checkGLcall ( " glFeedbackBuffer " ) ;
glRenderMode ( GL_FEEDBACK ) ;
glEvalMesh2 ( GL_FILL , 0 , ceilf ( patch - > numSegs [ 0 ] ) , 0 , ceilf ( patch - > numSegs [ 1 ] ) ) ;
checkGLcall ( " glEvalMesh2 \n " ) ;
i = glRenderMode ( GL_RENDER ) ;
if ( i = = - 1 ) {
2008-04-06 23:06:04 +02:00
LEAVE_GL ( ) ;
2007-07-04 17:57:45 +02:00
ERR ( " Feedback failed. Expected %d elements back \n " , buffer_size ) ;
Sleep ( 10000 ) ;
HeapFree ( GetProcessHeap ( ) , 0 , feedbuffer ) ;
return WINED3DERR_DRIVERINTERNALERROR ;
} else if ( i ! = buffer_size ) {
2008-04-06 23:06:04 +02:00
LEAVE_GL ( ) ;
2007-07-04 17:57:45 +02:00
ERR ( " Unexpected amount of elements returned. Expected %d, got %d \n " , buffer_size , i ) ;
Sleep ( 10000 ) ;
HeapFree ( GetProcessHeap ( ) , 0 , feedbuffer ) ;
return WINED3DERR_DRIVERINTERNALERROR ;
} else {
TRACE ( " Got %d elements as expected \n " , i ) ;
}
HeapFree ( GetProcessHeap ( ) , 0 , patch - > mem ) ;
patch - > mem = HeapAlloc ( GetProcessHeap ( ) , HEAP_ZERO_MEMORY , num_quads * 6 * d3d_out_vertex_size * sizeof ( float ) * 8 ) ;
i = 0 ;
for ( j = 0 ; j < buffer_size ; j + = ( 3 /* num verts */ * out_vertex_size + 2 /* tri marker */ ) ) {
if ( feedbuffer [ j ] ! = GL_POLYGON_TOKEN ) {
ERR ( " Unexpected token: %f \n " , feedbuffer [ j ] ) ;
continue ;
}
if ( feedbuffer [ j + 1 ] ! = 3 ) {
ERR ( " Unexpected polygon: %f corners \n " , feedbuffer [ j + 1 ] ) ;
continue ;
}
/* Somehow there are different ideas about back / front facing, so fix up the
* vertex order
*/
patch - > mem [ i + 0 ] = feedbuffer [ j + out_vertex_size * 2 + 2 ] ; /* x, triangle 2 */
patch - > mem [ i + 1 ] = feedbuffer [ j + out_vertex_size * 2 + 3 ] ; /* y, triangle 2 */
patch - > mem [ i + 2 ] = ( feedbuffer [ j + out_vertex_size * 2 + 4 ] - 0.5 ) * 4 * max_z ; /* z, triangle 3 */
if ( patch - > has_normals ) {
patch - > mem [ i + 3 ] = feedbuffer [ j + out_vertex_size * 2 + 5 ] ;
patch - > mem [ i + 4 ] = feedbuffer [ j + out_vertex_size * 2 + 6 ] ;
patch - > mem [ i + 5 ] = feedbuffer [ j + out_vertex_size * 2 + 7 ] ;
}
i + = d3d_out_vertex_size ;
patch - > mem [ i + 0 ] = feedbuffer [ j + out_vertex_size * 1 + 2 ] ; /* x, triangle 2 */
patch - > mem [ i + 1 ] = feedbuffer [ j + out_vertex_size * 1 + 3 ] ; /* y, triangle 2 */
patch - > mem [ i + 2 ] = ( feedbuffer [ j + out_vertex_size * 1 + 4 ] - 0.5 ) * 4 * max_z ; /* z, triangle 2 */
if ( patch - > has_normals ) {
patch - > mem [ i + 3 ] = feedbuffer [ j + out_vertex_size * 1 + 5 ] ;
patch - > mem [ i + 4 ] = feedbuffer [ j + out_vertex_size * 1 + 6 ] ;
patch - > mem [ i + 5 ] = feedbuffer [ j + out_vertex_size * 1 + 7 ] ;
}
i + = d3d_out_vertex_size ;
patch - > mem [ i + 0 ] = feedbuffer [ j + out_vertex_size * 0 + 2 ] ; /* x, triangle 1 */
patch - > mem [ i + 1 ] = feedbuffer [ j + out_vertex_size * 0 + 3 ] ; /* y, triangle 1 */
patch - > mem [ i + 2 ] = ( feedbuffer [ j + out_vertex_size * 0 + 4 ] - 0.5 ) * 4 * max_z ; /* z, triangle 1 */
if ( patch - > has_normals ) {
patch - > mem [ i + 3 ] = feedbuffer [ j + out_vertex_size * 0 + 5 ] ;
patch - > mem [ i + 4 ] = feedbuffer [ j + out_vertex_size * 0 + 6 ] ;
patch - > mem [ i + 5 ] = feedbuffer [ j + out_vertex_size * 0 + 7 ] ;
}
i + = d3d_out_vertex_size ;
}
if ( patch - > has_normals ) {
/* Now do the same with reverse light directions */
float x [ 4 ] = { - 1 , 0 , 0 , 0 } ;
float y [ 4 ] = { 0 , - 1 , 0 , 0 } ;
float z [ 4 ] = { 0 , 0 , - 1 , 0 } ;
glLightfv ( GL_LIGHT0 , GL_POSITION , x ) ;
glLightfv ( GL_LIGHT1 , GL_POSITION , y ) ;
glLightfv ( GL_LIGHT2 , GL_POSITION , z ) ;
checkGLcall ( " Setting up reverse light directions \n " ) ;
glRenderMode ( GL_FEEDBACK ) ;
checkGLcall ( " glRenderMode(GL_FEEDBACK) " ) ;
glEvalMesh2 ( GL_FILL , 0 , ceilf ( patch - > numSegs [ 0 ] ) , 0 , ceilf ( patch - > numSegs [ 1 ] ) ) ;
checkGLcall ( " glEvalMesh2 \n " ) ;
i = glRenderMode ( GL_RENDER ) ;
checkGLcall ( " glRenderMode(GL_RENDER) " ) ;
i = 0 ;
for ( j = 0 ; j < buffer_size ; j + = ( 3 /* num verts */ * out_vertex_size + 2 /* tri marker */ ) ) {
if ( feedbuffer [ j ] ! = GL_POLYGON_TOKEN ) {
ERR ( " Unexpected token: %f \n " , feedbuffer [ j ] ) ;
continue ;
}
if ( feedbuffer [ j + 1 ] ! = 3 ) {
ERR ( " Unexpected polygon: %f corners \n " , feedbuffer [ j + 1 ] ) ;
continue ;
}
if ( patch - > mem [ i + 3 ] = = 0.0 )
patch - > mem [ i + 3 ] = - feedbuffer [ j + out_vertex_size * 2 + 5 ] ;
if ( patch - > mem [ i + 4 ] = = 0.0 )
patch - > mem [ i + 4 ] = - feedbuffer [ j + out_vertex_size * 2 + 6 ] ;
if ( patch - > mem [ i + 5 ] = = 0.0 )
patch - > mem [ i + 5 ] = - feedbuffer [ j + out_vertex_size * 2 + 7 ] ;
normalize_normal ( patch - > mem + i + 3 ) ;
i + = d3d_out_vertex_size ;
if ( patch - > mem [ i + 3 ] = = 0.0 )
patch - > mem [ i + 3 ] = - feedbuffer [ j + out_vertex_size * 1 + 5 ] ;
if ( patch - > mem [ i + 4 ] = = 0.0 )
patch - > mem [ i + 4 ] = - feedbuffer [ j + out_vertex_size * 1 + 6 ] ;
if ( patch - > mem [ i + 5 ] = = 0.0 )
patch - > mem [ i + 5 ] = - feedbuffer [ j + out_vertex_size * 1 + 7 ] ;
normalize_normal ( patch - > mem + i + 3 ) ;
i + = d3d_out_vertex_size ;
if ( patch - > mem [ i + 3 ] = = 0.0 )
patch - > mem [ i + 3 ] = - feedbuffer [ j + out_vertex_size * 0 + 5 ] ;
if ( patch - > mem [ i + 4 ] = = 0.0 )
patch - > mem [ i + 4 ] = - feedbuffer [ j + out_vertex_size * 0 + 6 ] ;
if ( patch - > mem [ i + 5 ] = = 0.0 )
patch - > mem [ i + 5 ] = - feedbuffer [ j + out_vertex_size * 0 + 7 ] ;
normalize_normal ( patch - > mem + i + 3 ) ;
i + = d3d_out_vertex_size ;
}
}
glDisable ( GL_MAP2_VERTEX_3 ) ;
glDisable ( GL_AUTO_NORMAL ) ;
glDisable ( GL_MAP2_NORMAL ) ;
glDisable ( GL_MAP2_TEXTURE_COORD_4 ) ;
checkGLcall ( " glDisable vertex attrib generation " ) ;
LEAVE_GL ( ) ;
HeapFree ( GetProcessHeap ( ) , 0 , feedbuffer ) ;
vtxStride = 3 * sizeof ( float ) ;
if ( patch - > has_normals ) {
vtxStride + = 3 * sizeof ( float ) ;
}
if ( patch - > has_texcoords ) {
vtxStride + = 4 * sizeof ( float ) ;
}
memset ( & patch - > strided , 0 , sizeof ( & patch - > strided ) ) ;
patch - > strided . u . s . position . lpData = ( BYTE * ) patch - > mem ;
patch - > strided . u . s . position . dwStride = vtxStride ;
patch - > strided . u . s . position . dwType = WINED3DDECLTYPE_FLOAT3 ;
patch - > strided . u . s . position . streamNo = 255 ;
if ( patch - > has_normals ) {
patch - > strided . u . s . normal . lpData = ( BYTE * ) patch - > mem + 3 * sizeof ( float ) /* pos */ ;
patch - > strided . u . s . normal . dwStride = vtxStride ;
patch - > strided . u . s . normal . dwType = WINED3DDECLTYPE_FLOAT3 ;
patch - > strided . u . s . normal . streamNo = 255 ;
}
if ( patch - > has_texcoords ) {
patch - > strided . u . s . texCoords [ 0 ] . lpData = ( BYTE * ) patch - > mem + 3 * sizeof ( float ) /* pos */ ;
if ( patch - > has_normals ) {
patch - > strided . u . s . texCoords [ 0 ] . lpData + = 3 * sizeof ( float ) ;
}
patch - > strided . u . s . texCoords [ 0 ] . dwStride = vtxStride ;
patch - > strided . u . s . texCoords [ 0 ] . dwType = WINED3DDECLTYPE_FLOAT4 ;
/* MAX_STREAMS index points to an unused element in stateblock->streamOffsets which
* always remains set to 0. Windows uses stream 255 here , but this is not visible to the
* application .
*/
patch - > strided . u . s . texCoords [ 0 ] . streamNo = MAX_STREAMS ;
}
return WINED3D_OK ;
}