⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mgcclodmesh.cpp

📁 《3D游戏引擎设计》的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement.  The various license agreements may be found at
// the Magic Software web site.  This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf

#include "MgcCLodMesh.h"
#include "MgcRenderer.h"

MgcImplementRTTI(MgcCLodMesh,MgcTriMesh);
MgcImplementStream(MgcCLodMesh);

//----------------------------------------------------------------------------
MgcCLodMesh::MgcCLodMesh (unsigned int uiVertexQuantity, MgcVector3* akVertex,
    MgcVector3* akNormal, MgcColor* akColor, MgcVector2* akTexture,
    unsigned int uiTriangleQuantity, unsigned int* auiConnect)
    :
    MgcTriMesh(uiVertexQuantity,akVertex,akNormal,akColor,akTexture,
        uiTriangleQuantity,auiConnect)
{
    m_fLastUpdateTime = -MgcMath::INFINITY;
    m_uiInitialTriangleQuantity = m_uiTriangleQuantity;
    m_iTargetRecord = -1;

    ComputeRecords();
}
//----------------------------------------------------------------------------
MgcCLodMesh::MgcCLodMesh ()
{
    m_fLastUpdateTime = -MgcMath::INFINITY;
    m_uiInitialTriangleQuantity = 0;
    m_iTargetRecord = -1;
    m_iCurrentRecord = -1;
    m_akRecord = 0;
}
//----------------------------------------------------------------------------
MgcCLodMesh::~MgcCLodMesh ()
{
    delete[] m_akRecord;
}
//----------------------------------------------------------------------------
void MgcCLodMesh::SelectLevelOfDetail (MgcRenderer& rkRenderer)
{
    MgcTriMesh::UpdateWorldData(m_fLastUpdateTime);

    // Get target record.  The virtual function may be overridden by a derived
    // class to obtain a desired automated change in the target.
    int iTargetRecord = GetAutomatedTargetRecord();

    // collapse mesh (if necessary)
    unsigned int uiV, uiI;
    while ( m_iCurrentRecord < iTargetRecord )
    {
        m_iCurrentRecord++;

        // replace indices in connectivity array
        Record& rkRecord = m_akRecord[m_iCurrentRecord];
        for (uiV = 0; uiV < rkRecord.m_uiVertexQuantity; uiV++)
        {
            uiI = rkRecord.m_auiIndex[uiV];
            assert( m_auiConnect[uiI] == rkRecord.m_uiI1 );
            m_auiConnect[uiI] = rkRecord.m_uiI0;
        }

        // TO DO.  When ReorderVertices() is implemented, enable this.
        // reduce vertex count (vertices are properly ordered)
        //m_uiVertexQuantity -= rkRecord.m_uiVertexQuantity;

        // reduce triangle count (triangles are properly ordered)
        m_uiTriangleQuantity = rkRecord.m_uiTriangleQuantity;
    }

    // expand mesh (if necessary)
    while ( m_iCurrentRecord > iTargetRecord )
    {
        // restore indices in connectivity array
        Record& rkRecord = m_akRecord[m_iCurrentRecord];
        for (uiV = 0; uiV < rkRecord.m_uiVertexQuantity; uiV++)
        {
            uiI = rkRecord.m_auiIndex[uiV];
            assert( m_auiConnect[uiI] == rkRecord.m_uiI0 );
            m_auiConnect[uiI] = rkRecord.m_uiI1;
        }

        m_iCurrentRecord--;

        // TO DO.  When ReorderVertices() is implemented, enable this.
        // increase vertex count (vertices are properly ordered)
        //m_uiVertexQuantity += rkRecord.m_uiVertexQuantity;

        // increase triangle count (triangles are properly ordered)
        if ( m_iCurrentRecord > -1 )
        {
            m_uiTriangleQuantity =
                m_akRecord[m_iCurrentRecord].m_uiTriangleQuantity;
        }
        else
        {
            m_uiTriangleQuantity = m_uiInitialTriangleQuantity;
        }
    }
}
//----------------------------------------------------------------------------
void MgcCLodMesh::UpdateWorldData (MgcReal fAppTime)
{
    // Save the update time.  The update is deferred until Draw so that the
    // CLOD mesh is selected only when it is visible.  At this time the
    // update time is needed to pass to the UpdateGS call.
    m_fLastUpdateTime = fAppTime;

    // The deferred update means that none of the children world data is
    // computed by a recursive traversal.  Just compute the world bound.
    UpdateWorldBound();
}
//----------------------------------------------------------------------------
void MgcCLodMesh::Draw (MgcRenderer& rkRenderer)
{
    SelectLevelOfDetail(rkRenderer);
    MgcTriMesh::Draw(rkRenderer);
}
//----------------------------------------------------------------------------
MgcCLodMesh::Record::Record ()
{
    m_uiI0 = 0;
    m_uiI1 = 0;
    m_uiTriangleQuantity = 0;
    m_uiVertexQuantity = 0;
    m_auiIndex = 0;
}
//----------------------------------------------------------------------------
MgcCLodMesh::Record::~Record ()
{
    delete[] m_auiIndex;
}
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// record calculations
//----------------------------------------------------------------------------
MgcCLodMesh::ErrorMatrix* MgcCLodMesh::ComputeVertexErrorMatrices ()
{
    ErrorMatrix* akQ = new ErrorMatrix[m_uiVertexQuantity];
    memset(akQ,0,m_uiVertexQuantity*sizeof(ErrorMatrix));

    for (unsigned int uiT = 0; uiT < m_uiTriangleQuantity; uiT++)
    {
        unsigned int uiK = 3*uiT;
        unsigned int uiI0 = m_auiConnect[uiK++];
        unsigned int uiI1 = m_auiConnect[uiK++];
        unsigned int uiI2 = m_auiConnect[uiK];

        MgcVector3 kE0 = m_akVertex[uiI1] - m_akVertex[uiI0];
        MgcVector3 kE1 = m_akVertex[uiI2] - m_akVertex[uiI0];
        MgcVector3 kNormal = kE0.UnitCross(kE1);
        MgcReal fConstant = kNormal.Dot(m_akVertex[uiI0]);

        ErrorMatrix kError;
        kError[0] = kNormal.x*kNormal.x;
        kError[1] = kNormal.x*kNormal.y;
        kError[2] = kNormal.x*kNormal.z;
        kError[3] = kNormal.x*fConstant;
        kError[4] = kNormal.y*kNormal.y;
        kError[5] = kNormal.y*kNormal.z;
        kError[6] = kNormal.y*fConstant;
        kError[7] = kNormal.z*kNormal.z;
        kError[8] = kNormal.z*fConstant;
        kError[9] = fConstant*fConstant;

        for (uiK = 0; uiK < 10; uiK++)
        {
            akQ[uiI0][uiK] += kError[uiK];
            akQ[uiI1][uiK] += kError[uiK];
            akQ[uiI2][uiK] += kError[uiK];
        }
    }

    return akQ;
}
//----------------------------------------------------------------------------
MgcCLodMesh::HeapType* MgcCLodMesh::ComputeEdgeErrorMetrics (
    ErrorMatrix* akQ)
{
    HeapType* pkHeap = new HeapType(3*m_uiTriangleQuantity);

    for (unsigned int uiT = 0; uiT < m_uiTriangleQuantity; uiT++)
    {
        unsigned int uiK = 3*uiT;
        unsigned int uiI0 = m_auiConnect[uiK++];
        unsigned int uiI1 = m_auiConnect[uiK++];
        unsigned int uiI2 = m_auiConnect[uiK];

        // edge <I0,I1>
        ErrorMatrix kSum;
        MgcReal fMetric;
        KeyType kKey(uiI0,uiI1);
        if ( !pkHeap->GetAt(kKey,fMetric) )
        {
            for (uiK = 0; uiK < 10; uiK++)
                kSum[uiK] = akQ[uiI0][uiK] + akQ[uiI1][uiK];

            MgcVector3& rkV = m_akVertex[kKey.m_uiI0];

            fMetric =
                rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
                rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
                rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
                      (kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);

            pkHeap->SetAt(kKey,fMetric);
        }

        // edge <I0,I2>
        kKey = KeyType(uiI0,uiI2);
        if ( !pkHeap->GetAt(kKey,fMetric) )
        {
            for (uiK = 0; uiK < 10; uiK++)
                kSum[uiK] = akQ[uiI0][uiK] + akQ[uiI2][uiK];

            MgcVector3& rkV = m_akVertex[kKey.m_uiI0];

            fMetric =
                rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
                rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
                rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
                      (kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);

            pkHeap->SetAt(kKey,fMetric);
        }

        // edge <I1,I2>
        kKey = KeyType(uiI1,uiI2);
        if ( !pkHeap->GetAt(kKey,fMetric) )
        {
            for (uiK = 0; uiK < 10; uiK++)
                kSum[uiK] = akQ[uiI1][uiK] + akQ[uiI2][uiK];

            MgcVector3& rkV = m_akVertex[kKey.m_uiI0];

            fMetric =
                rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
                rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
                rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
                      (kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);

            pkHeap->SetAt(kKey,fMetric);
        }
    }

    return pkHeap;
}
//----------------------------------------------------------------------------
bool MgcCLodMesh::TriangleContainsEdge (unsigned int uiT, unsigned int uiI0,
    unsigned int uiI1)
{
    unsigned int uiK = 3*uiT;
    unsigned int uiJ0 = m_auiConnect[uiK++];
    unsigned int uiJ1 = m_auiConnect[uiK++];
    unsigned int uiJ2 = m_auiConnect[uiK];

    return ((uiJ0 == uiI0 && uiJ1 == uiI1) || (uiJ0 == uiI1 && uiJ1 == uiI0))
        || ((uiJ0 == uiI0 && uiJ2 == uiI1) || (uiJ0 == uiI1 && uiJ2 == uiI0))
        || ((uiJ1 == uiI0 && uiJ2 == uiI1) || (uiJ1 == uiI1 && uiJ2 == uiI0));
}
//----------------------------------------------------------------------------
void MgcCLodMesh::MoveTrianglesToEnd ()
{
    Record& rkRecord = m_akRecord[m_iCurrentRecord];
    unsigned int uiQuantity;
    if ( m_iCurrentRecord > 0 )
        uiQuantity = m_akRecord[m_iCurrentRecord-1].m_uiTriangleQuantity;
    else
        uiQuantity = m_uiTriangleQuantity;

    // Repack connectivity into two subsets, the first corresponding to those
    // triangles not containing the removed edge and the second corresponding
    // to those triangles containing the removed edge.
    unsigned int* auiIndex = new unsigned int[3*uiQuantity];
    unsigned int uiI;
    for (uiI = 0; uiI < 3*uiQuantity; uiI++)
        auiIndex[uiI] = uiI;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -