void StencilShadow::RenderShadow()
{
#ifndef DISABLE_STENCILSHADOW
	DWORD lighting, fog, srcblend, destblend, alphablend, zwrite, zfunc, cullmode;

	GL_State(GLS_DEFAULT);

	glw_state->device->GetRenderState( D3DRS_LIGHTING, &lighting );
	glw_state->device->GetRenderState( D3DRS_FOGENABLE, &fog );
	glw_state->device->GetRenderState( D3DRS_SRCBLEND, &srcblend );
	glw_state->device->GetRenderState( D3DRS_DESTBLEND, &destblend );
	glw_state->device->GetRenderState( D3DRS_ALPHABLENDENABLE, &alphablend );
	glw_state->device->GetRenderState( D3DRS_ZWRITEENABLE, &zwrite );
	glw_state->device->GetRenderState( D3DRS_ZFUNC, &zfunc );
	glw_state->device->GetRenderState( D3DRS_CULLMODE, &cullmode );

	pVerts = NULL;
	pExtrusions = NULL;

	GL_Bind( tr.whiteImage );

	glw_state->device->SetRenderState( D3DRS_LIGHTING, FALSE );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, FALSE );

	glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
	glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );

    // Disable z-buffer writes (note: z-testing still occurs), and enable the
    // stencil-buffer
    glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );
    glw_state->device->SetRenderState( D3DRS_STENCILENABLE, TRUE );

    // Don't bother with interpolating color
    glw_state->device->SetRenderState( D3DRS_SHADEMODE,     D3DSHADE_FLAT );

	glw_state->device->SetRenderState( D3DRS_ZFUNC,			D3DCMP_LESS );

    // Set up stencil compare function, reference value, and masks.
    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
    // Note: since we set up the stencil-test to always pass, the STENCILFAIL
    // renderstate is really not needed.
    glw_state->device->SetRenderState( D3DRS_STENCILFUNC,   D3DCMP_ALWAYS );
#ifdef _STENCIL_REVERSE
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL,  D3DSTENCILOP_INCR );
    glw_state->device->SetRenderState( D3DRS_STENCILFAIL,   D3DSTENCILOP_KEEP );
	glw_state->device->SetRenderState( D3DRS_STENCILPASS,   D3DSTENCILOP_KEEP );
#else
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL,  D3DSTENCILOP_KEEP );
    glw_state->device->SetRenderState( D3DRS_STENCILFAIL,   D3DSTENCILOP_KEEP );
	glw_state->device->SetRenderState( D3DRS_STENCILPASS,   D3DSTENCILOP_INCR );	
#endif

    // If ztest passes, inc/decrement stencil buffer value
    glw_state->device->SetRenderState( D3DRS_STENCILREF,       0x1 );
    glw_state->device->SetRenderState( D3DRS_STENCILMASK,      0x7f ); //0xffffffff );
    glw_state->device->SetRenderState( D3DRS_STENCILWRITEMASK, 0x7f ); //0xffffffff );

    // Make sure that no pixels get drawn to the frame buffer
    glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
    glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, 0 );

	glw_state->device->SetTexture(0, NULL);
	glw_state->device->SetTexture(1, NULL);

	// Compute the matrix set
    XGMATRIX matComposite, matProjectionViewport, matWorld;
	glw_state->device->GetProjectionViewportMatrix( &matProjectionViewport );

	XGMatrixMultiply( &matComposite, (XGMATRIX*)glw_state->matrixStack[glwstate_t::MatrixMode_Model]->GetTop(), &matProjectionViewport );

	// Transpose and set the composite matrix.
	XGMatrixTranspose( &matComposite, &matComposite );
	glw_state->device->SetVertexShaderConstant( CV_WORLDVIEWPROJ_0, &matComposite, 4 );

	// Set viewport offsets.
	float fViewportOffsets[4] = { 0.53125f, 0.53125f, 0.0f, 0.0f };
	glw_state->device->SetVertexShaderConstant( CV_VIEWPORT_OFFSETS, &fViewportOffsets, 1 );

	glw_state->device->SetVertexShader(m_dwVertexShaderShadow);

