예제 #1
0
////////////////////////////////////////////////////////////////
//
// 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);
        }
    }
}