Beispiel #1
0
bool HybridModel::Build(const OPCODECREATE& create)
{
    // 1) Checkings
    if(!create.mIMesh || !create.mIMesh->IsValid())	return false;

    // Look for degenerate faces.
    udword NbDegenerate = create.mIMesh->CheckTopology();
    if(NbDegenerate)	OpcodeLog("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
    // We continue nonetheless....

    Release();	// Make sure previous tree has been discarded

    // 1-1) Setup mesh interface automatically
    SetMeshInterface(create.mIMesh);

    bool Status = false;
    AABBTree* LeafTree = null;
    Internal Data;

    // 2) Build a generic AABB Tree.
    mSource = new AABBTree;
    CHECKALLOC(mSource);

    // 2-1) Setup a builder. Our primitives here are triangles from input mesh,
    // so we use an AABBTreeOfTrianglesBuilder.....
    {
        AABBTreeOfTrianglesBuilder TB;
        TB.mIMesh			= create.mIMesh;
        TB.mNbPrimitives	= create.mIMesh->GetNbTriangles();
        TB.mSettings		= create.mSettings;
        TB.mSettings.mLimit	= 16;	// ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
        if(!mSource->Build(&TB))	goto FreeAndExit;
    }

    // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
    struct Local
    {
        // A callback to count leaf nodes
        static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
        {
            if(current->IsLeaf())
            {
                Internal* Data = (Internal*)user_data;
                Data->mNbLeaves++;
            }
            return true;
        }

        // A callback to setup leaf nodes in our internal structures
        static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
        {
            if(current->IsLeaf())
            {
                Internal* Data = (Internal*)user_data;

                // Get current leaf's box
                Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();

                // Setup leaf data
                udword Index = (size_t(current->GetPrimitives()) - size_t(Data->mBase)) / sizeof(size_t);
                Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);

                Data->mNbLeaves++;
            }
            return true;
        }
    };

    // Walk the tree & count number of leaves
    Data.mNbLeaves = 0;
    mSource->Walk(Local::CountLeaves, &Data);
    mNbLeaves = Data.mNbLeaves;	// Keep track of it

    // Special case for 1-leaf meshes
    if(mNbLeaves==1)
    {
        mModelCode |= OPC_SINGLE_NODE;
        Status = true;
        goto FreeAndExit;
    }

    // Allocate our structures
    Data.mLeaves = new IceMaths::AABB[Data.mNbLeaves];
    CHECKALLOC(Data.mLeaves);
    mTriangles = new LeafTriangles[Data.mNbLeaves];
    CHECKALLOC(mTriangles);

    // Walk the tree again & setup leaf data
    Data.mTriangles	= mTriangles;
    Data.mBase		= mSource->GetIndices();
    Data.mNbLeaves	= 0;	// Reset for incoming walk
    mSource->Walk(Local::SetupLeafData, &Data);

    // Handle source indices
    {
        bool MustKeepIndices = true;
        if(create.mCanRemap)
        {
            // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
            // Remap can fail when we use callbacks => keep track of indices in that case (it still
            // works, only using more memory)
            if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
            {
                MustKeepIndices = false;
            }
        }

        if(MustKeepIndices)
        {
            // Keep track of source indices (from vanilla tree)
            mNbPrimitives = mSource->GetNbPrimitives();
            mIndices = new udword[mNbPrimitives];
            CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
        }
    }

    // Now, create our optimized tree using previous leaf nodes
    LeafTree = new AABBTree;
    CHECKALLOC(LeafTree);
    {
        AABBTreeOfAABBsBuilder TB;	// Now using boxes !
        TB.mSettings		= create.mSettings;
        TB.mSettings.mLimit	= 1;	// We now want a complete tree so that we can "optimize" it
        TB.mNbPrimitives	= Data.mNbLeaves;
        TB.mAABBArray		= Data.mLeaves;
        if(!LeafTree->Build(&TB))	goto FreeAndExit;
    }

    // 3) Create an optimized tree according to user-settings
    if(!CreateTree(create.mNoLeaf, create.mQuantized))	goto FreeAndExit;

    // 3-2) Create optimized tree
    if(!mTree->Build(LeafTree))	goto FreeAndExit;

    // Finally ok...
    Status = true;

FreeAndExit:	// Allow me this one...
    DELETESINGLE(LeafTree);

    // 3-3) Delete generic tree if needed
    if(!create.mKeepOriginal)	DELETESINGLE(mSource);

    return Status;
}