#ifdef _STENCIL_REVERSE
	qglCullFace( GL_FRONT );
#else
	qglCullFace( GL_BACK );
#endif

	BuildEdges();

	// Draw front-side of shadow volume in stencil/z only
	if(m_nIndexes)
        renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes );
#ifdef _STENCIL_REVERSE
	if(m_nIndexesCap)
        renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap );
#endif

	// Now reverse cull order so back sides of shadow volume are written.
#ifdef _STENCIL_REVERSE
	qglCullFace( GL_BACK );
#else
    qglCullFace( GL_FRONT );
#endif

    // Decrement stencil buffer value
#ifdef _STENCIL_REVERSE
	glw_state->device->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_DECR );
#else
	glw_state->device->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );
#endif

	// Draw back-side of shadow volume in stencil/z only
	if(m_nIndexes)
        renderObject_Shadow( D3DPT_QUADLIST, m_nIndexes, m_shadowIndexes );
#ifdef _STENCIL_REVERSE
	if(m_nIndexesCap)
        renderObject_Shadow( D3DPT_TRIANGLELIST, m_nIndexesCap, m_shadowIndexesCap );
#endif

	// Restore render states
	glw_state->device->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALL );

    glw_state->device->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
	glw_state->device->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
	glw_state->device->SetRenderState( D3DRS_LIGHTING, lighting );
	glw_state->device->SetRenderState( D3DRS_FOGENABLE, fog );
	glw_state->device->SetRenderState( D3DRS_SRCBLEND, srcblend );
	glw_state->device->SetRenderState( D3DRS_DESTBLEND, destblend );
	glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, alphablend );
	glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE, zwrite );
	glw_state->device->SetRenderState( D3DRS_ZFUNC, zfunc );
	glw_state->device->SetRenderState( D3DRS_CULLMODE, cullmode );
