📄 opc_sweepandprune.cpp
字号:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains an implementation of the sweep-and-prune algorithm (moved from Z-Collide)
* \file OPC_SweepAndPrune.cpp
* \author Pierre Terdiman
* \date January, 29, 2000
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Opcode/Stdafx.h"
using namespace Opcode;
inline_ void Sort(udword& id0, udword& id1)
{
if(id0>id1) Swap(id0, id1);
}
class Opcode::SAP_Element
{
public:
inline_ SAP_Element() {}
inline_ SAP_Element(udword id, SAP_Element* next) : mID(id), mNext(next) {}
inline_ ~SAP_Element() {}
udword mID;
SAP_Element* mNext;
};
class Opcode::SAP_Box
{
public:
SAP_EndPoint* Min[3];
SAP_EndPoint* Max[3];
};
class Opcode::SAP_EndPoint
{
public:
float Value; // Min or Max value
SAP_EndPoint* Previous; // Previous EndPoint whose Value is smaller than ours (or null)
SAP_EndPoint* Next; // Next EndPoint whose Value is greater than ours (or null)
udword Data; // Parent box ID *2 | MinMax flag
inline_ void SetData(udword box_id, BOOL is_max) { Data = (box_id<<1)|is_max; }
inline_ BOOL IsMax() const { return Data & 1; }
inline_ udword GetBoxID() const { return Data>>1; }
inline_ void InsertAfter(SAP_EndPoint* element)
{
if(this!=element && this!=element->Next)
{
// Remove
if(Previous) Previous->Next = Next;
if(Next) Next->Previous = Previous;
// Insert
Next = element->Next;
if(Next) Next->Previous = this;
element->Next = this;
Previous = element;
}
}
inline_ void InsertBefore(SAP_EndPoint* element)
{
if(this!=element && this!=element->Previous)
{
// Remove
if(Previous) Previous->Next = Next;
if(Next) Next->Previous = Previous;
// Insert
Previous = element->Previous;
element->Previous = this;
Next = element;
if(Previous) Previous->Next = this;
}
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SAP_PairData::SAP_PairData() :
mNbElements (0),
mNbUsedElements (0),
mElementPool (null),
mFirstFree (null),
mNbObjects (0),
mArray (null)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Destructor.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SAP_PairData::~SAP_PairData()
{
Release();
}
void SAP_PairData::Release()
{
mNbElements = 0;
mNbUsedElements = 0;
mNbObjects = 0;
DELETEARRAY(mElementPool);
DELETEARRAY(mArray);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes.
* \param nb_objects [in]
* \return true if success
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool SAP_PairData::Init(udword nb_objects)
{
// Make sure everything has been released
Release();
if(!nb_objects) return false;
mArray = new SAP_Element*[nb_objects];
CHECKALLOC(mArray);
ZeroMemory(mArray, nb_objects*sizeof(SAP_Element*));
mNbObjects = nb_objects;
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Remaps a pointer when pool gets resized.
* \param element [in/out] remapped element
* \param delta [in] offset in bytes
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void Remap(SAP_Element*& element, udword delta)
{
if(element) element = (SAP_Element*)(udword(element) + delta);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets a free element in the pool.
* \param id [in] element id
* \param next [in] next element
* \param remap [out] possible remapping offset
* \return the new element
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SAP_Element* SAP_PairData::GetFreeElem(udword id, SAP_Element* next, udword* remap)
{
if(remap) *remap = 0;
SAP_Element* FreeElem;
if(mFirstFree)
{
// Recycle
FreeElem = mFirstFree;
mFirstFree = mFirstFree->mNext; // First free = next free (or null)
}
else
{
if(mNbUsedElements==mNbElements)
{
// Resize
mNbElements = mNbElements ? (mNbElements<<1) : 2;
SAP_Element* NewElems = new SAP_Element[mNbElements];
if(mNbUsedElements) CopyMemory(NewElems, mElementPool, mNbUsedElements*sizeof(SAP_Element));
// Remap everything
{
udword Delta = udword(NewElems) - udword(mElementPool);
for(udword i=0;i<mNbUsedElements;i++) Remap(NewElems[i].mNext, Delta);
for(udword i=0;i<mNbObjects;i++) Remap(mArray[i], Delta);
Remap(mFirstFree, Delta);
Remap(next, Delta);
if(remap) *remap = Delta;
}
DELETEARRAY(mElementPool);
mElementPool = NewElems;
}
FreeElem = &mElementPool[mNbUsedElements++];
}
FreeElem->mID = id;
FreeElem->mNext = next;
return FreeElem;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Frees an element of the pool.
* \param elem [in] element to free/recycle
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SAP_PairData::FreeElem(SAP_Element* elem)
{
elem->mNext = mFirstFree; // Next free
mFirstFree = elem;
}
// Add a pair to the set.
void SAP_PairData::AddPair(udword id1, udword id2)
{
// Order the ids
Sort(id1, id2);
ASSERT(id1<mNbObjects);
if(id1>=mNbObjects) return;
// Select the right list from "mArray".
SAP_Element* Current = mArray[id1];
if(!Current)
{
// Empty slot => create new element
mArray[id1] = GetFreeElem(id2, null);
}
else if(Current->mID>id2)
{
// The list is not empty but all elements are greater than id2 => insert id2 in the front.
mArray[id1] = GetFreeElem(id2, mArray[id1]);
}
else
{
// Else find the correct location in the sorted list (ascending order) and insert id2 there.
while(Current->mNext)
{
if(Current->mNext->mID > id2) break;
Current = Current->mNext;
}
if(Current->mID==id2) return; // The pair already exists
// Current->mNext = GetFreeElem(id2, Current->mNext);
udword Delta;
SAP_Element* E = GetFreeElem(id2, Current->mNext, &Delta);
if(Delta) Remap(Current, Delta);
Current->mNext = E;
}
}
// Delete a pair from the set.
void SAP_PairData::RemovePair(udword id1, udword id2)
{
// Order the ids.
Sort(id1, id2);
// Exit if the pair doesn't exist in the set
if(id1>=mNbObjects) return;
// Otherwise, select the correct list.
SAP_Element* Current = mArray[id1];
// If this list is empty, the pair doesn't exist.
if(!Current) return;
// Otherwise, if id2 is the first element, delete it.
if(Current->mID==id2)
{
mArray[id1] = Current->mNext;
FreeElem(Current);
}
else
{
// If id2 is not the first element, start traversing the sorted list.
while(Current->mNext)
{
// If we have moved too far away without hitting id2, then the pair doesn't exist
if(Current->mNext->mID > id2) return;
// Otherwise, delete id2.
if(Current->mNext->mID == id2)
{
SAP_Element* Temp = Current->mNext;
Current->mNext = Temp->mNext;
FreeElem(Temp);
return;
}
Current = Current->mNext;
}
}
}
void SAP_PairData::DumpPairs(Pairs& pairs) const
{
// ### Ugly and slow
for(udword i=0;i<mNbObjects;i++)
{
SAP_Element* Current = mArray[i];
while(Current)
{
ASSERT(Current->mID<mNbObjects);
pairs.AddPair(i, Current->mID);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -