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
2008-08-21 18:23:32 +02:00
* Copyright 2006 , 2008 Henri Verbeet
2008-10-18 19:21:20 +02:00
* Copyright 2007 - 2008 Stefan Dö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
2009-05-14 19:40:56 +02:00
/* GL locking is done by the caller */
2009-01-08 10:19:16 +01:00
static void drawStridedFast ( IWineD3DDevice * iface , GLenum primitive_type ,
2009-03-05 12:30:42 +01:00
UINT min_vertex_idx , UINT max_vertex_idx , UINT count , UINT idx_size ,
2009-01-08 10:19:16 +01:00
const void * idx_data , UINT start_idx )
2009-01-07 09:00:55 +01:00
{
2005-08-19 12:05:00 +02:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2004-12-09 12:42:34 +01:00
2009-01-08 10:19:16 +01:00
if ( idx_size )
{
TRACE ( " (%p) : glElements(%x, %d, %d, ...) \n " , This , primitive_type , count , min_vertex_idx ) ;
2005-08-19 12:05:00 +02:00
# if 1
2009-01-08 10:19:16 +01:00
glDrawElements ( primitive_type , count ,
idx_size = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ,
( const char * ) idx_data + ( idx_size * start_idx ) ) ;
2007-08-10 16:01:12 +02:00
checkGLcall ( " glDrawElements " ) ;
2009-01-08 10:19:16 +01:00
# else
glDrawRangeElements ( primitive_type , min_vertex_idx , max_vertex_idx , count ,
idx_size = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT ,
( const char * ) idx_data + ( idx_size * start_idx ) ) ;
2004-12-09 12:42:34 +01:00
checkGLcall ( " glDrawRangeElements " ) ;
2007-08-10 16:01:12 +02:00
# endif
2009-01-08 10:19:16 +01:00
}
else
{
TRACE ( " (%p) : glDrawArrays(%#x, %d, %d) \n " , This , primitive_type , start_idx , count ) ;
2004-12-09 12:42:34 +01:00
2009-01-08 10:19:16 +01:00
glDrawArrays ( primitive_type , start_idx , count ) ;
2004-12-09 12:42:34 +01:00
checkGLcall ( " glDrawArrays " ) ;
}
}
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
2009-05-14 19:40:56 +02:00
/* GL locking is done by the caller */
2009-03-27 10:25:55 +01:00
static void drawStridedSlow ( IWineD3DDevice * iface , const struct wined3d_stream_info * si , UINT NumVertexes ,
2009-03-05 12:30:42 +01:00
GLenum glPrimType , const void * idxData , UINT idxSize , UINT minIndex , UINT startIdx )
2008-11-28 15:30:12 +01:00
{
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 ;
2009-03-05 12:30:42 +01:00
UINT vx_index ;
2004-12-09 12:42:34 +01:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2008-11-28 15:30:12 +01:00
const UINT * streamOffset = This - > stateBlock - > streamOffset ;
2009-01-07 09:00:55 +01:00
long SkipnStrides = startIdx + This - > stateBlock - > loadBaseVertexIndex ;
2008-12-30 14:56:49 +01:00
BOOL pixelShader = use_ps ( This - > stateBlock ) ;
2008-12-04 17:41:30 +01:00
BOOL specular_fog = FALSE ;
UINT texture_stages = GL_LIMITS ( texture_stages ) ;
2008-11-28 15:30:12 +01:00
const BYTE * texCoords [ WINED3DDP_MAXTEXCOORD ] ;
const BYTE * diffuse = NULL , * specular = NULL , * normal = NULL , * position = NULL ;
2009-03-27 10:25:55 +01:00
const struct wined3d_stream_info_element * element ;
2009-06-22 10:15:58 +02:00
UINT num_untracked_materials ;
2008-12-04 17:41:30 +01:00
DWORD tex_mask = 0 ;
2007-01-17 00:06:34 +01:00
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 ) {
2009-04-09 18:40:57 +02:00
idxData = buffer_get_sysmem ( ( struct wined3d_buffer * ) This - > stateBlock - > pIndexData ) ;
2007-02-19 15:25:32 +01:00
}
2009-01-20 10:00:20 +01:00
if ( idxSize = = 2 ) pIdxBufS = idxData ;
else pIdxBufL = idxData ;
2008-10-07 16:01:01 +02:00
} else if ( idxData ) {
ERR ( " non-NULL idxData with 0 idxSize, this should never happen \n " ) ;
return ;
2004-12-09 12:42:34 +01:00
}
2008-12-04 17:41:30 +01:00
/* Start drawing in GL */
VTRACE ( ( " glBegin(%x) \n " , glPrimType ) ) ;
glBegin ( glPrimType ) ;
2009-03-27 10:25:55 +01:00
element = & si - > elements [ WINED3D_FFP_POSITION ] ;
if ( element - > data ) position = element - > data + streamOffset [ element - > stream_idx ] ;
2008-12-04 17:41:30 +01:00
2009-03-27 10:25:55 +01:00
element = & si - > elements [ WINED3D_FFP_NORMAL ] ;
if ( element - > data ) normal = element - > data + streamOffset [ element - > stream_idx ] ;
2008-12-04 17:41:30 +01:00
else glNormal3f ( 0 , 0 , 0 ) ;
2009-03-27 10:25:55 +01:00
element = & si - > elements [ WINED3D_FFP_DIFFUSE ] ;
if ( element - > data ) diffuse = element - > data + streamOffset [ element - > stream_idx ] ;
2008-12-04 17:41:30 +01:00
else glColor4f ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
2009-06-22 10:15:58 +02:00
num_untracked_materials = This - > activeContext - > num_untracked_materials ;
if ( num_untracked_materials & & element - > format_desc - > format ! = WINED3DFMT_A8R8G8B8 )
2009-03-30 11:24:54 +02:00
FIXME ( " Implement diffuse color tracking from %s \n " , debug_d3dformat ( element - > format_desc - > format ) ) ;
2008-12-04 17:41:30 +01:00
2009-03-27 10:25:55 +01:00
element = & si - > elements [ WINED3D_FFP_SPECULAR ] ;
if ( element - > data )
2008-12-04 17:41:30 +01:00
{
2009-03-27 10:25:55 +01:00
specular = element - > data + streamOffset [ element - > stream_idx ] ;
2007-01-17 00:06:34 +01:00
2008-12-04 17:41:30 +01:00
/* special case where the fog density is stored in the specular alpha channel */
if ( This - > stateBlock - > renderState [ WINED3DRS_FOGENABLE ]
& & ( This - > stateBlock - > renderState [ WINED3DRS_FOGVERTEXMODE ] = = WINED3DFOG_NONE
2009-03-30 11:24:54 +02:00
| | si - > elements [ WINED3D_FFP_POSITION ] . format_desc - > format = = WINED3DFMT_R32G32B32A32_FLOAT )
2008-12-04 17:41:30 +01:00
& & This - > stateBlock - > renderState [ WINED3DRS_FOGTABLEMODE ] = = WINED3DFOG_NONE )
{
if ( GL_SUPPORT ( EXT_FOG_COORD ) )
{
2009-03-30 11:24:54 +02:00
if ( element - > format_desc - > format = = WINED3DFMT_A8R8G8B8 ) specular_fog = TRUE ;
else FIXME ( " Implement fog coordinates from %s \n " , debug_d3dformat ( element - > format_desc - > format ) ) ;
2008-12-04 17:41:30 +01:00
}
else
{
static BOOL warned ;
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
}
}
2008-12-04 17:41:30 +01:00
}
else if ( GL_SUPPORT ( EXT_SECONDARY_COLOR ) )
{
GL_EXTCALL ( glSecondaryColor3fEXT ) ( 0 , 0 , 0 ) ;
2007-12-19 17:10:02 +01:00
}
2008-12-04 17:41:30 +01:00
for ( textureNo = 0 ; textureNo < texture_stages ; + + textureNo )
{
int coordIdx = This - > stateBlock - > textureState [ textureNo ] [ WINED3DTSS_TEXCOORDINDEX ] ;
int texture_idx = This - > texUnitMap [ textureNo ] ;
2004-12-09 12:42:34 +01:00
2008-12-04 17:41:30 +01:00
if ( ! GL_SUPPORT ( ARB_MULTITEXTURE ) & & textureNo > 0 )
{
FIXME ( " Program using multiple concurrent textures which this opengl implementation doesn't support \n " ) ;
continue ;
}
if ( ! pixelShader & & ! This - > stateBlock - > textures [ textureNo ] ) continue ;
if ( texture_idx = = - 1 ) continue ;
if ( coordIdx > 7 )
{
TRACE ( " tex: %d - Skip tex coords, as being system generated \n " , textureNo ) ;
continue ;
}
else if ( coordIdx < 0 )
{
FIXME ( " tex: %d - Coord index %d is less than zero, expect a crash. \n " , textureNo , coordIdx ) ;
continue ;
}
2009-03-27 10:25:55 +01:00
element = & si - > elements [ WINED3D_FFP_TEXCOORD0 + coordIdx ] ;
if ( element - > data )
2008-12-04 17:41:30 +01:00
{
2009-03-27 10:25:55 +01:00
texCoords [ coordIdx ] = element - > data + streamOffset [ element - > stream_idx ] ;
2008-12-04 17:41:30 +01:00
tex_mask | = ( 1 < < textureNo ) ;
}
else
{
TRACE ( " tex: %d - Skipping tex coords, as no data supplied \n " , textureNo ) ;
if ( GL_SUPPORT ( ARB_MULTITEXTURE ) )
GL_EXTCALL ( glMultiTexCoord4fARB ( GL_TEXTURE0_ARB + texture_idx , 0 , 0 , 0 , 1 ) ) ;
else
glTexCoord4f ( 0 , 0 , 0 , 1 ) ;
2007-01-16 23:43:28 +01:00
}
}
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 ) {
2008-12-04 17:41:30 +01:00
UINT texture , tmp_tex_mask ;
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 ) {
2008-11-26 21:37:28 +01:00
VTRACE ( ( " Idx for vertex %u = %u \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 {
2008-11-26 21:37:28 +01:00
VTRACE ( ( " Idx for vertex %u = %u \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
}
}
2008-12-04 17:41:30 +01:00
tmp_tex_mask = tex_mask ;
for ( texture = 0 ; tmp_tex_mask ; tmp_tex_mask > > = 1 , + + texture )
{
int coord_idx ;
const void * ptr ;
2008-12-16 13:18:49 +01:00
int texture_idx ;
2004-12-09 12:42:34 +01:00
2008-12-04 17:41:30 +01:00
if ( ! ( tmp_tex_mask & 1 ) ) continue ;
2004-12-09 12:42:34 +01:00
2008-12-04 17:41:30 +01:00
coord_idx = This - > stateBlock - > textureState [ texture ] [ WINED3DTSS_TEXCOORDINDEX ] ;
2009-03-27 10:25:55 +01:00
ptr = texCoords [ coord_idx ] + ( SkipnStrides * si - > elements [ WINED3D_FFP_TEXCOORD0 + coord_idx ] . stride ) ;
2008-09-24 15:56:48 +02:00
2008-12-16 13:18:49 +01:00
texture_idx = This - > texUnitMap [ texture ] ;
2009-03-30 11:24:54 +02:00
multi_texcoord_funcs [ si - > elements [ WINED3D_FFP_TEXCOORD0 + coord_idx ] . format_desc - > emit_idx ] (
2009-03-27 10:25:55 +01:00
GL_TEXTURE0_ARB + texture_idx , ptr ) ;
2008-12-04 17:41:30 +01:00
}
2004-12-09 12:42:34 +01:00
/* Diffuse -------------------------------- */
2007-01-17 00:06:34 +01:00
if ( diffuse ) {
2009-03-27 10:25:55 +01:00
const void * ptrToCoords = diffuse + SkipnStrides * si - > elements [ WINED3D_FFP_DIFFUSE ] . stride ;
2007-06-20 14:36:32 +02:00
2009-03-30 11:24:54 +02:00
diffuse_funcs [ si - > elements [ WINED3D_FFP_DIFFUSE ] . format_desc - > emit_idx ] ( ptrToCoords ) ;
2009-06-22 10:15:58 +02:00
if ( num_untracked_materials )
{
2008-11-28 15:30:12 +01:00
DWORD diffuseColor = ( ( const DWORD * ) ptrToCoords ) [ 0 ] ;
2007-06-20 14:36:32 +02:00
unsigned char i ;
float color [ 4 ] ;
2007-12-19 17:10:02 +01:00
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 ;
2009-06-22 10:15:58 +02:00
for ( i = 0 ; i < num_untracked_materials ; + + i )
{
2007-06-20 14:36:32 +02:00
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 ) {
2009-03-27 10:25:55 +01:00
const void * ptrToCoords = specular + SkipnStrides * si - > elements [ WINED3D_FFP_SPECULAR ] . stride ;
2007-01-16 23:43:28 +01:00
2009-03-30 11:24:54 +02:00
specular_funcs [ si - > elements [ WINED3D_FFP_SPECULAR ] . format_desc - > emit_idx ] ( ptrToCoords ) ;
2008-12-04 17:41:30 +01:00
if ( specular_fog )
{
DWORD specularColor = * ( const DWORD * ) ptrToCoords ;
GL_EXTCALL ( glFogCoordfEXT ( specularColor > > 24 ) ) ;
}
2004-12-09 12:42:34 +01:00
}
/* Normal -------------------------------- */
2007-01-17 00:06:34 +01:00
if ( normal ! = NULL ) {
2009-03-27 10:25:55 +01:00
const void * ptrToCoords = normal + SkipnStrides * si - > elements [ WINED3D_FFP_NORMAL ] . stride ;
2009-03-30 11:24:54 +02:00
normal_funcs [ si - > elements [ WINED3D_FFP_NORMAL ] . format_desc - > emit_idx ] ( 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 ) {
2009-03-27 10:25:55 +01:00
const void * ptrToCoords = position + SkipnStrides * si - > elements [ WINED3D_FFP_POSITION ] . stride ;
2009-03-30 11:24:54 +02:00
position_funcs [ si - > elements [ WINED3D_FFP_POSITION ] . format_desc - > emit_idx ] ( 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 " ) ;
}
2009-05-14 19:40:56 +02:00
/* GL locking is done by the caller */
2009-03-27 10:25:56 +01:00
static inline void send_attribute ( IWineD3DDeviceImpl * This , WINED3DFORMAT format , const UINT index , const void * ptr )
{
switch ( format )
{
case WINED3DFMT_R32_FLOAT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib1fvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R32G32_FLOAT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib2fvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R32G32B32_FLOAT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib3fvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R32G32B32A32_FLOAT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4fvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R8G8B8A8_UINT :
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib4ubvARB ( index , ptr ) ) ;
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_A8R8G8B8 :
2009-01-23 10:22:33 +01:00
if ( GL_SUPPORT ( EXT_VERTEX_ARRAY_BGRA ) )
{
const DWORD * src = ptr ;
DWORD c = * src & 0xff00ff00 ;
c | = ( * src & 0xff0000 ) > > 16 ;
c | = ( * src & 0xff ) < < 16 ;
GL_EXTCALL ( glVertexAttrib4NubvARB ( index , ( GLubyte * ) & c ) ) ;
break ;
}
/* else fallthrough */
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R8G8B8A8_UNORM :
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib4NubvARB ( index , ptr ) ) ;
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16_SINT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4svARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16B16A16_SINT :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4svARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16_SNORM :
2007-12-17 18:18:19 +01:00
{
2008-11-25 11:57:39 +01:00
GLshort s [ 4 ] = { ( ( const GLshort * ) ptr ) [ 0 ] , ( ( const GLshort * ) ptr ) [ 1 ] , 0 , 1 } ;
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib4NsvARB ( index , s ) ) ;
break ;
}
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16_UNORM :
2007-12-17 18:18:19 +01:00
{
2008-11-25 11:57:39 +01:00
GLushort s [ 4 ] = { ( ( const GLushort * ) ptr ) [ 0 ] , ( ( const GLushort * ) ptr ) [ 1 ] , 0 , 1 } ;
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib4NusvARB ( index , s ) ) ;
break ;
}
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16B16A16_SNORM :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4NsvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16B16A16_UNORM :
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4NusvARB ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R10G10B10A2_UINT :
2007-12-17 18:18:19 +01:00
FIXME ( " Unsure about WINED3DDECLTYPE_UDEC3 \n " ) ;
/*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R10G10B10A2_SNORM :
2007-12-17 18:18:19 +01:00
FIXME ( " Unsure about WINED3DDECLTYPE_DEC3N \n " ) ;
/*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16_FLOAT :
2007-12-17 18:18:19 +01:00
/* 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 ) ) {
2009-04-06 19:07:51 +02:00
/* Not supported by GL_ARB_half_float_vertex */
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib2hvNV ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
} else {
2008-11-25 11:57:39 +01:00
float x = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 0 ) ;
float y = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 1 ) ;
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib2fARB ( index , x , y ) ) ;
}
break ;
2009-03-27 10:25:56 +01:00
case WINED3DFMT_R16G16B16A16_FLOAT :
2007-12-17 18:18:19 +01:00
if ( GL_SUPPORT ( NV_HALF_FLOAT ) ) {
2009-04-06 19:07:51 +02:00
/* Not supported by GL_ARB_half_float_vertex */
2009-01-20 10:00:20 +01:00
GL_EXTCALL ( glVertexAttrib4hvNV ( index , ptr ) ) ;
2007-12-17 18:18:19 +01:00
} else {
2008-11-25 11:57:39 +01:00
float x = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 0 ) ;
float y = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 1 ) ;
float z = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 2 ) ;
float w = float_16_to_32 ( ( ( const unsigned short * ) ptr ) + 3 ) ;
2007-12-17 18:18:19 +01:00
GL_EXTCALL ( glVertexAttrib4fARB ( index , x , y , z , w ) ) ;
}
break ;
default :
2009-03-27 10:25:56 +01:00
ERR ( " Unexpected attribute format: %s \n " , debug_d3dformat ( format ) ) ;
2007-12-17 18:18:19 +01:00
break ;
}
}
2009-05-14 19:40:56 +02:00
/* GL locking is done by the caller */
2009-03-27 10:25:55 +01:00
static void drawStridedSlowVs ( IWineD3DDevice * iface , const struct wined3d_stream_info * si , UINT numberOfVertices ,
2009-03-05 12:30:42 +01:00
GLenum glPrimitiveType , const void * idxData , UINT idxSize , UINT minIndex , UINT startIdx )
2008-11-28 15:30:12 +01:00
{
2007-12-17 18:18:19 +01:00
IWineD3DDeviceImpl * This = ( IWineD3DDeviceImpl * ) iface ;
2009-01-07 09:00:55 +01:00
long SkipnStrides = startIdx + This - > stateBlock - > loadBaseVertexIndex ;
2007-12-17 18:18:19 +01:00
const WORD * pIdxBufS = NULL ;
const DWORD * pIdxBufL = NULL ;
2009-03-05 12:30:42 +01:00
UINT vx_index ;
2007-12-17 18:18:19 +01:00
int i ;
2008-01-23 22:39:59 +01:00
IWineD3DStateBlockImpl * stateblock = This - > stateBlock ;
2008-11-28 15:30:12 +01:00
const BYTE * ptr ;
2007-12-17 18:18:19 +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 ) {
2009-04-09 18:40:57 +02:00
idxData = buffer_get_sysmem ( ( struct wined3d_buffer * ) This - > stateBlock - > pIndexData ) ;
2007-12-17 18:18:19 +01:00
}
2009-01-20 10:00:20 +01:00
if ( idxSize = = 2 ) pIdxBufS = idxData ;
else pIdxBufL = idxData ;
2008-10-30 17:38:56 +01:00
} else if ( idxData ) {
ERR ( " non-NULL idxData with 0 idxSize, this should never happen \n " ) ;
return ;
2007-12-17 18:18:19 +01:00
}
/* Start drawing in GL */
2008-09-03 16:26:38 +02:00
VTRACE ( ( " glBegin(%x) \n " , glPrimitiveType ) ) ;
2007-12-17 18:18:19 +01:00
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 - - ) {
2009-03-27 10:25:55 +01:00
if ( ! si - > elements [ i ] . data ) continue ;
2007-12-17 18:18:19 +01:00
2009-03-27 10:25:55 +01:00
ptr = si - > elements [ i ] . data +
si - > elements [ i ] . stride * SkipnStrides +
stateblock - > streamOffset [ si - > elements [ i ] . stream_idx ] ;
2007-12-17 18:18:19 +01:00
2009-03-30 11:24:54 +02:00
send_attribute ( This , si - > elements [ i ] . format_desc - > format , i , ptr ) ;
2007-12-17 18:18:19 +01:00
}
2007-12-19 16:28:14 +01:00
SkipnStrides + + ;
2007-12-17 18:18:19 +01:00
}
glEnd ( ) ;
}
2009-05-14 19:40:56 +02:00
/* GL locking is done by the caller */
2009-03-27 10:25:55 +01:00
static inline void drawStridedInstanced ( IWineD3DDevice * iface , const struct wined3d_stream_info * si ,
2009-03-05 12:30:42 +01:00
UINT numberOfVertices , GLenum glPrimitiveType , const void * idxData , UINT idxSize , UINT minIndex ,
UINT startIdx )
2008-11-28 15:30:12 +01:00
{
2008-11-26 21:37:28 +01:00
UINT numInstances = 0 , i ;
int numInstancedAttribs = 0 , j ;
2009-03-27 10:25:55 +01:00
UINT instancedData [ sizeof ( si - > elements ) / sizeof ( * si - > elements ) /* 16 */ ] ;
2007-02-14 17:56:29 +01:00
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 ) ;
/* 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
}
}
2009-03-27 10:25:55 +01:00
for ( i = 0 ; i < sizeof ( si - > elements ) / sizeof ( * si - > elements ) ; + + i )
{
if ( stateblock - > streamFlags [ si - > elements [ i ] . stream_idx ] & 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 + + ) {
2009-03-27 10:25:55 +01:00
const BYTE * ptr = si - > elements [ instancedData [ j ] ] . data +
si - > elements [ instancedData [ j ] ] . stride * i +
stateblock - > streamOffset [ si - > elements [ instancedData [ j ] ] . stream_idx ] ;
if ( si - > elements [ instancedData [ j ] ] . buffer_object )
{
struct wined3d_buffer * vb =
( struct wined3d_buffer * ) stateblock - > streamSource [ si - > elements [ instancedData [ j ] ] . stream_idx ] ;
2009-04-09 18:40:57 +02:00
ptr + = ( long ) buffer_get_sysmem ( vb ) ;
2007-02-14 17:56:29 +01:00
}
2009-03-30 11:24:54 +02:00
send_attribute ( This , si - > elements [ instancedData [ j ] ] . format_desc - > format , 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 " ) ;
}
}
2009-03-27 10:25:55 +01:00
static inline void remove_vbos ( IWineD3DDeviceImpl * This , struct wined3d_stream_info * s )
{
2009-03-26 10:43:40 +01:00
unsigned int i ;
2007-08-23 17:35:10 +02:00
2009-03-27 10:25:55 +01:00
for ( i = 0 ; i < ( sizeof ( s - > elements ) / sizeof ( * s - > elements ) ) ; + + i )
2009-03-26 10:43:40 +01:00
{
2009-03-27 10:25:55 +01:00
struct wined3d_stream_info_element * e = & s - > elements [ i ] ;
if ( e - > buffer_object )
2009-03-26 10:43:40 +01:00
{
2009-03-27 10:25:55 +01:00
struct wined3d_buffer * vb = ( struct wined3d_buffer * ) This - > stateBlock - > streamSource [ e - > stream_idx ] ;
e - > buffer_object = 0 ;
2009-04-09 18:40:57 +02:00
e - > data = ( BYTE * ) ( ( unsigned long ) e - > data + ( unsigned long ) buffer_get_sysmem ( vb ) ) ;
2007-08-23 17:35:10 +02:00
}
}
}
2004-12-09 12:42:34 +01:00
/* Routine common to the draw primitive and draw indexed primitive routines */
2009-03-05 12:30:43 +01:00
void drawPrimitive ( IWineD3DDevice * iface , UINT index_count , UINT numberOfVertices ,
UINT StartIdx , UINT idxSize , const void * idxData , UINT minIndex )
2009-01-07 09:00:55 +01:00
{
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
IWineD3DSurfaceImpl * target ;
2008-11-26 21:37:28 +01:00
unsigned int i ;
2004-12-09 12:42:34 +01:00
2009-03-05 12:30:42 +01:00
if ( ! index_count ) return ;
2008-03-23 13:53:45 +01:00
2009-06-19 11:04:31 +02:00
if ( This - > stateBlock - > renderState [ WINED3DRS_COLORWRITEENABLE ] )
{
/* Invalidate the back buffer memory so LockRect will read it the next time */
for ( i = 0 ; i < GL_LIMITS ( buffers ) ; + + i )
{
target = ( IWineD3DSurfaceImpl * ) This - > render_targets [ i ] ;
if ( target )
{
IWineD3DSurface_LoadLocation ( ( IWineD3DSurface * ) target , SFLAG_INDRAWABLE , NULL ) ;
IWineD3DSurface_ModifyLocation ( ( IWineD3DSurface * ) target , SFLAG_INDRAWABLE , TRUE ) ;
}
2006-06-04 16:42:57 +02:00
}
}
2008-09-03 16:25:44 +02:00
/* Signals other modules that a drawing is in progress and the stateblock finalized */
This - > isInDraw = TRUE ;
ActivateContext ( This , This - > render_targets [ 0 ] , CTXUSAGE_DRAWPRIM ) ;
2008-08-21 18:23:32 +02:00
if ( This - > stencilBufferTarget ) {
2008-09-03 16:25:44 +02:00
/* Note that this depends on the ActivateContext call above to set
2009-06-17 10:19:52 +02:00
* This - > render_offscreen properly . We don ' t currently take the
* Z - compare function into account , but we could skip loading the
* depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well . Also note
* that we never copy the stencil data . */
2008-08-21 18:23:32 +02:00
DWORD location = This - > render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN ;
2009-06-17 10:19:52 +02:00
if ( This - > stateBlock - > renderState [ WINED3DRS_ZWRITEENABLE ]
| | This - > stateBlock - > renderState [ WINED3DRS_ZENABLE ] )
surface_load_ds_location ( This - > stencilBufferTarget , location ) ;
if ( This - > stateBlock - > renderState [ WINED3DRS_ZWRITEENABLE ] )
surface_modify_ds_location ( This - > stencilBufferTarget , location ) ;
2008-08-21 18:23:32 +02:00
}
2004-12-09 12:42:34 +01:00
/* Ok, we will be updating the screen from here onwards so grab the lock */
2007-08-06 16:27:08 +02:00
ENTER_GL ( ) ;
2005-08-19 12:05:00 +02:00
{
2009-03-05 12:30:43 +01:00
GLenum glPrimType = This - > stateBlock - > gl_primitive_type ;
2007-06-20 14:36:32 +02:00
BOOL emulation = FALSE ;
2009-03-27 10:25:55 +01:00
const struct wined3d_stream_info * stream_info = & This - > strided_streams ;
struct wined3d_stream_info stridedlcl ;
2009-03-05 12:30:42 +01:00
if ( ! numberOfVertices ) numberOfVertices = index_count ;
2006-07-04 11:08:39 +02:00
2008-12-30 14:56:49 +01:00
if ( ! use_vs ( This - > stateBlock ) )
{
2009-01-08 10:19:16 +01:00
if ( ! This - > strided_streams . position_transformed & & This - > activeContext - > num_untracked_materials
& & This - > stateBlock - > renderState [ WINED3DRS_LIGHTING ] )
{
2008-12-01 15:32:14 +01:00
static BOOL warned ;
if ( ! warned ) {
2008-04-18 23:42:03 +02:00
FIXME ( " Using software emulation because not all material properties could be tracked \n " ) ;
2008-12-01 15:32:14 +01:00
warned = TRUE ;
2008-04-18 23:42:03 +02:00
} 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-12-01 15:32:14 +01:00
static BOOL warned ;
if ( ! warned ) {
2008-04-18 23:42:03 +02:00
FIXME ( " Using software emulation because manual fog coordinates are provided \n " ) ;
2008-12-01 15:32:14 +01:00
warned = TRUE ;
2008-04-18 23:42:03 +02:00
} else {
TRACE ( " Using software emulation because manual fog coordinates are provided \n " ) ;
}
2007-08-14 02:31:10 +02:00
emulation = TRUE ;
}
if ( emulation ) {
2009-03-27 10:25:55 +01:00
stream_info = & stridedlcl ;
2007-06-20 14:36:32 +02:00
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 */
2008-12-30 14:56:49 +01:00
if ( use_vs ( This - > stateBlock ) )
{
2008-12-01 15:32:14 +01:00
static BOOL warned ;
if ( ! warned ) {
2008-04-18 23:42:03 +02:00
FIXME ( " Using immediate mode with vertex shaders for half float emulation \n " ) ;
2008-12-01 15:32:14 +01:00
warned = TRUE ;
2008-04-18 23:42:03 +02:00
} else {
TRACE ( " Using immediate mode with vertex shaders for half float emulation \n " ) ;
}
2009-03-27 10:25:55 +01:00
drawStridedSlowVs ( iface , stream_info , index_count , glPrimType , idxData , idxSize , minIndex , StartIdx ) ;
2007-12-19 17:18:39 +01:00
} else {
2009-03-27 10:25:55 +01:00
drawStridedSlow ( iface , stream_info , index_count , glPrimType , idxData , idxSize , minIndex , StartIdx ) ;
2007-12-19 17:18:39 +01:00
}
2007-02-14 17:56:29 +01:00
} else if ( This - > instancedDraw ) {
/* Instancing emulation with mixing immediate mode and arrays */
2009-03-05 12:30:42 +01:00
drawStridedInstanced ( iface , & This - > strided_streams , index_count ,
glPrimType , idxData , idxSize , minIndex , StartIdx ) ;
2007-12-19 17:18:39 +01:00
} else {
2009-01-08 10:19:16 +01:00
drawStridedFast ( iface , glPrimType , minIndex , minIndex + numberOfVertices - 1 ,
2009-03-05 12:30:42 +01:00
index_count , idxSize , idxData , StartIdx ) ;
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 ] ;
2008-09-10 20:25:35 +02:00
IWineD3DSurface_LockRect ( This - > render_targets [ 0 ] , & r , NULL , WINED3DLOCK_READONLY ) ;
2008-09-10 22:41:10 +02:00
sprintf ( buffer , " /tmp/backbuffer_%ld.tga " , primCounter ) ;
2004-12-09 12:42:34 +01:00
TRACE ( " Saving screenshot %s \n " , buffer ) ;
2008-09-10 20:25:35 +02:00
IWineD3DSurface_SaveSnapshot ( This - > render_targets [ 0 ] , buffer ) ;
IWineD3DSurface_UnlockRect ( This - > render_targets [ 0 ] ) ;
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 ) {
2008-09-10 22:41:10 +02:00
sprintf ( buffer , " /tmp/texture_%p_%ld_%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 ) {
2009-02-03 09:36:07 +01:00
IWineD3DTexture_GetSurfaceLevel ( This - > stateBlock - > textures [ textureNo ] , 0 , & pSur ) ;
2005-09-27 12:49:59 +02:00
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
}
2008-09-10 22:41:10 +02:00
TRACE ( " drawprim #%ld \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 .
*
2008-09-10 20:25:35 +02:00
* To read back , the opengl feedback mode is used . This creates a problem because we want
2007-07-04 17:57:45 +02:00
* 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 ;
2009-03-27 10:25:55 +01:00
struct wined3d_stream_info stream_info ;
struct wined3d_stream_info_element * e ;
2008-11-28 15:30:12 +01:00
const BYTE * data ;
2008-11-28 15:30:12 +01:00
const WINED3DRECTPATCH_INFO * info = & patch - > RectPatchInfo ;
2007-07-04 17:57:45 +02:00
DWORD vtxStride ;
GLenum feedback_type ;
GLfloat * feedbuffer ;
2009-06-25 10:24:55 +02:00
/* Simply activate the context for blitting. This disables all the things we don't want and
* 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 . */
ActivateContext ( This , This - > lastActiveRenderTarget , CTXUSAGE_BLIT ) ;
2007-07-04 17:57:45 +02:00
/* First, locate the position data. This is provided in a vertex buffer in the stateblock.
* Beware of vbos
*/
2009-03-27 10:25:55 +01:00
device_stream_info_from_declaration ( This , FALSE , & stream_info , NULL ) ;
e = & stream_info . elements [ WINED3D_FFP_POSITION ] ;
if ( e - > buffer_object )
{
2009-03-06 14:56:23 +01:00
struct wined3d_buffer * vb ;
2009-03-27 10:25:55 +01:00
vb = ( struct wined3d_buffer * ) This - > stateBlock - > streamSource [ e - > stream_idx ] ;
2009-04-09 18:40:57 +02:00
e - > data = ( BYTE * ) ( ( unsigned long ) e - > data + ( unsigned long ) buffer_get_sysmem ( vb ) ) ;
2007-07-04 17:57:45 +02:00
}
2009-03-27 10:25:55 +01:00
vtxStride = e - > stride ;
data = e - > data +
2007-07-04 17:57:45 +02:00
vtxStride * info - > Stride * info - > StartVertexOffsetHeight +
vtxStride * info - > StartVertexOffsetWidth ;
/* Not entirely sure about what happens with transformed vertices */
2009-03-27 10:25:55 +01:00
if ( stream_info . position_transformed ) FIXME ( " Transformed position in rectpatch generation \n " ) ;
2009-01-08 10:19:16 +01:00
2007-07-04 17:57:45 +02:00
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 + + ) {
2008-11-28 15:30:12 +01:00
const float * v = ( const float * ) ( data + vtxStride * i + vtxStride * info - > Stride * j ) ;
2007-07-04 17:57:45 +02:00
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 ;
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 ) {
2008-12-10 10:04:40 +01:00
static const GLfloat black [ ] = { 0 , 0 , 0 , 0 } ;
static const GLfloat red [ ] = { 1 , 0 , 0 , 0 } ;
static const GLfloat green [ ] = { 0 , 1 , 0 , 0 } ;
static const GLfloat blue [ ] = { 0 , 0 , 1 , 0 } ;
static const GLfloat white [ ] = { 1 , 1 , 1 , 1 } ;
2007-07-04 17:57:45 +02:00
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 ,
2008-11-28 15:30:12 +01:00
( const GLfloat * ) data ) ;
2007-07-04 17:57:45 +02:00
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 ,
2008-11-28 15:30:12 +01:00
( const GLfloat * ) data ) ;
2007-07-04 17:57:45 +02:00
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 ) ;
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 ) ;
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 */
2008-12-10 10:04:40 +01:00
static const GLfloat x [ ] = { - 1 , 0 , 0 , 0 } ;
static const GLfloat y [ ] = { 0 , - 1 , 0 , 0 } ;
static const GLfloat z [ ] = { 0 , 0 , - 1 , 0 } ;
2007-07-04 17:57:45 +02:00
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 ) ) ;
2009-03-27 10:25:56 +01:00
patch - > strided . position . format = WINED3DFMT_R32G32B32_FLOAT ;
2009-03-27 10:25:55 +01:00
patch - > strided . position . lpData = ( BYTE * ) patch - > mem ;
patch - > strided . position . dwStride = vtxStride ;
2007-07-04 17:57:45 +02:00
if ( patch - > has_normals ) {
2009-03-27 10:25:56 +01:00
patch - > strided . normal . format = WINED3DFMT_R32G32B32_FLOAT ;
2009-03-27 10:25:55 +01:00
patch - > strided . normal . lpData = ( BYTE * ) patch - > mem + 3 * sizeof ( float ) /* pos */ ;
patch - > strided . normal . dwStride = vtxStride ;
2007-07-04 17:57:45 +02:00
}
if ( patch - > has_texcoords ) {
2009-03-27 10:25:56 +01:00
patch - > strided . texCoords [ 0 ] . format = WINED3DFMT_R32G32B32A32_FLOAT ;
2009-03-27 10:25:55 +01:00
patch - > strided . texCoords [ 0 ] . lpData = ( BYTE * ) patch - > mem + 3 * sizeof ( float ) /* pos */ ;
2007-07-04 17:57:45 +02:00
if ( patch - > has_normals ) {
2009-03-27 10:25:55 +01:00
patch - > strided . texCoords [ 0 ] . lpData + = 3 * sizeof ( float ) ;
2007-07-04 17:57:45 +02:00
}
2009-03-27 10:25:55 +01:00
patch - > strided . texCoords [ 0 ] . dwStride = vtxStride ;
2007-07-04 17:57:45 +02:00
}
return WINED3D_OK ;
}