#endif
}
Exemple #2
0
void setup_weighted_mesh_vertex_shader( void *p_root_matrix, void *p_bone_matrices, int num_bone_matrices )
{
	XGMATRIX	dest_matrix;
	XGMATRIX	inverse_view_matrix;
	XGMATRIX	temp_matrix;
	XGMATRIX	projMatrix;
	XGMATRIX	viewMatrix;
	XGMATRIX	worldMatrix;

	// Projection matrix.
	XGMatrixTranspose( &projMatrix, &EngineGlobals.projection_matrix );
	
	// View matrix.
	XGMatrixTranspose( &viewMatrix, &EngineGlobals.view_matrix );
    viewMatrix.m[3][0] = 0.0f;
    viewMatrix.m[3][1] = 0.0f;
    viewMatrix.m[3][2] = 0.0f;
    viewMatrix.m[3][3] = 1.0f;
	
	// World space transformation matrix. (3x3 rotation plus 3 element translation component).
	worldMatrix.m[0][0] = ((float*)p_root_matrix )[0];
	worldMatrix.m[0][1] = ((float*)p_root_matrix )[1];
	worldMatrix.m[0][2] = ((float*)p_root_matrix )[2];
	worldMatrix.m[0][3] = ((float*)p_root_matrix )[3];
	worldMatrix.m[1][0] = ((float*)p_root_matrix )[4];
	worldMatrix.m[1][1] = ((float*)p_root_matrix )[5];
	worldMatrix.m[1][2] = ((float*)p_root_matrix )[6];
	worldMatrix.m[1][3] = ((float*)p_root_matrix )[7];
	worldMatrix.m[2][0] = ((float*)p_root_matrix )[8];
	worldMatrix.m[2][1] = ((float*)p_root_matrix )[9];
	worldMatrix.m[2][2] = ((float*)p_root_matrix )[10];
	worldMatrix.m[2][3] = ((float*)p_root_matrix )[11];
	worldMatrix.m[3][0] = 0.0f;
	worldMatrix.m[3][1] = 0.0f;
	worldMatrix.m[3][2] = 0.0f;
	worldMatrix.m[3][3] = 1.0f;

	// Calculate composite world->view->projection matrix.
	XGMatrixMultiply( &temp_matrix, &viewMatrix, &worldMatrix );
	XGMatrixMultiply( &dest_matrix, &projMatrix, &temp_matrix );

	// Switch to 192 constant mode, removing the lock on the reserved constants c-38 and c-37.
//	D3DDevice_SetShaderConstantMode( D3DSCM_192CONSTANTS | D3DSCM_NORESERVEDCONSTANTS );

	// Load up the combined world, camera & projection matrix.
	D3DDevice_SetVertexShaderConstantFast( VSCONST_REG_TRANSFORM_OFFSET, (void*)&dest_matrix, VSCONST_REG_TRANSFORM_SIZE );
	D3DDevice_SetVertexShaderConstantFast( VSCONST_REG_WORLD_TRANSFORM_OFFSET,	(void*)&worldMatrix, VSCONST_REG_WORLD_TRANSFORM_SIZE );

	// We want to transform the light directions by the inverse of the world transform - this means we don't have to transform
	// the normal by the world transform for every vertex in the vertex shader. However, the function D3DXVec3TransformNormal
	// (used below) does the inverse transform for us, so need to actually figure the inverse...
//	XGMATRIX inverse_world_transform = worldMatrix;
//	D3DXMatrixInverse( &inverse_world_transform, NULL, &worldMatrix );

	float directional_light_color[24];
	CopyMemory( directional_light_color, EngineGlobals.directional_light_color, sizeof( float ) * 24 );
	
	XGVec3TransformNormal((XGVECTOR3*)&directional_light_color[0],	(XGVECTOR3*)&EngineGlobals.directional_light_color[0], &worldMatrix );
	XGVec3TransformNormal((XGVECTOR3*)&directional_light_color[8],	(XGVECTOR3*)&EngineGlobals.directional_light_color[8], &worldMatrix );
	XGVec3TransformNormal((XGVECTOR3*)&directional_light_color[16],	(XGVECTOR3*)&EngineGlobals.directional_light_color[16], &worldMatrix );
	
	XGVec3Normalize((XGVECTOR3*)&directional_light_color[0], (XGVECTOR3*)&directional_light_color[0] ); 
	XGVec3Normalize((XGVECTOR3*)&directional_light_color[8], (XGVECTOR3*)&directional_light_color[8] ); 
	XGVec3Normalize((XGVECTOR3*)&directional_light_color[16], (XGVECTOR3*)&directional_light_color[16] ); 

	// Load up the directional light data.
	D3DDevice_SetVertexShaderConstantFast( VSCONST_REG_DIR_LIGHT_OFFSET, (void*)directional_light_color, 6 );

	// Load up the ambient light color.
	D3DDevice_SetVertexShaderConstantFast( VSCONST_REG_AMB_LIGHT_OFFSET, (void*)EngineGlobals.ambient_light_color, 1 );
	
	// Calculate and load up the model-relative camera position.
	EngineGlobals.model_relative_cam_position = XGVECTOR3( EngineGlobals.cam_position.x - worldMatrix.m[0][3],
														   EngineGlobals.cam_position.y - worldMatrix.m[1][3],
														   EngineGlobals.cam_position.z - worldMatrix.m[2][3] );
	XGVec3TransformNormal( &EngineGlobals.model_relative_cam_position, &EngineGlobals.model_relative_cam_position, &worldMatrix );

	float specular_attribs[4] = { EngineGlobals.model_relative_cam_position.x,
								  EngineGlobals.model_relative_cam_position.y,
								  EngineGlobals.model_relative_cam_position.z,
								  0.0f };
	D3DDevice_SetVertexShaderConstantFast( VSCONST_REG_CAM_POS_OFFSET, (void*)&specular_attribs, 1 );

	// Safety check here to limit number of bones to that available.
	if( num_bone_matrices > 55 )
	{
		num_bone_matrices = 55;
	}

	DWORD*	p_bone_element	= (DWORD*)p_bone_matrices;

	// Begin state block to set vertex shader constants for bone transforms.
	DWORD *p_push;
	EngineGlobals.p_Device->BeginState(( num_bone_matrices * ( 12 + 1 )) + 3, &p_push );

	// 1 here isn't the parameter for SET_TRANSFORM_CONSTANT_LOAD; rather, it's the number of dwords written to that register.
	p_push[0] = D3DPUSH_ENCODE( D3DPUSH_SET_TRANSFORM_CONSTANT_LOAD, 1 ); 

	// Here is the actual parameter for SET_TRANSFORM_CONSTANT_LOAD. Always add 96 to the constant register.
	p_push[1] = VSCONST_REG_MATRIX_OFFSET + 96;

	p_push += 2;

	while( num_bone_matrices > 0 )
	{
		// A 3x4 matrix is 12 dwords. You can encode a maximum of 32 dwords to D3DPUSH_SET_TRANSFORM_CONSTANT before needing another D3DPUSH_ENCODE.
		p_push[0]		= D3DPUSH_ENCODE( D3DPUSH_SET_TRANSFORM_CONSTANT, 12 );

		p_push[1]		= p_bone_element[0];
		p_push[2]		= p_bone_element[4];
		p_push[3]		= p_bone_element[8];
		p_push[4]		= p_bone_element[12];

		p_push[5]		= p_bone_element[1];
		p_push[6]		= p_bone_element[5];
		p_push[7]		= p_bone_element[9];
		p_push[8]		= p_bone_element[13];

		p_push[9]		= p_bone_element[2];
		p_push[10]		= p_bone_element[6];
		p_push[11]		= p_bone_element[10];
		p_push[12]		= p_bone_element[14];

		--num_bone_matrices;

		p_bone_element	+= 16;
		p_push			+= 13;
	}

	EngineGlobals.p_Device->EndState( p_push );

	// Load up the replacement registers for c-38 and c-37
	// The z value is 2^24 - to take 1.0f to the max z buffer value for a 24bit z buffer.
	static float homogenous_to_screen_reg[8] = { 320.0f, -240.0f, 1.6777215e7f, 0.0f, 320.53125f, 240.53125f, 0.0f, 0.0f };
	
	if( EngineGlobals.is_orthographic )
	{
		homogenous_to_screen_reg[0] = 128.0f;
		homogenous_to_screen_reg[1] = -128.0f;

		homogenous_to_screen_reg[2] = 1.6777215e7f;
		
		homogenous_to_screen_reg[4] = 128.53125f;
		homogenous_to_screen_reg[5] = 128.53125f;
	}
	else
	{
		homogenous_to_screen_reg[0] = (float)EngineGlobals.viewport.Width * 0.5f;
		homogenous_to_screen_reg[1] = (float)EngineGlobals.viewport.Height * -0.5f;

		homogenous_to_screen_reg[2] = ( EngineGlobals.zstencil_depth == 16 ) ? 65535.0f : 1.6777215e7f;

		homogenous_to_screen_reg[4] = (float)NxXbox::EngineGlobals.viewport.X + ((float)NxXbox::EngineGlobals.viewport.Width * 0.5f ) + 0.53125f;
		homogenous_to_screen_reg[5] = (float)NxXbox::EngineGlobals.viewport.Y + ((float)NxXbox::EngineGlobals.viewport.Height * 0.5f ) + 0.53125f;
	}

	D3DDevice_SetVertexShaderConstantFast( 94, (void*)homogenous_to_screen_reg, 2 );
}