//////////////////////////////////////////////////////////////// // // CTileBatcher::AddTile // // Add a new tile to the buffer. // Will flush previous tiles if the material is changing and such // //////////////////////////////////////////////////////////////// void CTileBatcher::AddTile ( float fX1, float fY1, float fX2, float fY2, float fU1, float fV1, float fU2, float fV2, CMaterialItem* pMaterial, float fRotation, float fRotCenOffX, float fRotCenOffY, unsigned long ulColor ) { // Flush previous if it was using a shader transform if ( m_bUseCustomMatrices ) Flush (); m_bUseCustomMatrices = false; uint uiTessellationX = 1; uint uiTessellationY = 1; // Get settings from shader if ( CShaderInstance* pShaderInstance = DynamicCast < CShaderInstance > ( pMaterial ) ) { // Get transform setting if ( pShaderInstance && pShaderInstance->m_bHasModifiedTransform ) { MakeCustomMatrices ( pShaderInstance->m_Transform, fX1, fY1, fX2, fY2, m_MatCustomWorld, m_MatCustomProjection ); m_bUseCustomMatrices = true; } // Get tessellation setting // Validate tessellation range (ensure x*y < 65536) uiTessellationX = Clamp < uint > ( 1, pShaderInstance->m_uiTessellationX, 4000 ); uiTessellationY = Clamp < uint > ( 1, pShaderInstance->m_uiTessellationY, 4000 ); uint uiNumVertices = ( uiTessellationX + 1 ) * ( uiTessellationY + 1 ); if ( uiNumVertices > 65535 ) { uint div = uiNumVertices / 6553 + 1; if ( uiTessellationX > uiTessellationY ) uiTessellationX = uiTessellationX / div * 10; else uiTessellationY = uiTessellationY / div * 10; } } // Calc number of vertices to add uint uiNumVertices = ( uiTessellationX + 1 ) * ( uiTessellationY + 1 ); // Calc position of rotation center float fRotCenX = 0; float fRotCenY = 0; if ( fRotation != 0.0f ) { fRotCenX = fRotCenOffX + ( fX1 + fX2 ) * 0.5f; fRotCenY = fRotCenOffY + ( fY1 + fY2 ) * 0.5f; } // Check if we need to flush what has been done so far if ( pMaterial != m_pCurrentMaterial || fRotation != m_fCurrentRotation || fRotCenX != m_fCurrentRotCenX || fRotCenY != m_fCurrentRotCenY || uiNumVertices + m_Vertices.size () > 65535 || m_bUseCustomMatrices ) { Flush (); SetCurrentMaterial ( pMaterial ); m_fCurrentRotation = fRotation; m_fCurrentRotCenX = fRotCenX; m_fCurrentRotCenY = fRotCenY; } uint uiBaseIndex = m_Vertices.size (); // Do quicker things if tessellation is not required if ( uiTessellationX == 1 && uiTessellationY == 1 ) { // Make room for 4 more vertices m_Vertices.resize ( m_Vertices.size () + 4 ); SPDTVertex* pVBuffer = &m_Vertices[m_Vertices.size () - 4]; // Fill vertex data WRITE_PDT_VERTEX( pVBuffer, fX1, fY1, 0, ulColor, fU1 , fV1 ); WRITE_PDT_VERTEX( pVBuffer, fX2, fY1, 0, ulColor, fU2 , fV1 ); WRITE_PDT_VERTEX( pVBuffer, fX1, fY2, 0, ulColor, fU1 , fV2 ); WRITE_PDT_VERTEX( pVBuffer, fX2, fY2, 0, ulColor, fU2 , fV2 ); // Make room for 6 more indices m_Indices.resize ( m_Indices.size () + 6 ); WORD* pIBuffer = &m_Indices[m_Indices.size () - 6]; WRITE_QUAD_INDICES( pIBuffer, uiBaseIndex, uiBaseIndex + 2 ); return; } // Write out the vertices { // Make room for vertices m_Vertices.resize ( m_Vertices.size () + uiNumVertices ); SPDTVertex* pVBuffer = &m_Vertices[m_Vertices.size () - uiNumVertices]; float fStepX = ( fX2 - fX1 ) / (float)uiTessellationX; float fStepY = ( fY2 - fY1 ) / (float)uiTessellationY; float fStepU = ( fU2 - fU1 ) / (float)uiTessellationX; float fStepV = ( fV2 - fV1 ) / (float)uiTessellationY; for ( uint y = 0 ; y < uiTessellationY + 1 ; y++ ) { float fY = fY1 + fStepY * y; float fV = fV1 + fStepV * y; for ( uint x = 0 ; x < uiTessellationX + 1 ; x++ ) { float fX = fX1 + fStepX * x; float fU = fU1 + fStepU * x; WRITE_PDT_VERTEX( pVBuffer, fX, fY, 0, ulColor, fU, fV ); } } } // Write out the indices { uint uiNumIndices = uiTessellationX * uiTessellationY * 6; // Make room for indices m_Indices.resize ( m_Indices.size () + uiNumIndices ); WORD* pIBuffer = &m_Indices[m_Indices.size () - uiNumIndices]; for ( uint y = 0 ; y < uiTessellationY ; y++ ) { uint uiRow0Base = y * ( uiTessellationX + 1 ); uint uiRow1Base = ( y + 1 ) * ( uiTessellationX + 1 ); for ( uint x = 0 ; x < uiTessellationX ; x++ ) { WRITE_QUAD_INDICES( pIBuffer, uiBaseIndex + uiRow0Base + x, uiBaseIndex + uiRow1Base + x ); } } } }
//////////////////////////////////////////////////////////////// // // CMaterialLine3DBatcher::DrawBatch // // Create vertices and draw // //////////////////////////////////////////////////////////////// void CMaterialLine3DBatcher::DrawBatch(const CVector& vecCameraPos, uint* pBatchIndices, uint uiNumBatchLines, CMaterialItem* pMaterial) { // Prepare vertex buffer std::vector<SPDTVertex> vertices; vertices.resize(uiNumBatchLines * 6); SPDTVertex* pBuffer = &vertices[0]; // For each line for (uint i = 0; i < uiNumBatchLines; i++) { const SMaterialLine3DItem& item = m_LineList[pBatchIndices[i]]; SColor color = item.ulColor; if (m_bPreGUI) { color.R /= 2; color.G /= 2; color.B /= 2; } const ulong ulColor = color; const CVector& vecA = item.vecFrom; const CVector& vecB = item.vecTo; const CVector& vecFaceToward = item.bUseFaceToward ? item.vecFaceToward : vecCameraPos; // Face toward supplied point const CVector vecDif = vecB - vecA; const CVector vecToCam = vecFaceToward - vecA; const float t = vecDif.DotProduct(&vecToCam) / vecDif.DotProduct(&vecDif); const CVector vecClosestPoint = vecA + vecDif * t; const CVector vecToLine = vecClosestPoint - vecFaceToward; // Calc other direction CVector vecLeft = vecDif; vecLeft.CrossProduct(&vecToLine); vecLeft.Normalize(); // Create rectangle points const CVector vecShift = vecLeft * (item.fWidth * 0.5f); const CVector vecA2 = item.vecFrom + vecShift; const CVector vecB2 = item.vecTo + vecShift; const CVector vecA1 = item.vecFrom - vecShift; const CVector vecB1 = item.vecTo - vecShift; WRITE_PDT_VERTEX(pBuffer, vecA1.fX, vecA1.fY, vecA1.fZ, ulColor, item.fU1, item.fV1); WRITE_PDT_VERTEX(pBuffer, vecA2.fX, vecA2.fY, vecA2.fZ, ulColor, item.fU2, item.fV1); WRITE_PDT_VERTEX(pBuffer, vecB1.fX, vecB1.fY, vecB1.fZ, ulColor, item.fU1, item.fV2); WRITE_PDT_VERTEX(pBuffer, vecA2.fX, vecA2.fY, vecA2.fZ, ulColor, item.fU2, item.fV1); WRITE_PDT_VERTEX(pBuffer, vecB2.fX, vecB2.fY, vecB2.fZ, ulColor, item.fU2, item.fV2); WRITE_PDT_VERTEX(pBuffer, vecB1.fX, vecB1.fY, vecB1.fZ, ulColor, item.fU1, item.fV2); } // Set vertex stream uint PrimitiveCount = vertices.size() / 3; const void* pVertexStreamZeroData = &vertices[0]; uint VertexStreamZeroStride = sizeof(SPDTVertex); m_pDevice->SetFVF(SPDTVertex::FVF); // Change texture addressing mode if required if (m_CurrentTextureAddress != pMaterial->m_TextureAddress) { m_CurrentTextureAddress = pMaterial->m_TextureAddress; m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, m_CurrentTextureAddress); m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, m_CurrentTextureAddress); } if (m_CurrentTextureAddress == TADDRESS_BORDER) m_pDevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, pMaterial->m_uiBorderColor); // Draw if (CTextureItem* pTextureItem = DynamicCast<CTextureItem>(pMaterial)) { // Draw using texture m_pDevice->SetTexture(0, pTextureItem->m_pD3DTexture); m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); } else if (CShaderInstance* pShaderInstance = DynamicCast<CShaderInstance>(pMaterial)) { // Draw using shader ID3DXEffect* pD3DEffect = pShaderInstance->m_pEffectWrap->m_pD3DEffect; // Apply custom parameters pShaderInstance->ApplyShaderParameters(); // Apply common parameters pShaderInstance->m_pEffectWrap->ApplyCommonHandles(); // Apply mapped parameters pShaderInstance->m_pEffectWrap->ApplyMappedHandles(); // Do shader passes DWORD dwFlags = D3DXFX_DONOTSAVESHADERSTATE; // D3DXFX_DONOTSAVE(SHADER|SAMPLER)STATE uint uiNumPasses = 0; pShaderInstance->m_pEffectWrap->Begin(&uiNumPasses, dwFlags); for (uint uiPass = 0; uiPass < uiNumPasses; uiPass++) { pD3DEffect->BeginPass(uiPass); m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); pD3DEffect->EndPass(); } pShaderInstance->m_pEffectWrap->End(); // If we didn't get the effect to save the shader state, clear some things here if (dwFlags & D3DXFX_DONOTSAVESHADERSTATE) { m_pDevice->SetVertexShader(NULL); m_pDevice->SetPixelShader(NULL); } } }