bluecore/ode/OPCODE/OPC_Model.cpp

223 lines
8.4 KiB
C++

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code for OPCODE models.
* \file OPC_Model.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* The main collision wrapper, for all trees. Supported trees are:
* - Normal trees (2*N-1 nodes, full size)
* - No-leaf trees (N-1 nodes, full size)
* - Quantized trees (2*N-1 nodes, half size)
* - Quantized no-leaf trees (N-1 nodes, half size)
*
* Usage:
*
* 1) Create a static mesh interface using callbacks or pointers. (see OPC_MeshInterface.cpp).
* Keep it around in your app, since a pointer to this interface is saved internally and
* used until you release the collision structures.
*
* 2) Build a Model using a creation structure:
*
* \code
* Model Sample;
*
* OPCODECREATE OPCC;
* OPCC.IMesh = ...;
* OPCC.Rules = ...;
* OPCC.NoLeaf = ...;
* OPCC.Quantized = ...;
* OPCC.KeepOriginal = ...;
* bool Status = Sample.Build(OPCC);
* \endcode
*
* 3) Create a tree collider and set it up:
*
* \code
* AABBTreeCollider TC;
* TC.SetFirstContact(...);
* TC.SetFullBoxBoxTest(...);
* TC.SetFullPrimBoxTest(...);
* TC.SetTemporalCoherence(...);
* \endcode
*
* 4) Perform a collision query
*
* \code
* // Setup cache
* static BVTCache ColCache;
* ColCache.Model0 = &Model0;
* ColCache.Model1 = &Model1;
*
* // Collision query
* bool IsOk = TC.Collide(ColCache, World0, World1);
*
* // Get collision status => if true, objects overlap
* BOOL Status = TC.GetContactStatus();
*
* // Number of colliding pairs and list of pairs
* udword NbPairs = TC.GetNbPairs();
* const Pair* p = TC.GetPairs()
* \endcode
*
* 5) Stats
*
* \code
* Model0.GetUsedBytes() = number of bytes used for this collision tree
* TC.GetNbBVBVTests() = number of BV-BV overlap tests performed during last query
* TC.GetNbPrimPrimTests() = number of Triangle-Triangle overlap tests performed during last query
* TC.GetNbBVPrimTests() = number of Triangle-BV overlap tests performed during last query
* \endcode
*
* \class Model
* \author Pierre Terdiman
* \version 1.3
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::Model()
{
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
mHull = null;
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Model::~Model()
{
Release();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Releases the model.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Model::Release()
{
ReleaseBase();
#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE !
DELETESINGLE(mHull);
#endif // __MESHMERIZER_H__
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Builds a collision model.
* \param create [in] model creation structure
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Model::Build(const OPCODECREATE& create)
{
// 1) Checkings
if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
// For this model, we only support complete trees
if(create.mSettings.mLimit!=1) return SetIceError("OPCODE WARNING: supports complete trees only! Use mLimit = 1.\n", null);
// Look for degenerate faces.
udword NbDegenerate = create.mIMesh->CheckTopology();
if(NbDegenerate) Log("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 [Opcode 1.3, thanks Adam]
// 1-1) Setup mesh interface automatically [Opcode 1.3]
SetMeshInterface(create.mIMesh);
// Special case for 1-triangle meshes [Opcode 1.3]
udword NbTris = create.mIMesh->GetNbTriangles();
if(NbTris==1)
{
// We don't need to actually create a tree here, since we'll only have a single triangle to deal with anyway.
// It's a waste to use a "model" for this but at least it will work.
mModelCode |= OPC_SINGLE_NODE;
return true;
}
// 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.mSettings = create.mSettings;
TB.mNbPrimitives = NbTris;
if(!mSource->Build(&TB)) return false;
}
// 3) Create an optimized tree according to user-settings
if(!CreateTree(create.mNoLeaf, create.mQuantized)) return false;
// 3-2) Create optimized tree
if(!mTree->Build(mSource)) return false;
// 3-3) Delete generic tree if needed
if(!create.mKeepOriginal) DELETESINGLE(mSource);
#ifdef __MESHMERIZER_H__
// 4) Convex hull
if(create.mCollisionHull)
{
// Create hull
mHull = new CollisionHull;
CHECKALLOC(mHull);
CONVEXHULLCREATE CHC;
// ### doesn't work with strides
CHC.NbVerts = create.mIMesh->GetNbVertices();
CHC.Vertices = create.mIMesh->GetVerts();
CHC.UnifyNormals = true;
CHC.ReduceVertices = true;
CHC.WordFaces = false;
mHull->Compute(CHC);
}
#endif // __MESHMERIZER_H__
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the number of bytes used by the tree.
* \return amount of bytes used
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
udword Model::GetUsedBytes() const
{
if(!mTree) return 0;
return mTree->GetUsedBytes();
}