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 }
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 ); }