Updated CDTestFramework with the OPCODE Array SAP test.
Thanks Pierre Terdiman for the latest update.
This commit is contained in:
@@ -1,20 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains AABB-related code. (axis-aligned bounding box)
|
||||
@@ -26,8 +9,20 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEAABB_H__
|
||||
#define __ICEAABB_H__
|
||||
#ifndef ICEAABB_H
|
||||
#define ICEAABB_H
|
||||
|
||||
inline_ void ComputeMinMax(const Point& p, Point& min, Point& max)
|
||||
{
|
||||
if(p.x > max.x) max.x = p.x;
|
||||
if(p.x < min.x) min.x = p.x;
|
||||
|
||||
if(p.y > max.y) max.y = p.y;
|
||||
if(p.y < min.y) min.y = p.y;
|
||||
|
||||
if(p.z > max.z) max.z = p.z;
|
||||
if(p.z < min.z) min.z = p.z;
|
||||
}
|
||||
|
||||
// Forward declarations
|
||||
class Sphere;
|
||||
@@ -35,6 +30,7 @@ subject to the following restrictions:
|
||||
//! Declarations of type-independent methods (most of them implemented in the .cpp)
|
||||
#define AABB_COMMON_METHODS \
|
||||
AABB& Add(const AABB& aabb); \
|
||||
AABB& Sub(const AABB& aabb); \
|
||||
float MakeCube(AABB& cube) const; \
|
||||
void MakeSphere(Sphere& sphere) const; \
|
||||
const sbyte* ComputeOutline(const Point& local_eye, sdword& num) const; \
|
||||
@@ -69,7 +65,7 @@ subject to the following restrictions:
|
||||
Point mMax;
|
||||
};
|
||||
|
||||
class ICEMATHS_API AABB
|
||||
class ICEMATHS_API AABB : public Allocateable
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
@@ -126,17 +122,8 @@ subject to the following restrictions:
|
||||
* \param p [in] the next point
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Extend(const Point& p)
|
||||
{
|
||||
if(p.x > mMax.x) mMax.x = p.x;
|
||||
if(p.x < mMin.x) mMin.x = p.x;
|
||||
inline_ void Extend(const Point& p) { ComputeMinMax(p, mMin, mMax); }
|
||||
|
||||
if(p.y > mMax.y) mMax.y = p.y;
|
||||
if(p.y < mMin.y) mMin.y = p.y;
|
||||
|
||||
if(p.z > mMax.z) mMax.z = p.z;
|
||||
if(p.z < mMin.z) mMin.z = p.z;
|
||||
}
|
||||
// Data access
|
||||
|
||||
//! Get min point of the box
|
||||
@@ -492,18 +479,7 @@ subject to the following restrictions:
|
||||
|
||||
#endif
|
||||
|
||||
inline_ void ComputeMinMax(const Point& p, Point& min, Point& max)
|
||||
{
|
||||
if(p.x > max.x) max.x = p.x;
|
||||
if(p.x < min.x) min.x = p.x;
|
||||
|
||||
if(p.y > max.y) max.y = p.y;
|
||||
if(p.y < min.y) min.y = p.y;
|
||||
|
||||
if(p.z > max.z) max.z = p.z;
|
||||
if(p.z < min.z) min.z = p.z;
|
||||
}
|
||||
|
||||
//! Computes the AABB around a set of vertices
|
||||
inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts)
|
||||
{
|
||||
if(list)
|
||||
@@ -519,4 +495,20 @@ subject to the following restrictions:
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __ICEAABB_H__
|
||||
//! Computes the AABB around a set of vertices after transform by a matrix
|
||||
inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts, const Matrix4x4& world)
|
||||
{
|
||||
if(list)
|
||||
{
|
||||
Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
|
||||
Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT);
|
||||
while(nb_pts--)
|
||||
{
|
||||
// _prefetch(list+1); // off by one ?
|
||||
ComputeMinMax((*list++)*world, Mini, Maxi);
|
||||
}
|
||||
aabb.SetMinMax(Mini, Maxi);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ICEAABB_H
|
||||
|
||||
805
Extras/CDTestFramework/Opcode/Ice/IceAllocator.cpp
Normal file
805
Extras/CDTestFramework/Opcode/Ice/IceAllocator.cpp
Normal file
@@ -0,0 +1,805 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains an allocator base class.
|
||||
* \file IceAllocator.cpp
|
||||
* \author Pierre Terdiman
|
||||
* \date December, 19, 2003
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "StdAfx.h"
|
||||
#include <malloc.h>
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
//#define ZERO_OVERHEAD_RELEASE
|
||||
#define NEW_CODE
|
||||
// For some reason dmalloc seems a lot slower than the system malloc?
|
||||
//#define USE_DMALLOC
|
||||
|
||||
#ifdef USE_DMALLOC
|
||||
#include "dmalloc.h"
|
||||
#define LOCAL_MALLOC dlmalloc
|
||||
#define LOCAL_FREE dlfree
|
||||
#else
|
||||
#define LOCAL_MALLOC ::malloc
|
||||
#define LOCAL_FREE ::free
|
||||
#endif
|
||||
|
||||
|
||||
// WARNING: this makes allocations a lot slower. Only use when tracking memory leaks.
|
||||
//#define ALLOC_STRINGS
|
||||
|
||||
// ### doesn't seem that useful
|
||||
//#define FAST_BUFFER_SIZE 256*1024
|
||||
|
||||
#define DEBUG_IDENTIFIER 0xBeefBabe
|
||||
#define DEBUG_DEALLOCATED 0xDeadDead
|
||||
|
||||
#ifdef ALLOC_STRINGS
|
||||
static const char* AllocString(const char* str)
|
||||
{
|
||||
if(!str) return null;
|
||||
char* mem = (char*)LOCAL_MALLOC(strlen(str)+1);
|
||||
strcpy(mem, str);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void FreeString(const char* str)
|
||||
{
|
||||
if(str) LOCAL_FREE((void*)str);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class DefaultAllocator : public Allocator
|
||||
{
|
||||
public:
|
||||
DefaultAllocator();
|
||||
virtual ~DefaultAllocator();
|
||||
|
||||
void reset();
|
||||
|
||||
override(Allocator) void* malloc(size_t size, MemoryType type);
|
||||
override(Allocator) void* mallocDebug(size_t size, const char* filename, udword line, const char* class_name, MemoryType type);
|
||||
override(Allocator) void* realloc(void* memory, size_t size);
|
||||
override(Allocator) void* shrink(void* memory, size_t size);
|
||||
override(Allocator) void free(void* memory);
|
||||
|
||||
void DumpCurrentMemoryState() const;
|
||||
|
||||
void** mMemBlockList;
|
||||
udword mMemBlockListSize;
|
||||
#ifdef NEW_CODE
|
||||
udword mFirstFree;
|
||||
#else
|
||||
udword mMemBlockFirstFree;
|
||||
#endif
|
||||
udword mMemBlockUsed;
|
||||
|
||||
sdword mNbAllocatedBytes;
|
||||
sdword mHighWaterMark;
|
||||
sdword mTotalNbAllocs;
|
||||
sdword mNbAllocs;
|
||||
sdword mNbReallocs;
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
udword mNbFastBytes;
|
||||
udword mFastBufferOffset;
|
||||
ubyte* mFastBuffer;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MEMBLOCKSTART 64
|
||||
|
||||
struct DebugBlock
|
||||
{
|
||||
udword mCheckValue;
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
MemoryType mType;
|
||||
#endif
|
||||
udword mSize;
|
||||
const char* mFilename;
|
||||
udword mLine;
|
||||
udword mSlotIndex;
|
||||
const char* mClassName;
|
||||
};
|
||||
|
||||
#ifndef FAST_BUFFER_SIZE
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(DebugBlock)==24); // Prevents surprises.....
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DefaultAllocator::DefaultAllocator() : mNbAllocatedBytes(0), mHighWaterMark(0), mTotalNbAllocs(0), mNbAllocs(0), mNbReallocs(0)
|
||||
{
|
||||
mMemBlockList = null;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Initialize the Memory blocks list (DEBUG mode only)
|
||||
mMemBlockList = (void**)LOCAL_MALLOC(MEMBLOCKSTART*sizeof(void*));
|
||||
ZeroMemory(mMemBlockList, MEMBLOCKSTART*sizeof(void*));
|
||||
mMemBlockListSize = MEMBLOCKSTART;
|
||||
#ifdef NEW_CODE
|
||||
mFirstFree = INVALID_ID;
|
||||
#else
|
||||
mMemBlockFirstFree = 0;
|
||||
#endif
|
||||
mMemBlockUsed = 0;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
mNbFastBytes = 0;
|
||||
mFastBufferOffset = 0;
|
||||
mFastBuffer = (ubyte*)LOCAL_MALLOC(FAST_BUFFER_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DefaultAllocator::~DefaultAllocator()
|
||||
{
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
mNbFastBytes = 0;
|
||||
mFastBufferOffset = 0;
|
||||
if(mFastBuffer) LOCAL_FREE(mFastBuffer);
|
||||
mFastBuffer = null;
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
// Ok, it is a bad idea to use _F() here, because it internally uses the allocator (for the log string). So let's use good old C style here.
|
||||
char Buffer[4096];
|
||||
|
||||
if(mNbAllocatedBytes)
|
||||
{
|
||||
sprintf(Buffer, "Memory leak detected: %d bytes non released\n", mNbAllocatedBytes);
|
||||
// IceTrace(Buffer);
|
||||
// IceTrace(_F("Memory leak detected: %d bytes non released\n", mNbAllocatedBytes));
|
||||
}
|
||||
if(mNbAllocs)
|
||||
{
|
||||
sprintf(Buffer, "Remaining allocs: %d\n", mNbAllocs);
|
||||
// IceTrace(Buffer);
|
||||
// IceTrace(_F("Remaining allocs: %d\n", mNbAllocs));
|
||||
}
|
||||
// IceTrace(_F("Nb alloc: %d\n", mTotalNbAllocs));
|
||||
sprintf(Buffer, "Total nb alloc: %d\n", mTotalNbAllocs);
|
||||
// IceTrace(Buffer);
|
||||
|
||||
// IceTrace(_F("Nb realloc: %d\n", mNbReallocs));
|
||||
sprintf(Buffer, "Nb realloc: %d\n", mNbReallocs);
|
||||
// IceTrace(Buffer);
|
||||
|
||||
// IceTrace(_F("High water mark: %d Kb\n", mHighWaterMark/1024));
|
||||
sprintf(Buffer, "High water mark: %d Kb\n", mHighWaterMark/1024);
|
||||
// IceTrace(Buffer);
|
||||
|
||||
// Scanning for memory leaks
|
||||
if(mMemBlockList && mNbAllocs)
|
||||
{
|
||||
udword NbLeaks = 0;
|
||||
// IceTrace("\n\n ICE Message Memory leaks detected :\n\n");
|
||||
|
||||
#ifdef NEW_CODE
|
||||
for(udword i=0; i<mMemBlockUsed; i++)
|
||||
{
|
||||
if(udword(mMemBlockList[i])&1)
|
||||
continue;
|
||||
|
||||
const DebugBlock* DB = (const DebugBlock*)mMemBlockList[i];
|
||||
// IceTrace(_F(" Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", cur+6, cur[1], (const char*)cur[5], (const char*)cur[2], cur[3]));
|
||||
// IceTrace(_F(" Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", DB+1, DB->mSize, DB->mClassName, DB->mFilename, DB->mLine));
|
||||
sprintf(Buffer, " Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", DB+1, DB->mSize, DB->mClassName, DB->mFilename, DB->mLine);
|
||||
// IceTrace(Buffer);
|
||||
|
||||
NbLeaks++;
|
||||
// Free(cur+4);
|
||||
}
|
||||
#else
|
||||
for(udword i=0, j=0; i<mMemBlockUsed; i++, j++)
|
||||
{
|
||||
// Skip empty slots
|
||||
while(!mMemBlockList[j]) j++;
|
||||
|
||||
const DebugBlock* DB = (const DebugBlock*)mMemBlockList[j];
|
||||
// IceTrace(_F(" Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", cur+6, cur[1], (const char*)cur[5], (const char*)cur[2], cur[3]));
|
||||
// IceTrace(_F(" Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", DB+1, DB->mSize, DB->mClassName, DB->mFilename, DB->mLine));
|
||||
sprintf(Buffer, " Address 0x%.8X, %d bytes (%s), allocated in: %s(%d):\n\n", DB+1, DB->mSize, DB->mClassName, DB->mFilename, DB->mLine);
|
||||
IceTrace(Buffer);
|
||||
|
||||
NbLeaks++;
|
||||
// Free(cur+4);
|
||||
}
|
||||
#endif
|
||||
// IceTrace(_F("\n Dump complete (%d leaks)\n\n", NbLeaks));
|
||||
sprintf(Buffer, "\n Dump complete (%d leaks)\n\n", NbLeaks);
|
||||
// IceTrace(Buffer);
|
||||
}
|
||||
// Free the Memory Block list
|
||||
if(mMemBlockList) LOCAL_FREE(mMemBlockList);
|
||||
mMemBlockList = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DefaultAllocator::reset()
|
||||
{
|
||||
mNbAllocatedBytes = 0;
|
||||
mHighWaterMark = 0;
|
||||
mNbAllocs = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* DefaultAllocator::malloc(udword size, MemoryType type)
|
||||
{
|
||||
// return ::malloc(size);
|
||||
|
||||
#ifdef _DEBUG
|
||||
return mallocDebug(size, null, 0, "Undefined", type);
|
||||
#endif
|
||||
|
||||
if(!size)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// IceTrace("Warning: trying to allocate 0 bytes\n");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
mTotalNbAllocs++;
|
||||
mNbAllocs++;
|
||||
|
||||
mNbAllocatedBytes+=size;
|
||||
if(mNbAllocatedBytes>mHighWaterMark) mHighWaterMark = mNbAllocatedBytes;
|
||||
|
||||
#ifdef ZERO_OVERHEAD_RELEASE
|
||||
return LOCAL_MALLOC(size);
|
||||
#else
|
||||
void* ptr = (void*)LOCAL_MALLOC(size+8);
|
||||
udword* blockStart = (udword*)ptr;
|
||||
blockStart[0] = DEBUG_IDENTIFIER;
|
||||
blockStart[1] = size;
|
||||
return ((udword*)ptr)+2;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* DefaultAllocator::mallocDebug(size_t size, const char* filename, udword line, const char* class_name, MemoryType type)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if(!size)
|
||||
{
|
||||
// IceTrace("Warning: trying to allocate 0 bytes\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Catch improper use of alloc macro...
|
||||
if(0 && class_name)
|
||||
{
|
||||
const char* c = class_name;
|
||||
while(*c)
|
||||
{
|
||||
if(*c==']' || *c=='[')
|
||||
{
|
||||
int stop=0;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure size is even
|
||||
if(size&1) size++;
|
||||
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
// Allocate one debug block in front of each real allocation
|
||||
void* ptr = null;
|
||||
if(type==MEMORY_TEMP)
|
||||
{
|
||||
udword NeededSize = size + sizeof(DebugBlock);
|
||||
if(mFastBufferOffset + NeededSize <= FAST_BUFFER_SIZE)
|
||||
{
|
||||
ptr = mFastBuffer + mFastBufferOffset;
|
||||
mFastBufferOffset += NeededSize;
|
||||
mNbFastBytes += NeededSize;
|
||||
}
|
||||
}
|
||||
|
||||
if(!ptr)
|
||||
{
|
||||
ptr = (void*)LOCAL_MALLOC(size + sizeof(DebugBlock));
|
||||
type = MEMORY_PERSISTENT;
|
||||
}
|
||||
#else
|
||||
// Allocate one debug block in front of each real allocation
|
||||
void* ptr = (void*)LOCAL_MALLOC(size + sizeof(DebugBlock));
|
||||
#endif
|
||||
ASSERT(IS_ALIGNED_2(udword(ptr)));
|
||||
|
||||
// Fill debug block
|
||||
DebugBlock* DB = (DebugBlock*)ptr;
|
||||
DB->mCheckValue = DEBUG_IDENTIFIER;
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
DB->mType = type;
|
||||
#endif
|
||||
DB->mSize = size;
|
||||
DB->mLine = line;
|
||||
DB->mSlotIndex = INVALID_ID;
|
||||
#ifdef ALLOC_STRINGS
|
||||
DB->mFilename = AllocString(filename);
|
||||
DB->mClassName = AllocString(class_name);
|
||||
#else
|
||||
DB->mFilename = filename;
|
||||
DB->mClassName = class_name;
|
||||
#endif
|
||||
|
||||
// Update global stats
|
||||
mTotalNbAllocs++;
|
||||
mNbAllocs++;
|
||||
mNbAllocatedBytes += size;
|
||||
if(mNbAllocatedBytes>mHighWaterMark)
|
||||
mHighWaterMark = mNbAllocatedBytes;
|
||||
|
||||
// Insert the allocated block in the debug memory block list
|
||||
if(mMemBlockList)
|
||||
{
|
||||
#ifdef NEW_CODE
|
||||
if(mFirstFree!=INVALID_ID)
|
||||
{
|
||||
// Recycle old location
|
||||
|
||||
udword NextFree = udword(mMemBlockList[mFirstFree]);
|
||||
if(NextFree!=INVALID_ID) NextFree>>=1;
|
||||
|
||||
mMemBlockList[mFirstFree] = ptr;
|
||||
DB->mSlotIndex = mFirstFree;
|
||||
|
||||
mFirstFree = NextFree;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mMemBlockUsed==mMemBlockListSize)
|
||||
{
|
||||
// Allocate a bigger block
|
||||
void** tps = (void**)LOCAL_MALLOC((mMemBlockListSize+MEMBLOCKSTART)*sizeof(void*));
|
||||
// Copy already used part
|
||||
CopyMemory(tps, mMemBlockList, mMemBlockListSize*sizeof(void*));
|
||||
// Initialize remaining part
|
||||
void* Next = tps + mMemBlockListSize;
|
||||
ZeroMemory(Next, MEMBLOCKSTART*sizeof(void*));
|
||||
|
||||
// Free previous memory, setup new pointer
|
||||
LOCAL_FREE(mMemBlockList);
|
||||
mMemBlockList = tps;
|
||||
// Setup new size
|
||||
mMemBlockListSize += MEMBLOCKSTART;
|
||||
}
|
||||
|
||||
mMemBlockList[mMemBlockUsed] = ptr;
|
||||
DB->mSlotIndex = mMemBlockUsed++;
|
||||
}
|
||||
#else
|
||||
// Store allocated pointer in first free slot
|
||||
mMemBlockList[mMemBlockFirstFree] = ptr;
|
||||
DB->mSlotIndex = mMemBlockFirstFree;
|
||||
|
||||
// Count number of used slots
|
||||
mMemBlockUsed++;
|
||||
|
||||
// Resize if needed
|
||||
if(mMemBlockUsed==mMemBlockListSize)
|
||||
{
|
||||
// Allocate a bigger block
|
||||
void** tps = (void**)LOCAL_MALLOC((mMemBlockListSize+MEMBLOCKSTART)*sizeof(void*));
|
||||
// Copy already used part
|
||||
CopyMemory(tps, mMemBlockList, mMemBlockListSize*sizeof(void*));
|
||||
// Initialize remaining part
|
||||
void* Next = tps + mMemBlockListSize;
|
||||
ZeroMemory(Next, MEMBLOCKSTART*sizeof(void*));
|
||||
|
||||
// Free previous memory, setup new pointer
|
||||
LOCAL_FREE(mMemBlockList);
|
||||
mMemBlockList = tps;
|
||||
// -1 because we'll do a ++ just afterwards
|
||||
mMemBlockFirstFree = mMemBlockListSize-1;
|
||||
// Setup new size
|
||||
mMemBlockListSize += MEMBLOCKSTART;
|
||||
}
|
||||
|
||||
// Look for first free ### recode this ugly thing
|
||||
while(mMemBlockList[++mMemBlockFirstFree] && (mMemBlockFirstFree<mMemBlockListSize));
|
||||
if(mMemBlockFirstFree==mMemBlockListSize)
|
||||
{
|
||||
mMemBlockFirstFree = (udword)-1;
|
||||
while(mMemBlockList[++mMemBlockFirstFree] && (mMemBlockFirstFree<mMemBlockListSize));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ((ubyte*)ptr) + sizeof(DebugBlock);
|
||||
#else
|
||||
Log("Error: mallocDebug has been called in release!\n");
|
||||
ASSERT(0);//Don't use debug malloc for release mode code!
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* DefaultAllocator::shrink(void* memory, udword size)
|
||||
{
|
||||
return null; // #ifdef ZERO_OVERHEAD_RELEASE
|
||||
|
||||
if(!memory) return null;
|
||||
#ifdef _DEBUG
|
||||
// Debug codepath
|
||||
|
||||
ubyte* SystemPointer = ((ubyte*)memory) - sizeof(DebugBlock);
|
||||
|
||||
DebugBlock* DB = (DebugBlock*)SystemPointer;
|
||||
if(DB->mCheckValue!=DEBUG_IDENTIFIER)
|
||||
{
|
||||
// Not a valid memory block
|
||||
return null;
|
||||
}
|
||||
if(size>DB->mSize)
|
||||
{
|
||||
// New size should be smaller!
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to shrink the block
|
||||
void* Reduced = _expand(SystemPointer, size + sizeof(DebugBlock));
|
||||
if(!Reduced) return null;
|
||||
|
||||
if(Reduced!=SystemPointer)
|
||||
{
|
||||
// Should not be possible?!
|
||||
}
|
||||
|
||||
// Update stats
|
||||
mNbAllocatedBytes -= DB->mSize;
|
||||
mNbAllocatedBytes += size;
|
||||
// Setup new size
|
||||
DB->mSize = size;
|
||||
|
||||
return memory; // The pointer should not have changed!
|
||||
#else
|
||||
// Release codepath
|
||||
udword* SystemPointer = ((udword*)memory)-2;
|
||||
if(SystemPointer[0]!=DEBUG_IDENTIFIER)
|
||||
{
|
||||
// Not a valid memory block
|
||||
return null;
|
||||
}
|
||||
if(size>SystemPointer[1])
|
||||
{
|
||||
// New size should be smaller!
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to shrink the block
|
||||
void* Reduced = _expand(SystemPointer, size+8);
|
||||
if(!Reduced) return null;
|
||||
|
||||
if(Reduced!=SystemPointer)
|
||||
{
|
||||
// Should not be possible?!
|
||||
}
|
||||
|
||||
// Update stats
|
||||
mNbAllocatedBytes -= SystemPointer[1];
|
||||
mNbAllocatedBytes += size;
|
||||
// Setup new size
|
||||
SystemPointer[1] = size;
|
||||
|
||||
return memory; // The pointer should not have changed!
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* DefaultAllocator::realloc(void* memory, udword size)
|
||||
{
|
||||
// return ::realloc(memory, size);
|
||||
|
||||
ASSERT(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DefaultAllocator::free(void* memory)
|
||||
{
|
||||
if(!memory)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// IceTrace("Warning: trying to free null pointer\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugBlock* DB = ((DebugBlock*)memory)-1;
|
||||
|
||||
// DebugBlock TmpDB = *DB; // Keep a local copy to have readable data when ::free() fails!
|
||||
|
||||
// Check we allocated it
|
||||
if(DB->mCheckValue!=DEBUG_IDENTIFIER)
|
||||
{
|
||||
// IceTrace("Error: free unknown memory!!\n");
|
||||
// ### should we really continue??
|
||||
return;
|
||||
}
|
||||
|
||||
// Update global stats
|
||||
mNbAllocatedBytes -= DB->mSize;
|
||||
mNbAllocs--;
|
||||
|
||||
#ifdef NEW_CODE
|
||||
// Remove the block from the Memory block list
|
||||
if(mMemBlockList)
|
||||
{
|
||||
udword FreeSlot = DB->mSlotIndex;
|
||||
ASSERT(mMemBlockList[FreeSlot]==DB);
|
||||
|
||||
udword NextFree = mFirstFree;
|
||||
if(NextFree!=INVALID_ID)
|
||||
{
|
||||
NextFree<<=1;
|
||||
NextFree|=1;
|
||||
}
|
||||
|
||||
mMemBlockList[FreeSlot] = (void*)NextFree;
|
||||
mFirstFree = FreeSlot;
|
||||
}
|
||||
#else
|
||||
udword MemBlockFirstFree = DB->mSlotIndex; // The slot we are in
|
||||
udword Line = DB->mLine;
|
||||
const char* File = DB->mFilename;
|
||||
|
||||
// Remove the block from the Memory block list
|
||||
if(mMemBlockList)
|
||||
{
|
||||
ASSERT(mMemBlockList[MemBlockFirstFree]==DB);
|
||||
mMemBlockList[MemBlockFirstFree] = null;
|
||||
mMemBlockUsed--;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ALLOC_STRINGS
|
||||
FreeString(DB->mClassName);
|
||||
FreeString(DB->mFilename);
|
||||
#endif
|
||||
|
||||
#ifdef FAST_BUFFER_SIZE
|
||||
if(DB->mType==MEMORY_TEMP)
|
||||
{
|
||||
mNbFastBytes -= DB->mSize + sizeof(DebugBlock);
|
||||
if(mNbFastBytes==0)
|
||||
{
|
||||
mFastBufferOffset = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ### should be useless since we'll release the memory just afterwards
|
||||
DB->mCheckValue = DEBUG_DEALLOCATED;
|
||||
DB->mSize = 0;
|
||||
DB->mClassName = null;
|
||||
DB->mFilename = null;
|
||||
DB->mSlotIndex = INVALID_ID;
|
||||
DB->mLine = INVALID_ID;
|
||||
|
||||
LOCAL_FREE(DB);
|
||||
#else
|
||||
// Release codepath
|
||||
#ifdef ZERO_OVERHEAD_RELEASE
|
||||
|
||||
// mNbAllocatedBytes -= ptr[1]; // ### use _msize() ?
|
||||
mNbAllocs--;
|
||||
LOCAL_FREE(memory);
|
||||
|
||||
#else
|
||||
|
||||
udword* ptr = ((udword*)memory)-2;
|
||||
if(ptr[0]!=DEBUG_IDENTIFIER)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
IceTrace("Error: free unknown memory!!\n");
|
||||
#endif
|
||||
}
|
||||
mNbAllocatedBytes -= ptr[1];
|
||||
if(mNbAllocatedBytes<0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
IceTrace(_F("Oops (%d)\n", ptr[1]));
|
||||
#endif
|
||||
}
|
||||
mNbAllocs--;
|
||||
ptr[0]=DEBUG_DEALLOCATED;
|
||||
ptr[1]=0;
|
||||
LOCAL_FREE(ptr);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline_ bool ValidAddress(const void* addy)
|
||||
{
|
||||
#ifdef NEW_CODE
|
||||
return (addy && !(udword(addy)&1));
|
||||
#else
|
||||
return addy!=null;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DefaultAllocator::DumpCurrentMemoryState() const
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// Scanning for memory leaks
|
||||
if(mMemBlockList && mMemBlockUsed)
|
||||
{
|
||||
// IceTrace("\n\n----ALLOCATOR MEMORY DUMP:\n\n");
|
||||
|
||||
// We can't just use the "const char*" stored in the debug blocks because they're not guaranteed to
|
||||
// be unique for similar strings. For example if a Container is allocated from two different DLLs,
|
||||
// the "Container" character string will be duplicated (one per DLL). So we need to group similar
|
||||
// strings together using the actual characters, not just the string address. We also have to do this
|
||||
// without allocating any new memory, since it would add new entries to the memory debug structure.
|
||||
//
|
||||
// The good news is that we don't care about speed too much in this function, since it's not supposed
|
||||
// to be called all the time.
|
||||
|
||||
struct Local
|
||||
{
|
||||
struct TmpStruct
|
||||
{
|
||||
const char* mName;
|
||||
udword mSize;
|
||||
};
|
||||
static int SortCB(const void* elem1, const void* elem2)
|
||||
{
|
||||
const TmpStruct* s1 = (const TmpStruct*)elem1;
|
||||
const TmpStruct* s2 = (const TmpStruct*)elem2;
|
||||
return strcmp(s1->mName, s2->mName);
|
||||
}
|
||||
};
|
||||
|
||||
Local::TmpStruct* SortedStrings = (Local::TmpStruct*)LOCAL_MALLOC(sizeof(Local::TmpStruct)*mMemBlockListSize);
|
||||
udword NbStrings = 0;
|
||||
udword TotalSize = 0;
|
||||
for(udword i=0;i<mMemBlockListSize;i++)
|
||||
{
|
||||
if(ValidAddress(mMemBlockList[i]))
|
||||
{
|
||||
const DebugBlock* DB = (const DebugBlock*)mMemBlockList[i];
|
||||
if(DB->mClassName)
|
||||
{
|
||||
SortedStrings[NbStrings].mName = DB->mClassName; // Memory by class
|
||||
// SortedStrings[NbStrings].mName = DB->mFilename; // Memory by file
|
||||
SortedStrings[NbStrings].mSize = DB->mSize;
|
||||
TotalSize += DB->mSize;
|
||||
NbStrings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
qsort(SortedStrings, NbStrings, sizeof(Local::TmpStruct), Local::SortCB);
|
||||
|
||||
// Strings are now sorted. They might still be duplicated, i.e. we may have two strings for the same
|
||||
// class. So now we parse the list and collect used memory for all classes. Then we sort this again,
|
||||
// to report results in order of increasing memory.
|
||||
|
||||
udword NbClasses=0;
|
||||
udword* Classes = (udword*)LOCAL_MALLOC(sizeof(udword)*NbStrings);
|
||||
udword* Sizes = (udword*)LOCAL_MALLOC(sizeof(udword)*NbStrings);
|
||||
|
||||
udword CurrentSize = SortedStrings[0].mSize;
|
||||
const char* CurrentClass = SortedStrings[0].mName;
|
||||
for(udword i=1;i<=NbStrings;i++) // One more time on purpose
|
||||
{
|
||||
const char* Current = null;
|
||||
if(i!=NbStrings)
|
||||
{
|
||||
Current = SortedStrings[i].mName;
|
||||
}
|
||||
|
||||
if(Current && strcmp(Current, CurrentClass)==0)
|
||||
{
|
||||
// Same class
|
||||
CurrentSize += SortedStrings[i].mSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New class
|
||||
|
||||
// Store previous class
|
||||
if(CurrentClass)
|
||||
{
|
||||
Classes[NbClasses] = (udword)CurrentClass; // We can store this pointer now because it's unique in our new array
|
||||
Sizes[NbClasses++] = CurrentSize;
|
||||
}
|
||||
|
||||
// Next one
|
||||
if(Current)
|
||||
{
|
||||
CurrentClass = Current;
|
||||
CurrentSize = SortedStrings[i].mSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
udword* Ranks0 = (udword*)LOCAL_MALLOC(sizeof(udword)*NbClasses);
|
||||
udword* Ranks1 = (udword*)LOCAL_MALLOC(sizeof(udword)*NbClasses);
|
||||
|
||||
StackRadixSort(RS, Ranks0, Ranks1);
|
||||
const udword* Sorted = RS.Sort(Sizes, NbClasses).GetRanks();
|
||||
for(udword i=0;i<NbClasses;i++)
|
||||
{
|
||||
udword Index = Sorted[i];
|
||||
char Buffer[4096];
|
||||
sprintf(Buffer, "%s : %d\n", (const char*)Classes[Index], Sizes[Index]);
|
||||
// IceTrace(Buffer);
|
||||
}
|
||||
char Buffer[4096];
|
||||
sprintf(Buffer, "Total size: %d\n", TotalSize);
|
||||
// IceTrace(Buffer);
|
||||
|
||||
LOCAL_FREE(Ranks1);
|
||||
LOCAL_FREE(Ranks0);
|
||||
|
||||
LOCAL_FREE(Sizes);
|
||||
LOCAL_FREE(Classes);
|
||||
|
||||
LOCAL_FREE(SortedStrings);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ### probably a bad idea to have a static var. Are we sure the "const char*" for class names/etc
|
||||
// are still valid when this gets deleted?
|
||||
|
||||
static Allocator* gAllocator = null;
|
||||
static DefaultAllocator gDefault;
|
||||
//static DefaultAllocator* gDefault = null;
|
||||
|
||||
Allocator* IceCore::GetAllocator()
|
||||
{
|
||||
if(!gAllocator) gAllocator = &gDefault;
|
||||
// if(!gAllocator) gAllocator = gDefault;
|
||||
return gAllocator;
|
||||
}
|
||||
|
||||
bool IceCore::SetAllocator(Allocator& allocator)
|
||||
{
|
||||
// ### make sure nothing has been allocated from the default one
|
||||
gAllocator = &allocator;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IceCore::DumpMemory()
|
||||
{
|
||||
gDefault.DumpCurrentMemoryState();
|
||||
// if(gDefault) gDefault->DumpCurrentMemoryState();
|
||||
}
|
||||
|
||||
void InitDefaultAllocator()
|
||||
{
|
||||
// gDefault = ::new DefaultAllocator;
|
||||
}
|
||||
|
||||
void ReleaseDefaultAllocator()
|
||||
{
|
||||
// if(gDefault) ::delete gDefault;
|
||||
// gDefault = null;
|
||||
}
|
||||
52
Extras/CDTestFramework/Opcode/Ice/IceAllocator.h
Normal file
52
Extras/CDTestFramework/Opcode/Ice/IceAllocator.h
Normal file
@@ -0,0 +1,52 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains an allocator base class.
|
||||
* \file IceAllocator.h
|
||||
* \author Pierre Terdiman
|
||||
* \date December, 19, 2003
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef ICEALLOCATOR_H
|
||||
#define ICEALLOCATOR_H
|
||||
|
||||
enum MemoryType
|
||||
{
|
||||
MEMORY_PERSISTENT,
|
||||
MEMORY_TEMP,
|
||||
};
|
||||
|
||||
class ICECORE_API Allocator
|
||||
{
|
||||
public:
|
||||
virtual void* malloc(size_t size, MemoryType type) = 0;
|
||||
virtual void* mallocDebug(size_t size, const char* filename, udword line, const char* class_name, MemoryType type) = 0;
|
||||
virtual void* realloc(void* memory, size_t size) = 0;
|
||||
virtual void* shrink(void* memory, size_t size) = 0;
|
||||
virtual void free(void* memory) = 0;
|
||||
};
|
||||
|
||||
FUNCTION ICECORE_API Allocator* GetAllocator();
|
||||
FUNCTION ICECORE_API bool SetAllocator(Allocator& allocator);
|
||||
FUNCTION ICECORE_API void DumpMemory();
|
||||
|
||||
class ICECORE_API Allocateable
|
||||
{
|
||||
public:
|
||||
#ifdef DONT_TRACK_MEMORY_LEAKS
|
||||
inline_ void* operator new (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
|
||||
inline_ void* operator new (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
|
||||
inline_ void* operator new[] (size_t size, MemoryType type) { return GetAllocator()->malloc(size, type); }
|
||||
inline_ void* operator new[] (size_t size, const char * filename, int line, const char* class_name, MemoryType type) { return GetAllocator()->mallocDebug(size, filename, line, class_name, type); }
|
||||
inline_ void operator delete (void* p) { GetAllocator()->free(p); }
|
||||
inline_ void operator delete (void* p, MemoryType) { GetAllocator()->free(p); }
|
||||
inline_ void operator delete (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
|
||||
inline_ void operator delete[] (void* p) { GetAllocator()->free(p); }
|
||||
inline_ void operator delete[] (void* p, MemoryType) { GetAllocator()->free(p); }
|
||||
inline_ void operator delete[] (void* p, const char*, int, const char*, MemoryType) { GetAllocator()->free(p); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ICEALLOCATOR_H
|
||||
48
Extras/CDTestFramework/Opcode/Ice/IceAssert.h
Normal file
48
Extras/CDTestFramework/Opcode/Ice/IceAssert.h
Normal file
@@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains custom assertion code.
|
||||
* \file IceAssert.h
|
||||
* \author Pierre Terdiman
|
||||
* \date January, 14, 2001
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef ICEASSERT_H
|
||||
#define ICEASSERT_H
|
||||
|
||||
// Leave the {} so that you can write this kind of things safely in release mode:
|
||||
// if(condition) ASSERT()
|
||||
|
||||
#ifndef ASSERT
|
||||
#if defined( _DEBUG )
|
||||
FUNCTION ICECORE_API bool CustomAssertFunction(int, char*, int, char*, bool&);
|
||||
|
||||
//! Custom ASSERT function. Various usages:
|
||||
//! ASSERT(condition)
|
||||
//! ASSERT(!"Not implemented")
|
||||
//! ASSERT(condition && "error text")
|
||||
#define ASSERT(exp) \
|
||||
{ \
|
||||
static bool IgnoreAlways = false; \
|
||||
if(!IgnoreAlways) \
|
||||
{ \
|
||||
if(CustomAssertFunction((int)(exp), #exp, __LINE__, __FILE__, IgnoreAlways)) \
|
||||
{ \
|
||||
_asm { int 3 } \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define ASSERT(exp) {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef assert
|
||||
#define assert ASSERT
|
||||
#endif
|
||||
|
||||
#define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ]
|
||||
|
||||
#endif // ICEASSERT_H
|
||||
73
Extras/CDTestFramework/Opcode/Ice/IceBitArray.cpp
Normal file
73
Extras/CDTestFramework/Opcode/Ice/IceBitArray.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains code for bit arrays.
|
||||
* \file IceBitArray.cpp
|
||||
* \author Pierre Terdiman
|
||||
* \date February, 5, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* A simple array of bits stored as bytes.
|
||||
*
|
||||
* \class Container
|
||||
* \author Pierre Terdiman
|
||||
* \version 1.0
|
||||
* \date February, 5, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "StdAfx.h"
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
BitArray::BitArray() : mSize(0), mBits(null)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
BitArray::BitArray(udword nb_bits) : mSize(0), mBits(null)
|
||||
{
|
||||
Init(nb_bits);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
BitArray::~BitArray()
|
||||
{
|
||||
ICE_FREE(mBits);
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Initializes the bit array for a given number of entries
|
||||
* \param nb_bits [in] max number of entries in the array
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool BitArray::Init(udword nb_bits)
|
||||
{
|
||||
mSize = BitsToDwords(nb_bits);
|
||||
// Get ram for n bits
|
||||
ICE_FREE(mBits);
|
||||
mBits = (udword*)ICE_ALLOC(sizeof(udword)*mSize);
|
||||
// Set all bits to 0
|
||||
ClearAll();
|
||||
return true;
|
||||
}
|
||||
82
Extras/CDTestFramework/Opcode/Ice/IceBitArray.h
Normal file
82
Extras/CDTestFramework/Opcode/Ice/IceBitArray.h
Normal file
@@ -0,0 +1,82 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains code for bit arrays.
|
||||
* \file IceBitArray.h
|
||||
* \author Pierre Terdiman
|
||||
* \date February, 5, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef ICEBITARRAY_H
|
||||
#define ICEBITARRAY_H
|
||||
|
||||
inline_ udword BitsToBytes(udword nb_bits)
|
||||
{
|
||||
return (nb_bits>>3) + ((nb_bits&7) ? 1 : 0);
|
||||
}
|
||||
|
||||
inline_ udword BitsToDwords(udword nb_bits)
|
||||
{
|
||||
return (nb_bits>>5) + ((nb_bits&31) ? 1 : 0);
|
||||
}
|
||||
|
||||
// Use that one instead of an array of bools. Takes less ram, nearly as fast [no bounds checkings and so on].
|
||||
class ICECORE_API BitArray
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
BitArray();
|
||||
BitArray(udword nb_bits);
|
||||
//! Destructor
|
||||
~BitArray();
|
||||
|
||||
bool Init(udword nb_bits);
|
||||
|
||||
// Data management
|
||||
inline_ void SetBit(udword bit_number) { mBits[bit_number>>5] |= 1<<(bit_number&31); }
|
||||
inline_ void ClearBit(udword bit_number) { mBits[bit_number>>5] &= ~(1<<(bit_number&31)); }
|
||||
inline_ void ToggleBit(udword bit_number) { mBits[bit_number>>5] ^= 1<<(bit_number&31); }
|
||||
|
||||
inline_ void ClearAll() { ZeroMemory(mBits, mSize*4); }
|
||||
inline_ void SetAll() { FillMemory(mBits, mSize*4, 0xff); }
|
||||
|
||||
// Data access
|
||||
inline_ BOOL IsSet(udword bit_number) const { return mBits[bit_number>>5] & (1<<(bit_number&31)); }
|
||||
|
||||
inline_ const udword* GetBits() const { return mBits; }
|
||||
inline_ udword GetSize() const { return mSize; }
|
||||
|
||||
protected:
|
||||
udword* mBits; //!< Array of bits
|
||||
udword mSize; //!< Size of the array in dwords
|
||||
};
|
||||
|
||||
// - We consider square symmetric N*N matrices
|
||||
// - A N*N symmetric matrix has N(N+1)/2 elements
|
||||
// - A boolean version needs N(N+1)/16 bytes
|
||||
// N NbBits NbBytes
|
||||
// 4 10 -
|
||||
// 8 36 4.5
|
||||
// 16 136 17 <= the one we select
|
||||
// 32 528 66
|
||||
static ubyte BitMasks[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
|
||||
static ubyte NegBitMasks[] = { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F };
|
||||
class ICECORE_API BoolSquareSymmetricMatrix16
|
||||
{
|
||||
public:
|
||||
inline_ udword Index(udword x, udword y) const { if(x>y) Swap(x,y); return x + (y ? ((y-1)*y)>>1 : 0); }
|
||||
|
||||
inline_ void Set(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] |= BitMasks[i&7]; }
|
||||
inline_ void Clear(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] &= NegBitMasks[i&7]; }
|
||||
inline_ void Toggle(udword x, udword y) { udword i = Index(x, y); mBits[i>>3] ^= BitMasks[i&7]; }
|
||||
inline_ bool IsSet(udword x, udword y) const { udword i = Index(x, y); return (mBits[i>>3] & BitMasks[i&7])!=0; }
|
||||
|
||||
inline_ void ClearAll() { ZeroMemory(mBits, 17); }
|
||||
inline_ void SetAll() { FillMemory(mBits, 17, 0xff); }
|
||||
|
||||
ubyte mBits[17];
|
||||
};
|
||||
|
||||
#endif // ICEBITARRAY_H
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains a simple container class.
|
||||
@@ -38,7 +22,7 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "Stdafx.h"
|
||||
#include "StdAfx.h"
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
@@ -46,6 +30,7 @@ using namespace IceCore;
|
||||
#ifdef CONTAINER_STATS
|
||||
udword Container::mNbContainers = 0;
|
||||
udword Container::mUsedRam = 0;
|
||||
LinkedList Container::mContainers;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -58,6 +43,7 @@ Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGr
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
mContainers.AddElem(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -66,11 +52,13 @@ Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGr
|
||||
* Constructor. Also allocates a given number of entries.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
|
||||
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null)
|
||||
{
|
||||
SetGrowthFactor(growth_factor);
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
mContainers.AddElem(this);
|
||||
#endif
|
||||
SetSize(size);
|
||||
}
|
||||
@@ -85,6 +73,7 @@ Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
mContainers.AddElem(this);
|
||||
#endif
|
||||
*this = object;
|
||||
}
|
||||
@@ -100,9 +89,25 @@ Container::~Container()
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers--;
|
||||
mUsedRam-=GetUsedRam();
|
||||
mContainers.RemElem(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
|
||||
* \param max_entries [in] max number of entries in the container
|
||||
* \param entries [in] external memory buffer
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Container::InitSharedBuffers(udword max_entries, udword* entries)
|
||||
{
|
||||
Empty(); // Make sure everything has been released
|
||||
mMaxNbEntries = max_entries;
|
||||
mEntries = entries;
|
||||
mGrowthFactor = -1.0f; // Negative growth ==> resize is disabled
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Clears the container. All stored values are deleted, and it frees used ram.
|
||||
@@ -115,7 +120,7 @@ Container& Container::Empty()
|
||||
#ifdef CONTAINER_STATS
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
DELETEARRAY(mEntries);
|
||||
if(mGrowthFactor>=0.0f) ICE_FREE(mEntries); // Release memory if we own it
|
||||
mCurNbEntries = mMaxNbEntries = 0;
|
||||
return *this;
|
||||
}
|
||||
@@ -129,6 +134,13 @@ Container& Container::Empty()
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Resize(udword needed)
|
||||
{
|
||||
// Check growth is allowed
|
||||
if(mGrowthFactor<=0.0f)
|
||||
{
|
||||
ASSERT(!"Invalid operation - trying to resize a static buffer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Subtract previous amount of bytes
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
@@ -139,7 +151,7 @@ bool Container::Resize(udword needed)
|
||||
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
|
||||
|
||||
// Get some bytes for new entries
|
||||
udword* NewEntries = new udword[mMaxNbEntries];
|
||||
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
|
||||
CHECKALLOC(NewEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
@@ -151,7 +163,7 @@ bool Container::Resize(udword needed)
|
||||
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||||
|
||||
// Delete old data
|
||||
DELETEARRAY(mEntries);
|
||||
ICE_FREE(mEntries);
|
||||
|
||||
// Assign new pointer
|
||||
mEntries = NewEntries;
|
||||
@@ -178,7 +190,7 @@ bool Container::SetSize(udword nb)
|
||||
mMaxNbEntries = nb;
|
||||
|
||||
// Get some bytes for new entries
|
||||
mEntries = new udword[mMaxNbEntries];
|
||||
mEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
|
||||
CHECKALLOC(mEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
@@ -196,6 +208,13 @@ bool Container::SetSize(udword nb)
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Refit()
|
||||
{
|
||||
// Check refit is allowed
|
||||
if(mGrowthFactor<=0.0f)
|
||||
{
|
||||
ASSERT(!"Invalid operation - trying to refit a static buffer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Subtract previous amount of bytes
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
@@ -206,7 +225,7 @@ bool Container::Refit()
|
||||
if(!mMaxNbEntries) return false;
|
||||
|
||||
// Get just enough bytes
|
||||
udword* NewEntries = new udword[mMaxNbEntries];
|
||||
udword* NewEntries = (udword*)ICE_ALLOC(sizeof(udword)*mMaxNbEntries);
|
||||
CHECKALLOC(NewEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
@@ -218,7 +237,7 @@ bool Container::Refit()
|
||||
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||||
|
||||
// Delete old data
|
||||
DELETEARRAY(mEntries);
|
||||
ICE_FREE(mEntries);
|
||||
|
||||
// Assign new pointer
|
||||
mEntries = NewEntries;
|
||||
@@ -226,6 +245,36 @@ bool Container::Refit()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Same as Refit but more efficient
|
||||
bool Container::Shrink()
|
||||
{
|
||||
if(!mEntries) return false;
|
||||
if(!mCurNbEntries)
|
||||
{
|
||||
Empty();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to shrink the pointer
|
||||
if(!GetAllocator()->shrink(mEntries, sizeof(udword)*mCurNbEntries))
|
||||
return false;
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Subtract previous amount of bytes
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
// Get just enough entries
|
||||
mMaxNbEntries = mCurNbEntries;
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Add current amount of bytes
|
||||
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Checks whether the container already contains a given value.
|
||||
@@ -353,6 +402,19 @@ udword Container::GetUsedRam() const
|
||||
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
|
||||
}
|
||||
|
||||
float Container::GetGrowthFactor() const
|
||||
{
|
||||
return mGrowthFactor;
|
||||
}
|
||||
|
||||
void Container::SetGrowthFactor(float growth)
|
||||
{
|
||||
// Negative growths are reserved for internal usages
|
||||
if(growth<0.0f) growth = 0.0f;
|
||||
mGrowthFactor = growth;
|
||||
}
|
||||
|
||||
//! Operator for "Container A = Container B"
|
||||
void Container::operator=(const Container& object)
|
||||
{
|
||||
SetSize(object.GetNbEntries());
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains a simple container class.
|
||||
@@ -25,10 +9,12 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICECONTAINER_H__
|
||||
#define __ICECONTAINER_H__
|
||||
#ifndef ICECONTAINER_H
|
||||
#define ICECONTAINER_H
|
||||
|
||||
#define CONTAINER_STATS
|
||||
// #define CONTAINER_STATS // #### doesn't work with micro-threads!
|
||||
|
||||
class LinkedList;
|
||||
|
||||
enum FindMode
|
||||
{
|
||||
@@ -38,7 +24,10 @@ subject to the following restrictions:
|
||||
FIND_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
class ICECORE_API Container
|
||||
class ICECORE_API Container : public Allocateable
|
||||
#ifdef CONTAINER_STATS
|
||||
, public ListElem
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
// Constructor / Destructor
|
||||
@@ -47,6 +36,15 @@ subject to the following restrictions:
|
||||
Container(udword size, float growth_factor);
|
||||
~Container();
|
||||
// Management
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Initializes the container so that it uses an external memory buffer. The container doesn't own the memory, resizing is disabled.
|
||||
* \param max_entries [in] max number of entries in the container
|
||||
* \param entries [in] external memory buffer
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void InitSharedBuffers(udword max_entries, udword* entries);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* A O(1) method to add a value in the container. The container is automatically resized if needed.
|
||||
@@ -71,14 +69,37 @@ subject to the following restrictions:
|
||||
}
|
||||
|
||||
inline_ Container& Add(const udword* entries, udword nb)
|
||||
{
|
||||
if(entries && nb)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
|
||||
|
||||
// Add new entry
|
||||
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
|
||||
mCurNbEntries += nb;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline_ Container& Add(const Container& container)
|
||||
{
|
||||
return Add(container.GetEntries(), container.GetNbEntries());
|
||||
}
|
||||
|
||||
inline_ udword* Reserve(udword nb)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
|
||||
|
||||
// Add new entry
|
||||
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
|
||||
mCurNbEntries+=nb;
|
||||
return *this;
|
||||
// We expect the user to fill reserved memory with 'nb' udwords
|
||||
udword* Reserved = &mEntries[mCurNbEntries];
|
||||
|
||||
// Meanwhile, we do as if it had been filled
|
||||
mCurNbEntries += nb;
|
||||
|
||||
// This is mainly used to avoid the copy when possible
|
||||
return Reserved;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -145,7 +166,7 @@ subject to the following restrictions:
|
||||
if(mCurNbEntries) mCurNbEntries = 0;
|
||||
}
|
||||
|
||||
// HANDLE WITH CARE
|
||||
// HANDLE WITH CARE - I hope you know what you're doing
|
||||
inline_ void ForceSize(udword size)
|
||||
{
|
||||
mCurNbEntries = size;
|
||||
@@ -168,6 +189,8 @@ subject to the following restrictions:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Refit();
|
||||
|
||||
bool Shrink();
|
||||
|
||||
// Checks whether the container already contains a given value.
|
||||
bool Contains(udword entry, udword* location=null) const;
|
||||
// Deletes an entry - doesn't preserve insertion order.
|
||||
@@ -184,15 +207,16 @@ subject to the following restrictions:
|
||||
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
|
||||
// Data access.
|
||||
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
|
||||
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry
|
||||
inline_ udword GetMaxNbEntries() const { return mMaxNbEntries; } //!< Returns max number of entries before resizing.
|
||||
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry.
|
||||
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
|
||||
|
||||
inline_ udword GetFirst() const { return mEntries[0]; }
|
||||
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
|
||||
|
||||
// Growth control
|
||||
inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor
|
||||
inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor
|
||||
float GetGrowthFactor() const; //!< Returns the growth factor
|
||||
void SetGrowthFactor(float growth); //!< Sets the growth factor
|
||||
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
|
||||
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
|
||||
|
||||
@@ -208,12 +232,14 @@ subject to the following restrictions:
|
||||
void operator = (const Container& object);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
inline_ udword GetNbContainers() const { return mNbContainers; }
|
||||
inline_ udword GetTotalBytes() const { return mUsedRam; }
|
||||
static udword GetNbContainers() { return mNbContainers; }
|
||||
static udword GetTotalBytes() { return mUsedRam; }
|
||||
static LinkedList& GetContainers() { return mContainers; }
|
||||
private:
|
||||
|
||||
static udword mNbContainers; //!< Number of containers around
|
||||
static udword mUsedRam; //!< Amount of bytes used by containers in the system
|
||||
static LinkedList mContainers;
|
||||
#endif
|
||||
private:
|
||||
// Resizing
|
||||
@@ -225,4 +251,4 @@ subject to the following restrictions:
|
||||
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
|
||||
};
|
||||
|
||||
#endif // __ICECONTAINER_H__
|
||||
#endif // ICECONTAINER_H
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains FPU related code.
|
||||
@@ -25,8 +9,8 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEFPU_H__
|
||||
#define __ICEFPU_H__
|
||||
#ifndef ICEFPU_H
|
||||
#define ICEFPU_H
|
||||
|
||||
#define SIGN_BITMASK 0x80000000
|
||||
|
||||
@@ -46,6 +30,12 @@ subject to the following restrictions:
|
||||
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
|
||||
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
|
||||
|
||||
//! Checks 2 values have different signs
|
||||
inline_ BOOL DifferentSign(float f0, float f1)
|
||||
{
|
||||
return (IR(f0)^IR(f1))&SIGN_BITMASK;
|
||||
}
|
||||
|
||||
//! Fast fabs for floating-point values. It just clears the sign bit.
|
||||
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
|
||||
inline_ float FastFabs(float x)
|
||||
@@ -292,6 +282,46 @@ subject to the following restrictions:
|
||||
return Res;
|
||||
}
|
||||
|
||||
//! A global function to find MAX(a,b,c,d) using FCOMI/FCMOV
|
||||
inline_ float FCMax4(float a, float b, float c, float d)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
_asm fld [c]
|
||||
_asm fld [d]
|
||||
FCOMI_ST1
|
||||
FCMOVB_ST1
|
||||
FCOMI_ST2
|
||||
FCMOVB_ST2
|
||||
FCOMI_ST3
|
||||
FCMOVB_ST3
|
||||
_asm fstp [Res]
|
||||
_asm fcompp
|
||||
_asm fcomp
|
||||
return Res;
|
||||
}
|
||||
|
||||
//! A global function to find MIN(a,b,c,d) using FCOMI/FCMOV
|
||||
inline_ float FCMin4(float a, float b, float c, float d)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
_asm fld [c]
|
||||
_asm fld [d]
|
||||
FCOMI_ST1
|
||||
FCMOVNB_ST1
|
||||
FCOMI_ST2
|
||||
FCMOVNB_ST2
|
||||
FCOMI_ST3
|
||||
FCMOVNB_ST3
|
||||
_asm fstp [Res]
|
||||
_asm fcompp
|
||||
_asm fcomp
|
||||
return Res;
|
||||
}
|
||||
|
||||
inline_ int ConvertToSortable(float f)
|
||||
{
|
||||
int& Fi = (int&)f;
|
||||
@@ -302,6 +332,32 @@ subject to the following restrictions:
|
||||
return Fi;
|
||||
}
|
||||
|
||||
inline_ udword EncodeFloat(const float val)
|
||||
{
|
||||
// We may need to check on -0 and 0
|
||||
// But it should make no practical difference.
|
||||
udword ir = IR(val);
|
||||
|
||||
if(ir & 0x80000000) //negative?
|
||||
ir = ~ir;//reverse sequence of negative numbers
|
||||
else
|
||||
ir |= 0x80000000; // flip sign
|
||||
|
||||
return ir;
|
||||
}
|
||||
|
||||
inline_ float DecodeFloat(udword ir)
|
||||
{
|
||||
udword rv;
|
||||
|
||||
if(ir & 0x80000000) //positive?
|
||||
rv = ir & ~0x80000000; //flip sign
|
||||
else
|
||||
rv = ~ir; //undo reversal
|
||||
|
||||
return FR(rv);
|
||||
}
|
||||
|
||||
enum FPUMode
|
||||
{
|
||||
FPU_FLOOR = 0,
|
||||
@@ -330,4 +386,18 @@ subject to the following restrictions:
|
||||
FUNCTION ICECORE_API int intFloor(const float& f);
|
||||
FUNCTION ICECORE_API int intCeil(const float& f);
|
||||
|
||||
#endif // __ICEFPU_H__
|
||||
inline_ sdword MyFloor(float f)
|
||||
{
|
||||
return (sdword)f - (IR(f)>>31);
|
||||
}
|
||||
|
||||
class ICECORE_API FPUGuard
|
||||
{
|
||||
public:
|
||||
FPUGuard();
|
||||
~FPUGuard();
|
||||
private:
|
||||
uword mControlWord;
|
||||
};
|
||||
|
||||
#endif // ICEFPU_H
|
||||
|
||||
78
Extras/CDTestFramework/Opcode/Ice/IceHashing.h
Normal file
78
Extras/CDTestFramework/Opcode/Ice/IceHashing.h
Normal file
@@ -0,0 +1,78 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains hashing code.
|
||||
* \file IceHashing.h
|
||||
* \author Pierre Terdiman
|
||||
* \date May, 08, 1999
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef ICEHASHING_H
|
||||
#define ICEHASHING_H
|
||||
|
||||
#define HashSize(n) ((udword)1<<(n))
|
||||
#define HashMask(n) (HashSize(n)-1)
|
||||
|
||||
ICECORE_API udword Hash(const char* str);
|
||||
ICECORE_API udword Hash(ubyte* k, udword length, udword initval);
|
||||
|
||||
// Bob Jenkin's hash
|
||||
inline_ unsigned int Hash32Bits_0(unsigned int key)
|
||||
{
|
||||
key += (key << 12);
|
||||
key ^= (key >> 22);
|
||||
key += (key << 4);
|
||||
key ^= (key >> 9);
|
||||
key += (key << 10);
|
||||
key ^= (key >> 2);
|
||||
key += (key << 7);
|
||||
key ^= (key >> 12);
|
||||
return key;
|
||||
}
|
||||
|
||||
// Thomas Wang's hash
|
||||
inline_ int Hash32Bits_1(int key)
|
||||
{
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
return key;
|
||||
}
|
||||
|
||||
// Thomas Wang's hash
|
||||
inline_ __int64 Hash64Bits_0(__int64 key)
|
||||
{
|
||||
key += ~(key << 32);
|
||||
key ^= (key >> 22);
|
||||
key += ~(key << 13);
|
||||
key ^= (key >> 8);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 15);
|
||||
key += ~(key << 27);
|
||||
key ^= (key >> 31);
|
||||
return key;
|
||||
}
|
||||
|
||||
inline_ __int64 Hash64Bits_1(__int64 key)
|
||||
{
|
||||
__int64 c1 = 0x6e5ea73858134343L;
|
||||
__int64 c2 = 0xb34e8f99a2ec9ef5L;
|
||||
key ^= ((c1 ^ key) >> 32);
|
||||
key *= c1;
|
||||
key ^= ((c2 ^ key) >> 31);
|
||||
key *= c2;
|
||||
key ^= ((c1 ^ key) >> 32);
|
||||
return key;
|
||||
}
|
||||
|
||||
inline_ udword Hash(udword id0, udword id1)
|
||||
{
|
||||
return Hash32Bits_1( (id0&0xffff)|(id1<<16) );
|
||||
}
|
||||
|
||||
#endif // ICEHASHING_H
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains all memory macros.
|
||||
@@ -25,8 +9,8 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEMEMORYMACROS_H__
|
||||
#define __ICEMEMORYMACROS_H__
|
||||
#ifndef ICEMEMORYMACROS_H
|
||||
#define ICEMEMORYMACROS_H
|
||||
|
||||
#undef ZeroMemory
|
||||
#undef CopyMemory
|
||||
@@ -40,7 +24,7 @@ subject to the following restrictions:
|
||||
//! \see StoreDwords
|
||||
//! \see CopyMemory
|
||||
//! \see MoveMemory
|
||||
inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); }
|
||||
inline_ void ZeroMemory(void* addr, regsize size) { memset(addr, 0, size); }
|
||||
|
||||
//! Fills a buffer with a given byte.
|
||||
//! \param addr [in] buffer address
|
||||
@@ -50,7 +34,7 @@ subject to the following restrictions:
|
||||
//! \see ZeroMemory
|
||||
//! \see CopyMemory
|
||||
//! \see MoveMemory
|
||||
inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); }
|
||||
inline_ void FillMemory(void* dest, regsize size, ubyte val) { memset(dest, val, size); }
|
||||
|
||||
//! Fills a buffer with a given dword.
|
||||
//! \param addr [in] buffer address
|
||||
@@ -90,7 +74,7 @@ subject to the following restrictions:
|
||||
//! \see FillMemory
|
||||
//! \see StoreDwords
|
||||
//! \see MoveMemory
|
||||
inline_ void CopyMemory(void* dest, const void* src, udword size) { memcpy(dest, src, size); }
|
||||
inline_ void CopyMemory(void* dest, const void* src, regsize size) { memcpy(dest, src, size); }
|
||||
|
||||
//! Moves a buffer.
|
||||
//! \param addr [in] destination buffer address
|
||||
@@ -100,22 +84,97 @@ subject to the following restrictions:
|
||||
//! \see FillMemory
|
||||
//! \see StoreDwords
|
||||
//! \see CopyMemory
|
||||
inline_ void MoveMemory(void* dest, const void* src, udword size) { memmove(dest, src, size); }
|
||||
inline_ void MoveMemory(void* dest, const void* src, regsize size) { memmove(dest, src, size); }
|
||||
|
||||
#define SIZEOFOBJECT sizeof(*this) //!< Gives the size of current object. Avoid some mistakes (e.g. "sizeof(this)").
|
||||
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); } //!< Clears current object. Laziness is my business. HANDLE WITH CARE.
|
||||
#define DELETESINGLE(x) if (x) { delete x; x = null; } //!< Deletes an instance of a class.
|
||||
#define DELETEARRAY(x) if (x) { delete []x; x = null; } //!< Deletes an array.
|
||||
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; } //!< Safe D3D-style release
|
||||
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release
|
||||
//! Flexible buffer copy
|
||||
//! \param src [in] source buffer address
|
||||
//! \param dst [in] destination buffer address
|
||||
//! \param nb_elem [in] number of elements to copy
|
||||
//! \param elem_size [in] size of an element
|
||||
//! \param stride [in] stride in bytes, including size of element
|
||||
inline_ void FlexiCopy(const void* src, void* dst, udword nb_elem, regsize elem_size, udword stride)
|
||||
{
|
||||
ubyte* d = (ubyte*)dst;
|
||||
const ubyte* s = (const ubyte*)src;
|
||||
const ubyte* Last = s + stride*nb_elem;
|
||||
while(s!=Last)
|
||||
{
|
||||
CopyMemory(d, s, elem_size);
|
||||
d += elem_size;
|
||||
s += stride;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __ICEERROR_H__
|
||||
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE.
|
||||
//! Gives the size of current object. This avoids some mistakes (e.g. "sizeof(this)").
|
||||
#define SIZEOFOBJECT sizeof(*this)
|
||||
|
||||
//! Clears current object. Laziness is my business! HANDLE WITH CARE. ### Removed, too dangerous, cleared too many v-tables
|
||||
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); }
|
||||
|
||||
// The two macros below are here for several reasons:
|
||||
// - sometimes we write "delete x" instead of "delete []x" just because we don't pay attention. Using the macro forces you
|
||||
// to think about what you're deleting, just because you have to write the macro's name (SINGLE or ARRAY).
|
||||
// - always clearing the pointer afterwards prevents some double-deletion in various situations.
|
||||
// - deleting null is a valid operation according to the standard, yet some lame memory managers don't like it. In sake of
|
||||
// robustness, we avoid trying.
|
||||
|
||||
//! Deletes an instance of a class.
|
||||
#define DELETESINGLE(x) if (x) { delete x; x = null; }
|
||||
//! Deletes an array.
|
||||
#define DELETEARRAY(x) if (x) { delete []x; x = null; }
|
||||
|
||||
//! Safe D3D-style release
|
||||
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; }
|
||||
|
||||
//! Safe ICE-style release
|
||||
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; }
|
||||
|
||||
#ifdef ICEERROR_H
|
||||
//! Standard alloc checking. HANDLE WITH CARE. Relies on strict coding rules. Probably shouldn't be used outside of ICE.
|
||||
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY);
|
||||
#else
|
||||
#define CHECKALLOC(x) if(!x) return false;
|
||||
#endif
|
||||
|
||||
//! Standard allocation cycle
|
||||
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
|
||||
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
|
||||
#define SAFE_ICE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = ICE_NEW(type)[count]; CHECKALLOC(ptr);
|
||||
|
||||
#endif // __ICEMEMORYMACROS_H__
|
||||
//! Don't use inline for alloca !!!
|
||||
#ifdef WIN32
|
||||
#define StackAlloc(x) _alloca(x)
|
||||
#elif LINUX
|
||||
#define StackAlloc(x) alloca(x)
|
||||
#elif defined(__APPLE__)
|
||||
#define StackAlloc(x) alloca(x)
|
||||
#elif defined(_XBOX)
|
||||
#define StackAlloc(x) _alloca(x)
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// #define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_TEMP)
|
||||
// #define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #x, MEMORY_PERSISTENT)
|
||||
#define ICE_ALLOC_TMP(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_TEMP)
|
||||
#define ICE_ALLOC(x) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, "(undefined)", MEMORY_PERSISTENT)
|
||||
#define ICE_ALLOC_TMP2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_TEMP)
|
||||
#define ICE_ALLOC2(x, y) GetAllocator()->mallocDebug(x, __FILE__, __LINE__, #y, MEMORY_PERSISTENT)
|
||||
#else
|
||||
#define ICE_ALLOC_TMP(x) GetAllocator()->malloc(x, MEMORY_TEMP)
|
||||
#define ICE_ALLOC(x) GetAllocator()->malloc(x, MEMORY_PERSISTENT)
|
||||
#endif
|
||||
#define ICE_FREE(x) if(x) { GetAllocator()->free(x); x = null; }
|
||||
|
||||
#ifdef DONT_TRACK_MEMORY_LEAKS
|
||||
#ifdef _DEBUG
|
||||
#define ICE_NEW_TMP(x) new(__FILE__, __LINE__, #x, MEMORY_TEMP) x
|
||||
#define ICE_NEW(x) new(__FILE__, __LINE__, #x, MEMORY_PERSISTENT) x
|
||||
#else
|
||||
#define ICE_NEW_TMP(x) new(MEMORY_TEMP) x
|
||||
#define ICE_NEW(x) new(MEMORY_PERSISTENT) x
|
||||
#endif
|
||||
#else
|
||||
#define ICE_NEW_TMP(x) new x
|
||||
#define ICE_NEW(x) new x
|
||||
#endif
|
||||
|
||||
#endif // ICEMEMORYMACROS_H
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains preprocessor stuff. This should be the first included header.
|
||||
@@ -25,8 +9,8 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEPREPROCESSOR_H__
|
||||
#define __ICEPREPROCESSOR_H__
|
||||
#ifndef ICEPREPROCESSOR_H
|
||||
#define ICEPREPROCESSOR_H
|
||||
|
||||
// Check platform
|
||||
#if defined( _WIN32 ) || defined( WIN32 )
|
||||
@@ -40,6 +24,14 @@ subject to the following restrictions:
|
||||
#if defined(_MSC_VER)
|
||||
#pragma message("Compiling with VC++...")
|
||||
#define COMPILER_VISUAL_CPP
|
||||
|
||||
#if _MSC_VER > 1300
|
||||
#pragma message("Compiling with VC7")
|
||||
#define COMPILER_VC7
|
||||
#else
|
||||
#pragma message("Compiling with VC6")
|
||||
#define COMPILER_VC6
|
||||
#endif
|
||||
#else
|
||||
#pragma message("Compiling with unknown compiler...")
|
||||
#endif
|
||||
@@ -73,7 +65,7 @@ subject to the following restrictions:
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Here you may define items for debug builds
|
||||
// Here you may define items for debug builds
|
||||
#endif
|
||||
|
||||
#ifndef THIS_FILE
|
||||
@@ -82,18 +74,14 @@ subject to the following restrictions:
|
||||
|
||||
#ifndef ICE_NO_DLL
|
||||
#ifdef ICECORE_EXPORTS
|
||||
#define ICECORE_API __declspec(dllexport)
|
||||
#define ICECORE_API __declspec(dllexport)
|
||||
#else
|
||||
#define ICECORE_API __declspec(dllimport)
|
||||
#define ICECORE_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define ICECORE_API
|
||||
#endif
|
||||
|
||||
// Don't override new/delete
|
||||
// #define DEFAULT_NEWDELETE
|
||||
#define DONT_TRACK_MEMORY_LEAKS
|
||||
|
||||
#define FUNCTION extern "C"
|
||||
|
||||
// Cosmetic stuff [mainly useful with multiple inheritance]
|
||||
@@ -106,16 +94,16 @@ subject to the following restrictions:
|
||||
// #define inline_ inline
|
||||
|
||||
// Contributed by Bruce Mitchener
|
||||
#if defined(COMPILER_VISUAL_CPP)
|
||||
#define inline_ __forceinline
|
||||
// #define inline_ inline
|
||||
#elif defined(__GNUC__) && __GNUC__ < 3
|
||||
#define inline_ inline
|
||||
#elif defined(__GNUC__)
|
||||
#define inline_ inline __attribute__ ((always_inline))
|
||||
#else
|
||||
#define inline_ inline
|
||||
#endif
|
||||
#if defined(COMPILER_VISUAL_CPP)
|
||||
#define inline_ __forceinline
|
||||
// #define inline_ inline
|
||||
#elif defined(__GNUC__) && __GNUC__ < 3
|
||||
#define inline_ inline
|
||||
#elif defined(__GNUC__)
|
||||
#define inline_ inline __attribute__ ((always_inline))
|
||||
#else
|
||||
#define inline_ inline
|
||||
#endif
|
||||
|
||||
// Down the hatch
|
||||
#pragma inline_depth( 255 )
|
||||
@@ -135,10 +123,36 @@ subject to the following restrictions:
|
||||
// ANSI compliance
|
||||
#ifdef _DEBUG
|
||||
// Remove painful warning in debug
|
||||
inline_ bool __False__(){ return false; }
|
||||
#define for if(__False__()){} else for
|
||||
inline_ bool ReturnsFalse(){ return false; }
|
||||
#define for if(ReturnsFalse()){} else for
|
||||
#else
|
||||
#define for if(0){} else for
|
||||
#endif
|
||||
|
||||
#endif // __ICEPREPROCESSOR_H__
|
||||
// Don't override new/delete
|
||||
#define DEFAULT_NEWDELETE
|
||||
#define DONT_TRACK_MEMORY_LEAKS
|
||||
|
||||
//! Macro used to give me a clue when it crashes in release and only the assembly is available
|
||||
#define INCLUDE_GUARDIANS
|
||||
#ifdef INCLUDE_GUARDIANS
|
||||
#define GUARD(x) \
|
||||
{ \
|
||||
static const char guard_text[] = x; \
|
||||
_asm push eax \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm lea eax, guard_text \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm nop \
|
||||
_asm pop eax \
|
||||
}
|
||||
#else
|
||||
#define GUARD(x)
|
||||
#endif
|
||||
|
||||
#endif // ICEPREPROCESSOR_H
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
@@ -44,12 +28,18 @@ subject to the following restrictions:
|
||||
* - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting......
|
||||
* - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all.
|
||||
* - ranks are not "reset" anymore, but implicit on first calls
|
||||
* - 07.05.02: - offsets rewritten with one less indirection.
|
||||
* - 11.03.02: - "bool" replaced with RadixHint enum
|
||||
* - 07.05.02: offsets rewritten with one less indirection.
|
||||
* - 11.03.02: "bool" replaced with RadixHint enum
|
||||
* - 07.15.04: stack-based radix added
|
||||
* - we want to use the radix sort but without making it static, and without allocating anything.
|
||||
* - we internally allocate two arrays of ranks. Each of them has N udwords to sort N values.
|
||||
* - 1Mb/2/sizeof(udword) = 131072 values max, at the same time.
|
||||
* - 09.22.04: - adapted to MacOS by Chris Lamb
|
||||
* - 01.12.06: - added optimizations suggested by Kyle Hubert
|
||||
*
|
||||
* \class RadixSort
|
||||
* \author Pierre Terdiman
|
||||
* \version 1.4
|
||||
* \version 1.5
|
||||
* \date August, 15, 1998
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -58,14 +48,13 @@ subject to the following restrictions:
|
||||
To do:
|
||||
- add an offset parameter between two input values (avoid some data recopy sometimes)
|
||||
- unroll ? asm ?
|
||||
- 11 bits trick & 3 passes as Michael did
|
||||
- prefetch stuff the day I have a P3
|
||||
- make a version with 16-bits indices ?
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "Stdafx.h"
|
||||
#include "StdAfx.h"
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
@@ -82,17 +71,31 @@ using namespace IceCore;
|
||||
mPreviousSize = n; \
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(_XBOX)
|
||||
#define H0_OFFSET 768
|
||||
#define H1_OFFSET 512
|
||||
#define H2_OFFSET 256
|
||||
#define H3_OFFSET 0
|
||||
#define BYTES_INC (3-j)
|
||||
#else
|
||||
#define H0_OFFSET 0
|
||||
#define H1_OFFSET 256
|
||||
#define H2_OFFSET 512
|
||||
#define H3_OFFSET 768
|
||||
#define BYTES_INC j
|
||||
#endif
|
||||
|
||||
#define CREATE_HISTOGRAMS(type, buffer) \
|
||||
/* Clear counters/histograms */ \
|
||||
ZeroMemory(mHistogram, 256*4*sizeof(udword)); \
|
||||
\
|
||||
/* Prepare to count */ \
|
||||
ubyte* p = (ubyte*)input; \
|
||||
ubyte* pe = &p[nb*4]; \
|
||||
udword* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \
|
||||
udword* h1= &mHistogram[256]; /* Histogram for second pass */ \
|
||||
udword* h2= &mHistogram[512]; /* Histogram for third pass */ \
|
||||
udword* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \
|
||||
const ubyte* p = (const ubyte*)input; \
|
||||
const ubyte* pe = &p[nb*4]; \
|
||||
udword* h0= &mHistogram[H0_OFFSET]; /* Histogram for first pass (LSB) */ \
|
||||
udword* h1= &mHistogram[H1_OFFSET]; /* Histogram for second pass */ \
|
||||
udword* h2= &mHistogram[H2_OFFSET]; /* Histogram for third pass */ \
|
||||
udword* h3= &mHistogram[H3_OFFSET]; /* Histogram for last pass (MSB) */ \
|
||||
\
|
||||
bool AlreadySorted = true; /* Optimism... */ \
|
||||
\
|
||||
@@ -128,7 +131,7 @@ using namespace IceCore;
|
||||
else \
|
||||
{ \
|
||||
/* Prepare for temporal coherence */ \
|
||||
udword* Indices = mRanks; \
|
||||
const udword* Indices = mRanks; \
|
||||
type PrevVal = (type)buffer[*Indices]; \
|
||||
\
|
||||
while(p!=pe) \
|
||||
@@ -159,7 +162,7 @@ using namespace IceCore;
|
||||
|
||||
#define CHECK_PASS_VALIDITY(pass) \
|
||||
/* Shortcut to current counters */ \
|
||||
udword* CurCount = &mHistogram[pass<<8]; \
|
||||
const udword* CurCount = &mHistogram[pass<<8]; \
|
||||
\
|
||||
/* Reset flag. The sorting pass is supposed to be performed. (default) */ \
|
||||
bool PerformPass = true; \
|
||||
@@ -183,12 +186,12 @@ using namespace IceCore;
|
||||
* Constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort::RadixSort() : mRanks(null), mRanks2(null), mCurrentSize(0), mTotalCalls(0), mNbHits(0)
|
||||
RadixSort::RadixSort() : mRanks(null), mRanks2(null), mCurrentSize(0), mTotalCalls(0), mNbHits(0), mDeleteRanks(true)
|
||||
{
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
// Allocate input-independent ram
|
||||
mHistogram = new udword[256*4];
|
||||
mOffset = new udword[256];
|
||||
mHistogram = ICE_ALLOC(sizeof(udword)*256*4);
|
||||
mOffset = ICE_ALLOC(sizeof(udword)*256);
|
||||
#endif
|
||||
// Initialize indices
|
||||
INVALIDATE_RANKS;
|
||||
@@ -203,11 +206,14 @@ RadixSort::~RadixSort()
|
||||
{
|
||||
// Release everything
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
DELETEARRAY(mOffset);
|
||||
DELETEARRAY(mHistogram);
|
||||
ICE_FREE(mOffset);
|
||||
ICE_FREE(mHistogram);
|
||||
#endif
|
||||
DELETEARRAY(mRanks2);
|
||||
DELETEARRAY(mRanks);
|
||||
if(mDeleteRanks)
|
||||
{
|
||||
ICE_FREE(mRanks2);
|
||||
ICE_FREE(mRanks);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -219,14 +225,16 @@ RadixSort::~RadixSort()
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool RadixSort::Resize(udword nb)
|
||||
{
|
||||
// Free previously used ram
|
||||
DELETEARRAY(mRanks2);
|
||||
DELETEARRAY(mRanks);
|
||||
|
||||
// Get some fresh one
|
||||
mRanks = new udword[nb]; CHECKALLOC(mRanks);
|
||||
mRanks2 = new udword[nb]; CHECKALLOC(mRanks2);
|
||||
if(mDeleteRanks)
|
||||
{
|
||||
// Free previously used ram
|
||||
ICE_FREE(mRanks2);
|
||||
ICE_FREE(mRanks);
|
||||
|
||||
// Get some fresh one
|
||||
mRanks = (udword*)ICE_ALLOC(sizeof(udword)*nb); CHECKALLOC(mRanks);
|
||||
mRanks2 = (udword*)ICE_ALLOC(sizeof(udword)*nb); CHECKALLOC(mRanks2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -276,7 +284,7 @@ RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
// have 2 code paths even if just a single opcode changes. Self-modifying code, someone?
|
||||
if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(udword, input); }
|
||||
else { CREATE_HISTOGRAMS(sdword, input); }
|
||||
|
||||
/*
|
||||
// Compute #negative values involved if needed
|
||||
udword NbNegativeValues = 0;
|
||||
if(hint==RADIX_SIGNED)
|
||||
@@ -287,7 +295,7 @@ RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
udword* h3= &mHistogram[768];
|
||||
for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
}
|
||||
|
||||
*/
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for(udword j=0;j<4;j++)
|
||||
{
|
||||
@@ -311,23 +319,38 @@ RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
else
|
||||
{
|
||||
// This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place.
|
||||
|
||||
/*
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
// mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
// for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// Fixing the wrong place for negative values
|
||||
// mOffset[128] = 0;
|
||||
mLink[128] = mRanks2;
|
||||
// for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
mLink[128] = mRanks2;
|
||||
for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
*/
|
||||
|
||||
// From Kyle Hubert:
|
||||
|
||||
//mOffset[128] = 0;
|
||||
mLink[128] = mRanks2;
|
||||
//for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
|
||||
//mOffset[0] = mOffset[255] + CurCount[255];
|
||||
mLink[0] = mLink[255] + CurCount[255];
|
||||
//for(i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Perform Radix Sort
|
||||
ubyte* InputBytes = (ubyte*)input;
|
||||
InputBytes += j;
|
||||
const ubyte* InputBytes = (const ubyte*)input;
|
||||
InputBytes += BYTES_INC;
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
// for(udword i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
|
||||
@@ -336,8 +359,8 @@ RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
}
|
||||
else
|
||||
{
|
||||
udword* Indices = mRanks;
|
||||
udword* IndicesEnd = &mRanks[nb];
|
||||
const udword* Indices = mRanks;
|
||||
const udword* IndicesEnd = &mRanks[nb];
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
udword id = *Indices++;
|
||||
@@ -347,7 +370,9 @@ RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
udword* Tmp = mRanks;
|
||||
mRanks = mRanks2;
|
||||
mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
@@ -371,7 +396,7 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
// Stats
|
||||
mTotalCalls++;
|
||||
|
||||
udword* input = (udword*)input2;
|
||||
const udword* input = (const udword*)input2;
|
||||
|
||||
// Resize lists if needed
|
||||
CheckResize(nb);
|
||||
@@ -392,15 +417,16 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
// generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just
|
||||
// wouldn't work with mixed positive/negative values....
|
||||
{ CREATE_HISTOGRAMS(float, input2); }
|
||||
|
||||
/*
|
||||
// Compute #negative values involved if needed
|
||||
udword NbNegativeValues = 0;
|
||||
// An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
|
||||
// last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
|
||||
// responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
|
||||
// ### is that ok on Apple ?!
|
||||
udword* h3= &mHistogram[768];
|
||||
for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
|
||||
*/
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for(udword j=0;j<4;j++)
|
||||
{
|
||||
@@ -419,8 +445,8 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
|
||||
// Perform Radix Sort
|
||||
ubyte* InputBytes = (ubyte*)input;
|
||||
InputBytes += j;
|
||||
const ubyte* InputBytes = (const ubyte*)input;
|
||||
InputBytes += BYTES_INC;
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
// for(i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
|
||||
@@ -429,8 +455,8 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
}
|
||||
else
|
||||
{
|
||||
udword* Indices = mRanks;
|
||||
udword* IndicesEnd = &mRanks[nb];
|
||||
const udword* Indices = mRanks;
|
||||
const udword* IndicesEnd = &mRanks[nb];
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
udword id = *Indices++;
|
||||
@@ -440,7 +466,9 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
udword* Tmp = mRanks;
|
||||
mRanks = mRanks2;
|
||||
mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -450,19 +478,32 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
|
||||
if(PerformPass)
|
||||
{
|
||||
/*
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
// mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
// for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// We must reverse the sorting order for negative numbers!
|
||||
// mOffset[255] = 0;
|
||||
mLink[255] = mRanks2;
|
||||
// for(i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
for(udword i=0;i<127;i++) mLink[254-i] = mLink[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
// for(i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values
|
||||
mLink[255] = mRanks2;
|
||||
for(udword i=0;i<127;i++) mLink[254-i] = mLink[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
for(udword i=128;i<256;i++) mLink[i] += CurCount[i]; // Fixing the wrong place for negative values
|
||||
*/
|
||||
|
||||
// From Kyle Hubert:
|
||||
|
||||
//mOffset[255] = CurCount[255];
|
||||
mLink[255] = mRanks2 + CurCount[255];
|
||||
//for(udword i=254;i>127;i--) mOffset[i] = mOffset[i+1] + CurCount[i];
|
||||
for(udword i=254;i>127;i--) mLink[i] = mLink[i+1] + CurCount[i];
|
||||
//mOffset[0] = mOffset[128] + CurCount[128];
|
||||
mLink[0] = mLink[128] + CurCount[128];
|
||||
//for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
|
||||
// Perform Radix Sort
|
||||
if(INVALID_RANKS)
|
||||
@@ -491,7 +532,9 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
}
|
||||
}
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
udword* Tmp = mRanks;
|
||||
mRanks = mRanks2;
|
||||
mRanks2 = Tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -510,7 +553,9 @@ RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
udword* Tmp = mRanks;
|
||||
mRanks = mRanks2;
|
||||
mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,3 +579,14 @@ udword RadixSort::GetUsedRam() const
|
||||
UsedRam += 2*CURRENT_SIZE*sizeof(udword); // 2 lists of indices
|
||||
return UsedRam;
|
||||
}
|
||||
|
||||
bool RadixSort::SetRankBuffers(udword* ranks0, udword* ranks1)
|
||||
{
|
||||
if(!ranks0 || !ranks1) return false;
|
||||
|
||||
mRanks = ranks0;
|
||||
mRanks2 = ranks1;
|
||||
mDeleteRanks = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
@@ -25,8 +9,8 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICERADIXSORT_H__
|
||||
#define __ICERADIXSORT_H__
|
||||
#ifndef ICERADIXSORT_H
|
||||
#define ICERADIXSORT_H
|
||||
|
||||
//! Allocate histograms & offsets locally
|
||||
#define RADIX_LOCAL_RAM
|
||||
@@ -39,7 +23,7 @@ subject to the following restrictions:
|
||||
RADIX_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
class ICECORE_API RadixSort
|
||||
class ICECORE_API RadixSort : public Allocateable
|
||||
{
|
||||
public:
|
||||
// Constructor/Destructor
|
||||
@@ -62,6 +46,9 @@ subject to the following restrictions:
|
||||
//! Returns the number of eraly exits due to temporal coherence.
|
||||
inline_ udword GetNbHits() const { return mNbHits; }
|
||||
|
||||
bool SetRankBuffers(udword* ranks0, udword* ranks1);
|
||||
|
||||
PREVENT_COPY(RadixSort)
|
||||
private:
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
udword* mHistogram; //!< Counters for each byte
|
||||
@@ -73,9 +60,15 @@ subject to the following restrictions:
|
||||
// Stats
|
||||
udword mTotalCalls; //!< Total number of calls to the sort routine
|
||||
udword mNbHits; //!< Number of early exits due to coherence
|
||||
// Stack-radix
|
||||
bool mDeleteRanks; //!<
|
||||
// Internal methods
|
||||
void CheckResize(udword nb);
|
||||
bool Resize(udword nb);
|
||||
};
|
||||
|
||||
#endif // __ICERADIXSORT_H__
|
||||
#define StackRadixSort(name, ranks0, ranks1) \
|
||||
RadixSort name; \
|
||||
name.SetRankBuffers(ranks0, ranks1);
|
||||
|
||||
#endif // ICERADIXSORT_H
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains custom types.
|
||||
@@ -25,13 +9,15 @@ subject to the following restrictions:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICETYPES_H__
|
||||
#define __ICETYPES_H__
|
||||
#ifndef ICETYPES_H
|
||||
#define ICETYPES_H
|
||||
|
||||
#define USE_HANDLE_MANAGER
|
||||
|
||||
// Constants
|
||||
#ifndef PI
|
||||
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
|
||||
#endif
|
||||
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
|
||||
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
|
||||
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
|
||||
@@ -59,16 +45,32 @@ subject to the following restrictions:
|
||||
#define null 0 //!< our own NULL pointer
|
||||
|
||||
// Custom types used in ICE
|
||||
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
|
||||
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
|
||||
typedef signed short sword; //!< sizeof(sword) must be 2
|
||||
typedef unsigned short uword; //!< sizeof(uword) must be 2
|
||||
typedef signed int sdword; //!< sizeof(sdword) must be 4
|
||||
typedef unsigned int udword; //!< sizeof(udword) must be 4
|
||||
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
|
||||
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
|
||||
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
|
||||
typedef signed short sword; //!< sizeof(sword) must be 2
|
||||
typedef unsigned short uword; //!< sizeof(uword) must be 2
|
||||
typedef signed int sdword; //!< sizeof(sdword) must be 4
|
||||
typedef unsigned int udword; //!< sizeof(udword) must be 4
|
||||
#ifdef WIN32
|
||||
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
|
||||
#elif LINUX
|
||||
typedef signed long long sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
|
||||
#elif defined(__APPLE__)
|
||||
typedef signed long long sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned long long uqword; //!< sizeof(uqword) must be 8
|
||||
#elif defined(_XBOX)
|
||||
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
|
||||
#endif
|
||||
typedef float float32; //!< sizeof(float32) must be 4
|
||||
typedef double float64; //!< sizeof(float64) must be 4
|
||||
typedef double float64; //!< sizeof(float64) must be 8
|
||||
typedef size_t regsize; //!< sizeof(regsize) must be sizeof(void*)
|
||||
|
||||
// For test purpose you can force one of those:
|
||||
// typedef udword regsize;
|
||||
// typedef uqword regsize;
|
||||
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
|
||||
@@ -79,6 +81,9 @@ subject to the following restrictions:
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(float32)==4);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(float64)==8);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(regsize)==sizeof(void*));
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
|
||||
@@ -90,7 +95,6 @@ subject to the following restrictions:
|
||||
#else
|
||||
typedef uword KID; //!< Kernel ID
|
||||
#endif
|
||||
typedef udword RTYPE; //!< Relationship-type (!) between owners and references
|
||||
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
|
||||
#ifdef USE_HANDLE_MANAGER
|
||||
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
|
||||
@@ -139,9 +143,7 @@ subject to the following restrictions:
|
||||
|
||||
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
|
||||
|
||||
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
|
||||
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
|
||||
typedef void** VTABLE; //!< A V-Table.
|
||||
typedef void** VTABLE; //!< A V-Table.
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
@@ -154,6 +156,7 @@ subject to the following restrictions:
|
||||
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
|
||||
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
|
||||
|
||||
/* Obsolete stuff - if needed, move to dedicated header and include in few files using this.
|
||||
#define SQR(x) ((x)*(x)) //!< Returns x square
|
||||
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
|
||||
|
||||
@@ -163,11 +166,16 @@ subject to the following restrictions:
|
||||
|
||||
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
|
||||
|
||||
#ifdef _WIN32
|
||||
# define srand48(x) srand((unsigned int) (x))
|
||||
# define srandom(x) srand((unsigned int) (x))
|
||||
# define random() ((double) rand())
|
||||
# define drand48() ((double) (((double) rand()) / ((double) RAND_MAX)))
|
||||
#endif
|
||||
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
|
||||
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
|
||||
|
||||
#endif // __ICETYPES_H__
|
||||
#ifdef _WIN32
|
||||
// Used to compile legacy code
|
||||
__forceinline void srand48(udword x) { srand(x); }
|
||||
__forceinline void srandom(udword x) { srand(x); }
|
||||
__forceinline double random() { return (double)rand(); }
|
||||
__forceinline double drand48() { return (double) ( ((double)rand()) / ((double)RAND_MAX) ); }
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif // ICETYPES_H
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains misc. useful macros & defines.
|
||||
* \file IceUtils.h
|
||||
* \author Pierre Terdiman (collected from various sources)
|
||||
* \author Pierre Terdiman (personal code + collected from various sources)
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEUTILS_H__
|
||||
#define __ICEUTILS_H__
|
||||
#ifndef ICEUTILS_H
|
||||
#define ICEUTILS_H
|
||||
|
||||
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
|
||||
#define END_RUNONCE __RunOnce__ = true;}}
|
||||
@@ -40,7 +24,7 @@ subject to the following restrictions:
|
||||
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
|
||||
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
|
||||
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
|
||||
// Etc for larger intergers (64 bits in Java)
|
||||
// Etc for larger integers (64 bits in Java)
|
||||
// NOTE: the >> operation must be unsigned! (>>> in java)
|
||||
}
|
||||
|
||||
@@ -48,15 +32,15 @@ subject to the following restrictions:
|
||||
inline_ udword CountBits(udword n)
|
||||
{
|
||||
// This relies of the fact that the count of n bits can NOT overflow
|
||||
// an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts
|
||||
// 2 bit interger, 3 bit count requires only a 2 bit interger.
|
||||
// an n bit integer. EG: 1 bit count takes a 1 bit integer, 2 bit counts
|
||||
// 2 bit integer, 3 bit count requires only a 2 bit integer.
|
||||
// So we add all bit pairs, then each nible, then each byte etc...
|
||||
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
|
||||
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
|
||||
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
|
||||
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
|
||||
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
|
||||
// Etc for larger intergers (64 bits in Java)
|
||||
// Etc for larger integers (64 bits in Java)
|
||||
// NOTE: the >> operation must be unsigned! (>>> in java)
|
||||
return n;
|
||||
}
|
||||
@@ -70,9 +54,44 @@ subject to the following restrictions:
|
||||
return (bits * 0x01010101) >> 24;
|
||||
}
|
||||
|
||||
// "Population Count (Ones Count)
|
||||
// The population count of a binary integer value x is the number of one bits in the value. Although many machines have
|
||||
// single instructions for this, the single instructions are usually microcoded loops that test a bit per cycle; a log-time
|
||||
// algorithm coded in C is often faster. The following code uses a variable-precision SWAR algorithm to perform a tree
|
||||
// reduction adding the bits in a 32-bit value:"
|
||||
inline_ udword ones32(udword x)
|
||||
{
|
||||
/* 32-bit recursive reduction using SWAR...
|
||||
but first step is mapping 2-bit values
|
||||
into sum of 2 1-bit values in sneaky way
|
||||
*/
|
||||
x -= ((x >> 1) & 0x55555555);
|
||||
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
||||
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
||||
x += (x >> 8);
|
||||
x += (x >> 16);
|
||||
return (x & 0x0000003f);
|
||||
// "It is worthwhile noting that the SWAR population count algorithm given above can be improved upon for the case of
|
||||
// counting the population of multi-word bit sets. How? The last few steps in the reduction are using only a portion
|
||||
// of the SWAR width to produce their results; thus, it would be possible to combine these steps across multiple words
|
||||
// being reduced. One additional note: the AMD Athlon optimization guidelines suggest a very similar algorithm that
|
||||
// replaces the last three lines with return((x * 0x01010101) >> 24);. For the Athlon (which has a very fast integer
|
||||
// multiply), I would have expected AMD's code to be faster... but it is actually 6% slower according to my benchmarks
|
||||
// using a 1.2GHz Athlon (a Thunderbird). Why? Well, it so happens that GCC doesn't use a multiply instruction - it
|
||||
// writes out the equivalent shift and add sequence!"
|
||||
}
|
||||
|
||||
// "Trailing Zero Count
|
||||
// Given the Least Significant 1 Bit and Population Count (Ones Count) algorithms, it is trivial to combine them to
|
||||
// construct a trailing zero count (as pointed-out by Joe Bowbeer):"
|
||||
inline_ udword tzc(sdword x)
|
||||
{
|
||||
return(ones32((x & -x) - 1));
|
||||
}
|
||||
|
||||
//! Spread out bits. EG 00001111 -> 0101010101
|
||||
//! 00001010 -> 0100010000
|
||||
//! This is used to interleve to intergers to produce a `Morten Key'
|
||||
//! This is used to interleave two integers to produce a `Morton Key'
|
||||
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
|
||||
//! Order is important.
|
||||
inline_ void SpreadBits(udword& n)
|
||||
@@ -84,12 +103,12 @@ subject to the following restrictions:
|
||||
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
|
||||
}
|
||||
|
||||
// Next Largest Power of 2
|
||||
// "Next Largest Power of 2
|
||||
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
|
||||
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
|
||||
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
|
||||
// largest power of 2. For a 32-bit value:
|
||||
inline_ udword nlpo2(udword x)
|
||||
// largest power of 2. For a 32-bit value:"
|
||||
inline_ udword NextPowerOfTwo(udword x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
@@ -131,24 +150,45 @@ subject to the following restrictions:
|
||||
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
|
||||
|
||||
//!< Alternative abs function
|
||||
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
|
||||
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
|
||||
|
||||
// "Integer Minimum or Maximum
|
||||
// Given 2's complement integer values x and y, the minimum can be computed without any branches as
|
||||
// x+(((y-x)>>(WORDBITS-1))&(y-x)).
|
||||
// Logically, this works because the shift by (WORDBITS-1) replicates the sign bit to create a mask
|
||||
// -- be aware, however, that the C language does not require that shifts are signed even if their
|
||||
// operands are signed, so there is a potential portability problem. Additionally, one might think
|
||||
// that a shift by any number greater than or equal to WORDBITS would have the same effect, but many
|
||||
// instruction sets have shifts that behave strangely when such shift distances are specified.
|
||||
// Of course, maximum can be computed using the same trick:
|
||||
// x-(((x-y)>>(WORDBITS-1))&(x-y))."
|
||||
|
||||
//!< Alternative min function
|
||||
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
|
||||
//!< Alternative max function
|
||||
inline_ sdword max_(sdword a, sdword b) { sdword delta = a-b; return a - (delta&(delta>>31)); }
|
||||
|
||||
// "Integer Selection
|
||||
// A branchless, lookup-free, alternative to code like if (a<b) x=c; else x=d; is ((((a-b) >> (WORDBITS-1)) & (c^d)) ^ d).
|
||||
// This code assumes that the shift is signed, which, of course, C does not promise."
|
||||
inline_ sdword IntegerSelection(sdword a, sdword b, sdword c, sdword d)
|
||||
{
|
||||
return ((((a-b)>>31) & (c^d)) ^ d);
|
||||
}
|
||||
|
||||
// Determine if one of the bytes in a 4 byte word is zero
|
||||
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
|
||||
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
|
||||
|
||||
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
|
||||
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
|
||||
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
|
||||
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
|
||||
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
|
||||
|
||||
// Most Significant 1 Bit
|
||||
// "Most Significant 1 Bit
|
||||
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
|
||||
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
|
||||
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
|
||||
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
|
||||
// yields the most significant bit. For a 32-bit value:
|
||||
// yields the most significant bit. For a 32-bit value:"
|
||||
inline_ udword msb32(udword x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
@@ -159,6 +199,23 @@ subject to the following restrictions:
|
||||
return (x & ~(x >> 1));
|
||||
}
|
||||
|
||||
// "Gray Code Conversion
|
||||
// A Gray code is any binary coding sequence in which only a single bit position changes as we move from one value to the next.
|
||||
// There are many such codes, but the traditional one is computed such that the Kth Gray code is K^(K>>1).
|
||||
//
|
||||
// The well-known algorithm for conversion from Gray to binary is a linear sequence of XORs that makes it seem each bit must be
|
||||
// dealt with separately. Fortunately, that is equivalent to a parallel prefix XOR that can be computed using SWAR techniques
|
||||
// in log time. For 32-bit Gray code values produced as described above, the conversion from Gray code back to unsigned binary is:"
|
||||
inline_ udword g2b(udword gray)
|
||||
{
|
||||
gray ^= (gray >> 16);
|
||||
gray ^= (gray >> 8);
|
||||
gray ^= (gray >> 4);
|
||||
gray ^= (gray >> 2);
|
||||
gray ^= (gray >> 1);
|
||||
return gray;
|
||||
}
|
||||
|
||||
/*
|
||||
"Just call it repeatedly with various input values and always with the same variable as "memory".
|
||||
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
|
||||
@@ -181,9 +238,9 @@ subject to the following restrictions:
|
||||
return memory = val * sharpness + memory * (1.0f - sharpness);
|
||||
}
|
||||
|
||||
//! If you can guarantee that your input domain (i.e. value of x) is slightly
|
||||
//! "If you can guarantee that your input domain (i.e. value of x) is slightly
|
||||
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
|
||||
//! following code to clamp the resulting value into [-32768,+32767] range:
|
||||
//! following code to clamp the resulting value into [-32768,+32767] range:"
|
||||
inline_ int ClampToInt16(int x)
|
||||
{
|
||||
// ASSERT(abs(x) < (int)((1<<31u)-32767));
|
||||
@@ -219,8 +276,12 @@ subject to the following restrictions:
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
|
||||
#if !defined(_XBOX)
|
||||
// Already defined on Xbox.
|
||||
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
@@ -236,7 +297,11 @@ subject to the following restrictions:
|
||||
#define IS_ALIGNED_4(x) ((x&3)==0)
|
||||
#define IS_ALIGNED_8(x) ((x&7)==0)
|
||||
|
||||
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
|
||||
// Updates a pointer with "stride" bytes
|
||||
inline_ void UpdatePtr(void*& ptr, udword stride) { ptr = ((ubyte*)ptr) + stride; }
|
||||
|
||||
// From Jon Watte IIRC
|
||||
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
|
||||
|
||||
// Compute implicit coords from an index:
|
||||
// The idea is to get back 2D coords from a 1D index.
|
||||
@@ -269,4 +334,44 @@ subject to the following restrictions:
|
||||
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
|
||||
}
|
||||
|
||||
#endif // __ICEUTILS_H__
|
||||
// Calling fsincos instead of fsin+fcos. Twice faster.
|
||||
inline_ void FSinCos(float& c, float& s, float f)
|
||||
{
|
||||
float LocalCos, LocalSin;
|
||||
float Local = f;
|
||||
#ifdef WIN32
|
||||
_asm fld Local
|
||||
_asm fsincos
|
||||
_asm fstp LocalCos
|
||||
_asm fstp LocalSin
|
||||
#elif LINUX
|
||||
asm("fld Local\n\t"
|
||||
"fsincos\n\t"
|
||||
"fstp LocalCos\n\t"
|
||||
"fstp LocalSin\n\t"
|
||||
);
|
||||
#endif
|
||||
c = LocalCos;
|
||||
s = LocalSin;
|
||||
}
|
||||
|
||||
// Modulo3 macros. See http://www.codercorner.com/Modulo3.htm
|
||||
#define GET_NEXT_INDICES(i, j, k) \
|
||||
k = 0x01000201; \
|
||||
k>>=(i<<3); \
|
||||
j = k & 0xff; \
|
||||
k>>=8; \
|
||||
k&=0xff;
|
||||
|
||||
#define GET_NEXT_INDICES2(i, j, k) \
|
||||
j = ( 9 >> (i<<1)) & 3; \
|
||||
k = (18 >> (i<<1)) & 3;
|
||||
|
||||
// 0=>1, 1=>2, 2=>0
|
||||
inline_ udword Modulo3(udword i)
|
||||
{
|
||||
ASSERT(i==0 || i==1 || i==2);
|
||||
return (9 >> (i << 1)) & 3;
|
||||
}
|
||||
|
||||
#endif // ICEUTILS_H
|
||||
|
||||
522
Extras/CDTestFramework/Opcode/Ice/_IceAABB.h
Normal file
522
Extras/CDTestFramework/Opcode/Ice/_IceAABB.h
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains AABB-related code. (axis-aligned bounding box)
|
||||
* \file IceAABB.h
|
||||
* \author Pierre Terdiman
|
||||
* \date January, 13, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEAABB_H__
|
||||
#define __ICEAABB_H__
|
||||
|
||||
// Forward declarations
|
||||
class Sphere;
|
||||
|
||||
//! Declarations of type-independent methods (most of them implemented in the .cpp)
|
||||
#define AABB_COMMON_METHODS \
|
||||
AABB& Add(const AABB& aabb); \
|
||||
float MakeCube(AABB& cube) const; \
|
||||
void MakeSphere(Sphere& sphere) const; \
|
||||
const sbyte* ComputeOutline(const Point& local_eye, sdword& num) const; \
|
||||
float ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const; \
|
||||
bool IsInside(const AABB& box) const; \
|
||||
bool ComputePlanes(Plane* planes) const; \
|
||||
bool ComputePoints(Point* pts) const; \
|
||||
const Point* GetVertexNormals() const; \
|
||||
const udword* GetEdges() const; \
|
||||
const Point* GetEdgeNormals() const; \
|
||||
inline_ BOOL ContainsPoint(const Point& p) const \
|
||||
{ \
|
||||
if(p.x > GetMax(0) || p.x < GetMin(0)) return FALSE; \
|
||||
if(p.y > GetMax(1) || p.y < GetMin(1)) return FALSE; \
|
||||
if(p.z > GetMax(2) || p.z < GetMin(2)) return FALSE; \
|
||||
return TRUE; \
|
||||
}
|
||||
|
||||
enum AABBType
|
||||
{
|
||||
AABB_RENDER = 0, //!< AABB used for rendering. Not visible == not rendered.
|
||||
AABB_UPDATE = 1, //!< AABB used for dynamic updates. Not visible == not updated.
|
||||
|
||||
AABB_FORCE_DWORD = 0x7fffffff,
|
||||
};
|
||||
|
||||
#ifdef USE_MINMAX
|
||||
|
||||
struct ICEMATHS_API ShadowAABB
|
||||
{
|
||||
Point mMin;
|
||||
Point mMax;
|
||||
};
|
||||
|
||||
class ICEMATHS_API AABB
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
inline_ AABB() {}
|
||||
//! Destructor
|
||||
inline_ ~AABB() {}
|
||||
|
||||
//! Type-independent methods
|
||||
AABB_COMMON_METHODS;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an AABB from min & max vectors.
|
||||
* \param min [in] the min point
|
||||
* \param max [in] the max point
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetMinMax(const Point& min, const Point& max) { mMin = min; mMax = max; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an AABB from center & extents vectors.
|
||||
* \param c [in] the center point
|
||||
* \param e [in] the extents vector
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetCenterExtents(const Point& c, const Point& e) { mMin = c - e; mMax = c + e; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an empty AABB.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetEmpty() { Point p(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); mMin = -p; mMax = p;}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups a point AABB.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetPoint(const Point& pt) { mMin = mMax = pt; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the size of the AABB. The size is defined as the longest extent.
|
||||
* \return the size of the AABB
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
float GetSize() const { Point e; GetExtents(e); return e.Max(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Extends the AABB.
|
||||
* \param p [in] the next point
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Extend(const Point& p)
|
||||
{
|
||||
if(p.x > mMax.x) mMax.x = p.x;
|
||||
if(p.x < mMin.x) mMin.x = p.x;
|
||||
|
||||
if(p.y > mMax.y) mMax.y = p.y;
|
||||
if(p.y < mMin.y) mMin.y = p.y;
|
||||
|
||||
if(p.z > mMax.z) mMax.z = p.z;
|
||||
if(p.z < mMin.z) mMin.z = p.z;
|
||||
}
|
||||
// Data access
|
||||
|
||||
//! Get min point of the box
|
||||
inline_ void GetMin(Point& min) const { min = mMin; }
|
||||
//! Get max point of the box
|
||||
inline_ void GetMax(Point& max) const { max = mMax; }
|
||||
|
||||
//! Get component of the box's min point along a given axis
|
||||
inline_ float GetMin(udword axis) const { return mMin[axis]; }
|
||||
//! Get component of the box's max point along a given axis
|
||||
inline_ float GetMax(udword axis) const { return mMax[axis]; }
|
||||
|
||||
//! Get box center
|
||||
inline_ void GetCenter(Point& center) const { center = (mMax + mMin)*0.5f; }
|
||||
//! Get box extents
|
||||
inline_ void GetExtents(Point& extents) const { extents = (mMax - mMin)*0.5f; }
|
||||
|
||||
//! Get component of the box's center along a given axis
|
||||
inline_ float GetCenter(udword axis) const { return (mMax[axis] + mMin[axis])*0.5f; }
|
||||
//! Get component of the box's extents along a given axis
|
||||
inline_ float GetExtents(udword axis) const { return (mMax[axis] - mMin[axis])*0.5f; }
|
||||
|
||||
//! Get box diagonal
|
||||
inline_ void GetDiagonal(Point& diagonal) const { diagonal = mMax - mMin; }
|
||||
inline_ float GetWidth() const { return mMax.x - mMin.x; }
|
||||
inline_ float GetHeight() const { return mMax.y - mMin.y; }
|
||||
inline_ float GetDepth() const { return mMax.z - mMin.z; }
|
||||
|
||||
//! Volume
|
||||
inline_ float GetVolume() const { return GetWidth() * GetHeight() * GetDepth(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Computes the intersection between two AABBs.
|
||||
* \param a [in] the other AABB
|
||||
* \return true on intersection
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL Intersect(const AABB& a) const
|
||||
{
|
||||
if(mMax.x < a.mMin.x
|
||||
|| a.mMax.x < mMin.x
|
||||
|| mMax.y < a.mMin.y
|
||||
|| a.mMax.y < mMin.y
|
||||
|| mMax.z < a.mMin.z
|
||||
|| a.mMax.z < mMin.z) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Computes the 1D-intersection between two AABBs, on a given axis.
|
||||
* \param a [in] the other AABB
|
||||
* \param axis [in] the axis (0, 1, 2)
|
||||
* \return true on intersection
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL Intersect(const AABB& a, udword axis) const
|
||||
{
|
||||
if(mMax[axis] < a.mMin[axis] || a.mMax[axis] < mMin[axis]) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
|
||||
* Original code by Charles Bloom on the GD-Algorithm list. (I slightly modified it)
|
||||
* \param mtx [in] the transform matrix
|
||||
* \param aabb [out] the transformed AABB [can be *this]
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const
|
||||
{
|
||||
// The three edges transformed: you can efficiently transform an X-only vector
|
||||
// by just getting the "X" column of the matrix
|
||||
Point vx,vy,vz;
|
||||
mtx.GetRow(0, vx); vx *= (mMax.x - mMin.x);
|
||||
mtx.GetRow(1, vy); vy *= (mMax.y - mMin.y);
|
||||
mtx.GetRow(2, vz); vz *= (mMax.z - mMin.z);
|
||||
|
||||
// Transform the min point
|
||||
aabb.mMin = aabb.mMax = mMin * mtx;
|
||||
|
||||
// Take the transformed min & axes and find new extents
|
||||
// Using CPU code in the right place is faster...
|
||||
if(IS_NEGATIVE_FLOAT(vx.x)) aabb.mMin.x += vx.x; else aabb.mMax.x += vx.x;
|
||||
if(IS_NEGATIVE_FLOAT(vx.y)) aabb.mMin.y += vx.y; else aabb.mMax.y += vx.y;
|
||||
if(IS_NEGATIVE_FLOAT(vx.z)) aabb.mMin.z += vx.z; else aabb.mMax.z += vx.z;
|
||||
if(IS_NEGATIVE_FLOAT(vy.x)) aabb.mMin.x += vy.x; else aabb.mMax.x += vy.x;
|
||||
if(IS_NEGATIVE_FLOAT(vy.y)) aabb.mMin.y += vy.y; else aabb.mMax.y += vy.y;
|
||||
if(IS_NEGATIVE_FLOAT(vy.z)) aabb.mMin.z += vy.z; else aabb.mMax.z += vy.z;
|
||||
if(IS_NEGATIVE_FLOAT(vz.x)) aabb.mMin.x += vz.x; else aabb.mMax.x += vz.x;
|
||||
if(IS_NEGATIVE_FLOAT(vz.y)) aabb.mMin.y += vz.y; else aabb.mMax.y += vz.y;
|
||||
if(IS_NEGATIVE_FLOAT(vz.z)) aabb.mMin.z += vz.z; else aabb.mMax.z += vz.z;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Checks the AABB is valid.
|
||||
* \return true if the box is valid
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL IsValid() const
|
||||
{
|
||||
// Consistency condition for (Min, Max) boxes: min < max
|
||||
if(mMin.x > mMax.x) return FALSE;
|
||||
if(mMin.y > mMax.y) return FALSE;
|
||||
if(mMin.z > mMax.z) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//! Operator for AABB *= float. Scales the extents, keeps same center.
|
||||
inline_ AABB& operator*=(float s)
|
||||
{
|
||||
Point Center; GetCenter(Center);
|
||||
Point Extents; GetExtents(Extents);
|
||||
SetCenterExtents(Center, Extents * s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Operator for AABB /= float. Scales the extents, keeps same center.
|
||||
inline_ AABB& operator/=(float s)
|
||||
{
|
||||
Point Center; GetCenter(Center);
|
||||
Point Extents; GetExtents(Extents);
|
||||
SetCenterExtents(Center, Extents / s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Operator for AABB += Point. Translates the box.
|
||||
inline_ AABB& operator+=(const Point& trans)
|
||||
{
|
||||
mMin+=trans;
|
||||
mMax+=trans;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
Point mMin; //!< Min point
|
||||
Point mMax; //!< Max point
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class ICEMATHS_API AABB
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
inline_ AABB() {}
|
||||
//! Destructor
|
||||
inline_ ~AABB() {}
|
||||
|
||||
//! Type-independent methods
|
||||
AABB_COMMON_METHODS;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an AABB from min & max vectors.
|
||||
* \param min [in] the min point
|
||||
* \param max [in] the max point
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an AABB from center & extents vectors.
|
||||
* \param c [in] the center point
|
||||
* \param e [in] the extents vector
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetCenterExtents(const Point& c, const Point& e) { mCenter = c; mExtents = e; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups an empty AABB.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetEmpty() { mCenter.Zero(); mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Setups a point AABB.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void SetPoint(const Point& pt) { mCenter = pt; mExtents.Zero(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the size of the AABB. The size is defined as the longest extent.
|
||||
* \return the size of the AABB
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
float GetSize() const { return mExtents.Max(); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Extends the AABB.
|
||||
* \param p [in] the next point
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void Extend(const Point& p)
|
||||
{
|
||||
Point Max = mCenter + mExtents;
|
||||
Point Min = mCenter - mExtents;
|
||||
|
||||
if(p.x > Max.x) Max.x = p.x;
|
||||
if(p.x < Min.x) Min.x = p.x;
|
||||
|
||||
if(p.y > Max.y) Max.y = p.y;
|
||||
if(p.y < Min.y) Min.y = p.y;
|
||||
|
||||
if(p.z > Max.z) Max.z = p.z;
|
||||
if(p.z < Min.z) Min.z = p.z;
|
||||
|
||||
SetMinMax(Min, Max);
|
||||
}
|
||||
// Data access
|
||||
|
||||
//! Get min point of the box
|
||||
inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
|
||||
//! Get max point of the box
|
||||
inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
|
||||
|
||||
//! Get component of the box's min point along a given axis
|
||||
inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
|
||||
//! Get component of the box's max point along a given axis
|
||||
inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
|
||||
|
||||
//! Get box center
|
||||
inline_ void GetCenter(Point& center) const { center = mCenter; }
|
||||
//! Get box extents
|
||||
inline_ void GetExtents(Point& extents) const { extents = mExtents; }
|
||||
|
||||
//! Get component of the box's center along a given axis
|
||||
inline_ float GetCenter(udword axis) const { return mCenter[axis]; }
|
||||
//! Get component of the box's extents along a given axis
|
||||
inline_ float GetExtents(udword axis) const { return mExtents[axis]; }
|
||||
|
||||
//! Get box diagonal
|
||||
inline_ void GetDiagonal(Point& diagonal) const { diagonal = mExtents * 2.0f; }
|
||||
inline_ float GetWidth() const { return mExtents.x * 2.0f; }
|
||||
inline_ float GetHeight() const { return mExtents.y * 2.0f; }
|
||||
inline_ float GetDepth() const { return mExtents.z * 2.0f; }
|
||||
|
||||
//! Volume
|
||||
inline_ float GetVolume() const { return mExtents.x * mExtents.y * mExtents.z * 8.0f; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Computes the intersection between two AABBs.
|
||||
* \param a [in] the other AABB
|
||||
* \return true on intersection
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL Intersect(const AABB& a) const
|
||||
{
|
||||
float tx = mCenter.x - a.mCenter.x; float ex = a.mExtents.x + mExtents.x; if(AIR(tx) > IR(ex)) return FALSE;
|
||||
float ty = mCenter.y - a.mCenter.y; float ey = a.mExtents.y + mExtents.y; if(AIR(ty) > IR(ey)) return FALSE;
|
||||
float tz = mCenter.z - a.mCenter.z; float ez = a.mExtents.z + mExtents.z; if(AIR(tz) > IR(ez)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* The standard intersection method from Gamasutra. Just here to check its speed against the one above.
|
||||
* \param a [in] the other AABB
|
||||
* \return true on intersection
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ bool GomezIntersect(const AABB& a)
|
||||
{
|
||||
Point T = mCenter - a.mCenter; // Vector from A to B
|
||||
return ((fabsf(T.x) <= (a.mExtents.x + mExtents.x))
|
||||
&& (fabsf(T.y) <= (a.mExtents.y + mExtents.y))
|
||||
&& (fabsf(T.z) <= (a.mExtents.z + mExtents.z)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Computes the 1D-intersection between two AABBs, on a given axis.
|
||||
* \param a [in] the other AABB
|
||||
* \param axis [in] the axis (0, 1, 2)
|
||||
* \return true on intersection
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL Intersect(const AABB& a, udword axis) const
|
||||
{
|
||||
float t = mCenter[axis] - a.mCenter[axis];
|
||||
float e = a.mExtents[axis] + mExtents[axis];
|
||||
if(AIR(t) > IR(e)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
|
||||
* \param mtx [in] the transform matrix
|
||||
* \param aabb [out] the transformed AABB [can be *this]
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const
|
||||
{
|
||||
// Compute new center
|
||||
aabb.mCenter = mCenter * mtx;
|
||||
|
||||
// Compute new extents. FPU code & CPU code have been interleaved for improved performance.
|
||||
Point Ex(mtx.m[0][0] * mExtents.x, mtx.m[0][1] * mExtents.x, mtx.m[0][2] * mExtents.x);
|
||||
IR(Ex.x)&=0x7fffffff; IR(Ex.y)&=0x7fffffff; IR(Ex.z)&=0x7fffffff;
|
||||
|
||||
Point Ey(mtx.m[1][0] * mExtents.y, mtx.m[1][1] * mExtents.y, mtx.m[1][2] * mExtents.y);
|
||||
IR(Ey.x)&=0x7fffffff; IR(Ey.y)&=0x7fffffff; IR(Ey.z)&=0x7fffffff;
|
||||
|
||||
Point Ez(mtx.m[2][0] * mExtents.z, mtx.m[2][1] * mExtents.z, mtx.m[2][2] * mExtents.z);
|
||||
IR(Ez.x)&=0x7fffffff; IR(Ez.y)&=0x7fffffff; IR(Ez.z)&=0x7fffffff;
|
||||
|
||||
aabb.mExtents.x = Ex.x + Ey.x + Ez.x;
|
||||
aabb.mExtents.y = Ex.y + Ey.y + Ez.y;
|
||||
aabb.mExtents.z = Ex.z + Ey.z + Ez.z;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Checks the AABB is valid.
|
||||
* \return true if the box is valid
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ BOOL IsValid() const
|
||||
{
|
||||
// Consistency condition for (Center, Extents) boxes: Extents >= 0
|
||||
if(IS_NEGATIVE_FLOAT(mExtents.x)) return FALSE;
|
||||
if(IS_NEGATIVE_FLOAT(mExtents.y)) return FALSE;
|
||||
if(IS_NEGATIVE_FLOAT(mExtents.z)) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//! Operator for AABB *= float. Scales the extents, keeps same center.
|
||||
inline_ AABB& operator*=(float s) { mExtents*=s; return *this; }
|
||||
|
||||
//! Operator for AABB /= float. Scales the extents, keeps same center.
|
||||
inline_ AABB& operator/=(float s) { mExtents/=s; return *this; }
|
||||
|
||||
//! Operator for AABB += Point. Translates the box.
|
||||
inline_ AABB& operator+=(const Point& trans)
|
||||
{
|
||||
mCenter+=trans;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
Point mCenter; //!< AABB Center
|
||||
Point mExtents; //!< x, y and z extents
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
inline_ void ComputeMinMax(const Point& p, Point& min, Point& max)
|
||||
{
|
||||
if(p.x > max.x) max.x = p.x;
|
||||
if(p.x < min.x) min.x = p.x;
|
||||
|
||||
if(p.y > max.y) max.y = p.y;
|
||||
if(p.y < min.y) min.y = p.y;
|
||||
|
||||
if(p.z > max.z) max.z = p.z;
|
||||
if(p.z < min.z) min.z = p.z;
|
||||
}
|
||||
|
||||
inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts)
|
||||
{
|
||||
if(list)
|
||||
{
|
||||
Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
|
||||
Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT);
|
||||
while(nb_pts--)
|
||||
{
|
||||
// _prefetch(list+1); // off by one ?
|
||||
ComputeMinMax(*list++, Mini, Maxi);
|
||||
}
|
||||
aabb.SetMinMax(Mini, Maxi);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __ICEAABB_H__
|
||||
361
Extras/CDTestFramework/Opcode/Ice/_IceContainer.cpp
Normal file
361
Extras/CDTestFramework/Opcode/Ice/_IceContainer.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains a simple container class.
|
||||
* \file IceContainer.cpp
|
||||
* \author Pierre Terdiman
|
||||
* \date February, 5, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains a list of 32-bits values.
|
||||
* Use this class when you need to store an unknown number of values. The list is automatically
|
||||
* resized and can contains 32-bits entities (dwords or floats)
|
||||
*
|
||||
* \class Container
|
||||
* \author Pierre Terdiman
|
||||
* \version 1.0
|
||||
* \date 08.15.98
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "Stdafx.h"
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
// Static members
|
||||
#ifdef CONTAINER_STATS
|
||||
udword Container::mNbContainers = 0;
|
||||
udword Container::mUsedRam = 0;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor. No entries allocated there.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor. Also allocates a given number of entries.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor)
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
#endif
|
||||
SetSize(size);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f)
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers++;
|
||||
mUsedRam+=sizeof(Container);
|
||||
#endif
|
||||
*this = object;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Destructor. Frees everything and leaves.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container::~Container()
|
||||
{
|
||||
Empty();
|
||||
#ifdef CONTAINER_STATS
|
||||
mNbContainers--;
|
||||
mUsedRam-=GetUsedRam();
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Clears the container. All stored values are deleted, and it frees used ram.
|
||||
* \see Reset()
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container& Container::Empty()
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
DELETEARRAY(mEntries);
|
||||
mCurNbEntries = mMaxNbEntries = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Resizes the container.
|
||||
* \param needed [in] assume the container can be added at least "needed" values
|
||||
* \return true if success.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Resize(udword needed)
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
// Subtract previous amount of bytes
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
// Get more entries
|
||||
mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2
|
||||
if(mMaxNbEntries<mCurNbEntries + needed) mMaxNbEntries = mCurNbEntries + needed;
|
||||
|
||||
// Get some bytes for new entries
|
||||
udword* NewEntries = new udword[mMaxNbEntries];
|
||||
CHECKALLOC(NewEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Add current amount of bytes
|
||||
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
// Copy old data if needed
|
||||
if(mCurNbEntries) CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||||
|
||||
// Delete old data
|
||||
DELETEARRAY(mEntries);
|
||||
|
||||
// Assign new pointer
|
||||
mEntries = NewEntries;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Sets the initial size of the container. If it already contains something, it's discarded.
|
||||
* \param nb [in] Number of entries
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::SetSize(udword nb)
|
||||
{
|
||||
// Make sure it's empty
|
||||
Empty();
|
||||
|
||||
// Checkings
|
||||
if(!nb) return false;
|
||||
|
||||
// Initialize for nb entries
|
||||
mMaxNbEntries = nb;
|
||||
|
||||
// Get some bytes for new entries
|
||||
mEntries = new udword[mMaxNbEntries];
|
||||
CHECKALLOC(mEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Add current amount of bytes
|
||||
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Refits the container and get rid of unused bytes.
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Refit()
|
||||
{
|
||||
#ifdef CONTAINER_STATS
|
||||
// Subtract previous amount of bytes
|
||||
mUsedRam-=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
// Get just enough entries
|
||||
mMaxNbEntries = mCurNbEntries;
|
||||
if(!mMaxNbEntries) return false;
|
||||
|
||||
// Get just enough bytes
|
||||
udword* NewEntries = new udword[mMaxNbEntries];
|
||||
CHECKALLOC(NewEntries);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
// Add current amount of bytes
|
||||
mUsedRam+=mMaxNbEntries*sizeof(udword);
|
||||
#endif
|
||||
|
||||
// Copy old data
|
||||
CopyMemory(NewEntries, mEntries, mCurNbEntries*sizeof(udword));
|
||||
|
||||
// Delete old data
|
||||
DELETEARRAY(mEntries);
|
||||
|
||||
// Assign new pointer
|
||||
mEntries = NewEntries;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Checks whether the container already contains a given value.
|
||||
* \param entry [in] the value to look for in the container
|
||||
* \param location [out] a possible pointer to store the entry location
|
||||
* \see Add(udword entry)
|
||||
* \see Add(float entry)
|
||||
* \see Empty()
|
||||
* \return true if the value has been found in the container, else false.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Contains(udword entry, udword* location) const
|
||||
{
|
||||
// Look for the entry
|
||||
for(udword i=0;i<mCurNbEntries;i++)
|
||||
{
|
||||
if(mEntries[i]==entry)
|
||||
{
|
||||
if(location) *location = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Deletes an entry. If the container contains such an entry, it's removed.
|
||||
* \param entry [in] the value to delete.
|
||||
* \return true if the value has been found in the container, else false.
|
||||
* \warning This method is arbitrary slow (O(n)) and should be used carefully. Insertion order is not preserved.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::Delete(udword entry)
|
||||
{
|
||||
// Look for the entry
|
||||
for(udword i=0;i<mCurNbEntries;i++)
|
||||
{
|
||||
if(mEntries[i]==entry)
|
||||
{
|
||||
// Entry has been found at index i. The strategy is to copy the last current entry at index i, and decrement the current number of entries.
|
||||
DeleteIndex(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Deletes an entry, preserving the insertion order. If the container contains such an entry, it's removed.
|
||||
* \param entry [in] the value to delete.
|
||||
* \return true if the value has been found in the container, else false.
|
||||
* \warning This method is arbitrary slow (O(n)) and should be used carefully.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Container::DeleteKeepingOrder(udword entry)
|
||||
{
|
||||
// Look for the entry
|
||||
for(udword i=0;i<mCurNbEntries;i++)
|
||||
{
|
||||
if(mEntries[i]==entry)
|
||||
{
|
||||
// Entry has been found at index i.
|
||||
// Shift entries to preserve order. You really should use a linked list instead.
|
||||
mCurNbEntries--;
|
||||
for(udword j=i;j<mCurNbEntries;j++)
|
||||
{
|
||||
mEntries[j] = mEntries[j+1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the next entry, starting from input one.
|
||||
* \param entry [in/out] On input, the entry to look for. On output, the next entry
|
||||
* \param find_mode [in] wrap/clamp
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container& Container::FindNext(udword& entry, FindMode find_mode)
|
||||
{
|
||||
udword Location;
|
||||
if(Contains(entry, &Location))
|
||||
{
|
||||
Location++;
|
||||
if(Location==mCurNbEntries) Location = find_mode==FIND_WRAP ? 0 : mCurNbEntries-1;
|
||||
entry = mEntries[Location];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the previous entry, starting from input one.
|
||||
* \param entry [in/out] On input, the entry to look for. On output, the previous entry
|
||||
* \param find_mode [in] wrap/clamp
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container& Container::FindPrev(udword& entry, FindMode find_mode)
|
||||
{
|
||||
udword Location;
|
||||
if(Contains(entry, &Location))
|
||||
{
|
||||
Location--;
|
||||
if(Location==0xffffffff) Location = find_mode==FIND_WRAP ? mCurNbEntries-1 : 0;
|
||||
entry = mEntries[Location];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the ram used by the container.
|
||||
* \return the ram used in bytes.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
udword Container::GetUsedRam() const
|
||||
{
|
||||
return sizeof(Container) + mMaxNbEntries * sizeof(udword);
|
||||
}
|
||||
|
||||
void Container::operator=(const Container& object)
|
||||
{
|
||||
SetSize(object.GetNbEntries());
|
||||
CopyMemory(mEntries, object.GetEntries(), mMaxNbEntries*sizeof(udword));
|
||||
mCurNbEntries = mMaxNbEntries;
|
||||
}
|
||||
228
Extras/CDTestFramework/Opcode/Ice/_IceContainer.h
Normal file
228
Extras/CDTestFramework/Opcode/Ice/_IceContainer.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains a simple container class.
|
||||
* \file IceContainer.h
|
||||
* \author Pierre Terdiman
|
||||
* \date February, 5, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICECONTAINER_H__
|
||||
#define __ICECONTAINER_H__
|
||||
|
||||
#define CONTAINER_STATS
|
||||
|
||||
enum FindMode
|
||||
{
|
||||
FIND_CLAMP,
|
||||
FIND_WRAP,
|
||||
|
||||
FIND_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
class ICECORE_API Container
|
||||
{
|
||||
public:
|
||||
// Constructor / Destructor
|
||||
Container();
|
||||
Container(const Container& object);
|
||||
Container(udword size, float growth_factor);
|
||||
~Container();
|
||||
// Management
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* A O(1) method to add a value in the container. The container is automatically resized if needed.
|
||||
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
|
||||
* costs a lot more than the call overhead...
|
||||
*
|
||||
* \param entry [in] a udword to store in the container
|
||||
* \see Add(float entry)
|
||||
* \see Empty()
|
||||
* \see Contains(udword entry)
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ Container& Add(udword entry)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries==mMaxNbEntries) Resize();
|
||||
|
||||
// Add new entry
|
||||
mEntries[mCurNbEntries++] = entry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline_ Container& Add(const udword* entries, udword nb)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
|
||||
|
||||
// Add new entry
|
||||
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword));
|
||||
mCurNbEntries+=nb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* A O(1) method to add a value in the container. The container is automatically resized if needed.
|
||||
* The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation
|
||||
* costs a lot more than the call overhead...
|
||||
*
|
||||
* \param entry [in] a float to store in the container
|
||||
* \see Add(udword entry)
|
||||
* \see Empty()
|
||||
* \see Contains(udword entry)
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ Container& Add(float entry)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries==mMaxNbEntries) Resize();
|
||||
|
||||
// Add new entry
|
||||
mEntries[mCurNbEntries++] = IR(entry);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline_ Container& Add(const float* entries, udword nb)
|
||||
{
|
||||
// Resize if needed
|
||||
if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb);
|
||||
|
||||
// Add new entry
|
||||
CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float));
|
||||
mCurNbEntries+=nb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Add unique [slow]
|
||||
inline_ Container& AddUnique(udword entry)
|
||||
{
|
||||
if(!Contains(entry)) Add(entry);
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Clears the container. All stored values are deleted, and it frees used ram.
|
||||
* \see Reset()
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Container& Empty();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again.
|
||||
* That's a kind of temporal coherence.
|
||||
* \see Empty()
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline_ void Reset()
|
||||
{
|
||||
// Avoid the write if possible
|
||||
// ### CMOV
|
||||
if(mCurNbEntries) mCurNbEntries = 0;
|
||||
}
|
||||
|
||||
// HANDLE WITH CARE
|
||||
inline_ void ForceSize(udword size)
|
||||
{
|
||||
mCurNbEntries = size;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Sets the initial size of the container. If it already contains something, it's discarded.
|
||||
* \param nb [in] Number of entries
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool SetSize(udword nb);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Refits the container and get rid of unused bytes.
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool Refit();
|
||||
|
||||
// Checks whether the container already contains a given value.
|
||||
bool Contains(udword entry, udword* location=null) const;
|
||||
// Deletes an entry - doesn't preserve insertion order.
|
||||
bool Delete(udword entry);
|
||||
// Deletes an entry - does preserve insertion order.
|
||||
bool DeleteKeepingOrder(udword entry);
|
||||
//! Deletes the very last entry.
|
||||
inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; }
|
||||
//! Deletes the entry whose index is given
|
||||
inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; }
|
||||
|
||||
// Helpers
|
||||
Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP);
|
||||
Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP);
|
||||
// Data access.
|
||||
inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries.
|
||||
inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry
|
||||
inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries.
|
||||
|
||||
inline_ udword GetFirst() const { return mEntries[0]; }
|
||||
inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; }
|
||||
|
||||
// Growth control
|
||||
inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor
|
||||
inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor
|
||||
inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full
|
||||
inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty
|
||||
|
||||
//! Read-access as an array
|
||||
inline_ udword operator[](udword i) const { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
|
||||
//! Write-access as an array
|
||||
inline_ udword& operator[](udword i) { ASSERT(i>=0 && i<mCurNbEntries); return mEntries[i]; }
|
||||
|
||||
// Stats
|
||||
udword GetUsedRam() const;
|
||||
|
||||
//! Operator for "Container A = Container B"
|
||||
void operator = (const Container& object);
|
||||
|
||||
#ifdef CONTAINER_STATS
|
||||
inline_ udword GetNbContainers() const { return mNbContainers; }
|
||||
inline_ udword GetTotalBytes() const { return mUsedRam; }
|
||||
private:
|
||||
|
||||
static udword mNbContainers; //!< Number of containers around
|
||||
static udword mUsedRam; //!< Amount of bytes used by containers in the system
|
||||
#endif
|
||||
private:
|
||||
// Resizing
|
||||
bool Resize(udword needed=1);
|
||||
// Data
|
||||
udword mMaxNbEntries; //!< Maximum possible number of entries
|
||||
udword mCurNbEntries; //!< Current number of entries
|
||||
udword* mEntries; //!< List of entries
|
||||
float mGrowthFactor; //!< Resize: new number of entries = old number * mGrowthFactor
|
||||
};
|
||||
|
||||
#endif // __ICECONTAINER_H__
|
||||
333
Extras/CDTestFramework/Opcode/Ice/_IceFPU.h
Normal file
333
Extras/CDTestFramework/Opcode/Ice/_IceFPU.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains FPU related code.
|
||||
* \file IceFPU.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEFPU_H__
|
||||
#define __ICEFPU_H__
|
||||
|
||||
#define SIGN_BITMASK 0x80000000
|
||||
|
||||
//! Integer representation of a floating-point value.
|
||||
#define IR(x) ((udword&)(x))
|
||||
|
||||
//! Signed integer representation of a floating-point value.
|
||||
#define SIR(x) ((sdword&)(x))
|
||||
|
||||
//! Absolute integer representation of a floating-point value
|
||||
#define AIR(x) (IR(x)&0x7fffffff)
|
||||
|
||||
//! Floating-point representation of an integer value.
|
||||
#define FR(x) ((float&)(x))
|
||||
|
||||
//! Integer-based comparison of a floating point value.
|
||||
//! Don't use it blindly, it can be faster or slower than the FPU comparison, depends on the context.
|
||||
#define IS_NEGATIVE_FLOAT(x) (IR(x)&0x80000000)
|
||||
|
||||
//! Fast fabs for floating-point values. It just clears the sign bit.
|
||||
//! Don't use it blindy, it can be faster or slower than the FPU comparison, depends on the context.
|
||||
inline_ float FastFabs(float x)
|
||||
{
|
||||
udword FloatBits = IR(x)&0x7fffffff;
|
||||
return FR(FloatBits);
|
||||
}
|
||||
|
||||
//! Fast square root for floating-point values.
|
||||
inline_ float FastSqrt(float square)
|
||||
{
|
||||
float retval;
|
||||
|
||||
__asm {
|
||||
mov eax, square
|
||||
sub eax, 0x3F800000
|
||||
sar eax, 1
|
||||
add eax, 0x3F800000
|
||||
mov [retval], eax
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//! Saturates positive to zero.
|
||||
inline_ float fsat(float f)
|
||||
{
|
||||
udword y = (udword&)f & ~((sdword&)f >>31);
|
||||
return (float&)y;
|
||||
}
|
||||
|
||||
//! Computes 1.0f / sqrtf(x).
|
||||
inline_ float frsqrt(float f)
|
||||
{
|
||||
float x = f * 0.5f;
|
||||
udword y = 0x5f3759df - ((udword&)f >> 1);
|
||||
// Iteration...
|
||||
(float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) );
|
||||
// Result
|
||||
return (float&)y;
|
||||
}
|
||||
|
||||
//! Computes 1.0f / sqrtf(x). Comes from NVIDIA.
|
||||
inline_ float InvSqrt(const float& x)
|
||||
{
|
||||
udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1;
|
||||
float y = *(float*)&tmp;
|
||||
return y * (1.47f - 0.47f * x * y * y);
|
||||
}
|
||||
|
||||
//! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above.
|
||||
//! See http://www.magic-software.com/3DGEDInvSqrt.html
|
||||
inline_ float RSqrt(float number)
|
||||
{
|
||||
long i;
|
||||
float x2, y;
|
||||
const float threehalfs = 1.5f;
|
||||
|
||||
x2 = number * 0.5f;
|
||||
y = number;
|
||||
i = * (long *) &y;
|
||||
i = 0x5f3759df - (i >> 1);
|
||||
y = * (float *) &i;
|
||||
y = y * (threehalfs - (x2 * y * y));
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
inline_ float fsqrt(float f)
|
||||
{
|
||||
udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000;
|
||||
// Iteration...?
|
||||
// (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f;
|
||||
// Result
|
||||
return (float&)y;
|
||||
}
|
||||
|
||||
//! Returns the float ranged espilon value.
|
||||
inline_ float fepsilon(float f)
|
||||
{
|
||||
udword b = (udword&)f & 0xff800000;
|
||||
udword a = b | 0x00000001;
|
||||
(float&)a -= (float&)b;
|
||||
// Result
|
||||
return (float&)a;
|
||||
}
|
||||
|
||||
//! Is the float valid ?
|
||||
inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; }
|
||||
inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; }
|
||||
inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; }
|
||||
inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; }
|
||||
|
||||
inline_ bool IsValidFloat(float value)
|
||||
{
|
||||
if(IsNAN(value)) return false;
|
||||
if(IsIndeterminate(value)) return false;
|
||||
if(IsPlusInf(value)) return false;
|
||||
if(IsMinusInf(value)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x));
|
||||
|
||||
/*
|
||||
//! FPU precision setting function.
|
||||
inline_ void SetFPU()
|
||||
{
|
||||
// This function evaluates whether the floating-point
|
||||
// control word is set to single precision/round to nearest/
|
||||
// exceptions disabled. If these conditions don't hold, the
|
||||
// function changes the control word to set them and returns
|
||||
// TRUE, putting the old control word value in the passback
|
||||
// location pointed to by pwOldCW.
|
||||
{
|
||||
uword wTemp, wSave;
|
||||
|
||||
__asm fstcw wSave
|
||||
if (wSave & 0x300 || // Not single mode
|
||||
0x3f != (wSave & 0x3f) || // Exceptions enabled
|
||||
wSave & 0xC00) // Not round to nearest mode
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov ax, wSave
|
||||
and ax, not 300h ;; single mode
|
||||
or ax, 3fh ;; disable all exceptions
|
||||
and ax, not 0xC00 ;; round to nearest mode
|
||||
mov wTemp, ax
|
||||
fldcw wTemp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
//! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON)
|
||||
inline_ float ComputeFloatEpsilon()
|
||||
{
|
||||
float f = 1.0f;
|
||||
((udword&)f)^=1;
|
||||
return f - 1.0f; // You can check it's the same as FLT_EPSILON
|
||||
}
|
||||
|
||||
inline_ bool IsFloatZero(float x, float epsilon=1e-6f)
|
||||
{
|
||||
return x*x < epsilon;
|
||||
}
|
||||
|
||||
#define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0
|
||||
#define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0
|
||||
#define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0
|
||||
#define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0
|
||||
|
||||
#define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1
|
||||
#define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1
|
||||
#define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1
|
||||
#define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1
|
||||
|
||||
#define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2
|
||||
#define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2
|
||||
#define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2
|
||||
#define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2
|
||||
|
||||
#define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3
|
||||
#define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3
|
||||
#define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3
|
||||
#define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3
|
||||
|
||||
#define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4
|
||||
#define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4
|
||||
#define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4
|
||||
#define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4
|
||||
|
||||
#define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5
|
||||
#define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5
|
||||
#define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5
|
||||
#define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5
|
||||
|
||||
#define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6
|
||||
#define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6
|
||||
#define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6
|
||||
#define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6
|
||||
|
||||
#define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7
|
||||
#define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7
|
||||
#define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7
|
||||
#define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7
|
||||
|
||||
//! A global function to find MAX(a,b) using FCOMI/FCMOV
|
||||
inline_ float FCMax2(float a, float b)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
FCOMI_ST1
|
||||
FCMOVB_ST1
|
||||
_asm fstp [Res]
|
||||
_asm fcomp
|
||||
return Res;
|
||||
}
|
||||
|
||||
//! A global function to find MIN(a,b) using FCOMI/FCMOV
|
||||
inline_ float FCMin2(float a, float b)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
FCOMI_ST1
|
||||
FCMOVNB_ST1
|
||||
_asm fstp [Res]
|
||||
_asm fcomp
|
||||
return Res;
|
||||
}
|
||||
|
||||
//! A global function to find MAX(a,b,c) using FCOMI/FCMOV
|
||||
inline_ float FCMax3(float a, float b, float c)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
_asm fld [c]
|
||||
FCOMI_ST1
|
||||
FCMOVB_ST1
|
||||
FCOMI_ST2
|
||||
FCMOVB_ST2
|
||||
_asm fstp [Res]
|
||||
_asm fcompp
|
||||
return Res;
|
||||
}
|
||||
|
||||
//! A global function to find MIN(a,b,c) using FCOMI/FCMOV
|
||||
inline_ float FCMin3(float a, float b, float c)
|
||||
{
|
||||
float Res;
|
||||
_asm fld [a]
|
||||
_asm fld [b]
|
||||
_asm fld [c]
|
||||
FCOMI_ST1
|
||||
FCMOVNB_ST1
|
||||
FCOMI_ST2
|
||||
FCMOVNB_ST2
|
||||
_asm fstp [Res]
|
||||
_asm fcompp
|
||||
return Res;
|
||||
}
|
||||
|
||||
inline_ int ConvertToSortable(float f)
|
||||
{
|
||||
int& Fi = (int&)f;
|
||||
int Fmask = (Fi>>31);
|
||||
Fi ^= Fmask;
|
||||
Fmask &= ~(1<<31);
|
||||
Fi -= Fmask;
|
||||
return Fi;
|
||||
}
|
||||
|
||||
enum FPUMode
|
||||
{
|
||||
FPU_FLOOR = 0,
|
||||
FPU_CEIL = 1,
|
||||
FPU_BEST = 2,
|
||||
|
||||
FPU_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
FUNCTION ICECORE_API FPUMode GetFPUMode();
|
||||
FUNCTION ICECORE_API void SaveFPU();
|
||||
FUNCTION ICECORE_API void RestoreFPU();
|
||||
FUNCTION ICECORE_API void SetFPUFloorMode();
|
||||
FUNCTION ICECORE_API void SetFPUCeilMode();
|
||||
FUNCTION ICECORE_API void SetFPUBestMode();
|
||||
|
||||
FUNCTION ICECORE_API void SetFPUPrecision24();
|
||||
FUNCTION ICECORE_API void SetFPUPrecision53();
|
||||
FUNCTION ICECORE_API void SetFPUPrecision64();
|
||||
FUNCTION ICECORE_API void SetFPURoundingChop();
|
||||
FUNCTION ICECORE_API void SetFPURoundingUp();
|
||||
FUNCTION ICECORE_API void SetFPURoundingDown();
|
||||
FUNCTION ICECORE_API void SetFPURoundingNear();
|
||||
|
||||
FUNCTION ICECORE_API int intChop(const float& f);
|
||||
FUNCTION ICECORE_API int intFloor(const float& f);
|
||||
FUNCTION ICECORE_API int intCeil(const float& f);
|
||||
|
||||
#endif // __ICEFPU_H__
|
||||
121
Extras/CDTestFramework/Opcode/Ice/_IceMemoryMacros.h
Normal file
121
Extras/CDTestFramework/Opcode/Ice/_IceMemoryMacros.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains all memory macros.
|
||||
* \file IceMemoryMacros.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEMEMORYMACROS_H__
|
||||
#define __ICEMEMORYMACROS_H__
|
||||
|
||||
#undef ZeroMemory
|
||||
#undef CopyMemory
|
||||
#undef MoveMemory
|
||||
#undef FillMemory
|
||||
|
||||
//! Clears a buffer.
|
||||
//! \param addr [in] buffer address
|
||||
//! \param size [in] buffer length
|
||||
//! \see FillMemory
|
||||
//! \see StoreDwords
|
||||
//! \see CopyMemory
|
||||
//! \see MoveMemory
|
||||
inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); }
|
||||
|
||||
//! Fills a buffer with a given byte.
|
||||
//! \param addr [in] buffer address
|
||||
//! \param size [in] buffer length
|
||||
//! \param val [in] the byte value
|
||||
//! \see StoreDwords
|
||||
//! \see ZeroMemory
|
||||
//! \see CopyMemory
|
||||
//! \see MoveMemory
|
||||
inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); }
|
||||
|
||||
//! Fills a buffer with a given dword.
|
||||
//! \param addr [in] buffer address
|
||||
//! \param nb [in] number of dwords to write
|
||||
//! \param value [in] the dword value
|
||||
//! \see FillMemory
|
||||
//! \see ZeroMemory
|
||||
//! \see CopyMemory
|
||||
//! \see MoveMemory
|
||||
//! \warning writes nb*4 bytes !
|
||||
inline_ void StoreDwords(udword* dest, udword nb, udword value)
|
||||
{
|
||||
// The asm code below **SHOULD** be equivalent to one of those C versions
|
||||
// or the other if your compiled is good: (checked on VC++ 6.0)
|
||||
//
|
||||
// 1) while(nb--) *dest++ = value;
|
||||
//
|
||||
// 2) for(udword i=0;i<nb;i++) dest[i] = value;
|
||||
//
|
||||
_asm push eax
|
||||
_asm push ecx
|
||||
_asm push edi
|
||||
_asm mov edi, dest
|
||||
_asm mov ecx, nb
|
||||
_asm mov eax, value
|
||||
_asm rep stosd
|
||||
_asm pop edi
|
||||
_asm pop ecx
|
||||
_asm pop eax
|
||||
}
|
||||
|
||||
//! Copies a buffer.
|
||||
//! \param addr [in] destination buffer address
|
||||
//! \param addr [in] source buffer address
|
||||
//! \param size [in] buffer length
|
||||
//! \see ZeroMemory
|
||||
//! \see FillMemory
|
||||
//! \see StoreDwords
|
||||
//! \see MoveMemory
|
||||
inline_ void CopyMemory(void* dest, const void* src, udword size) { memcpy(dest, src, size); }
|
||||
|
||||
//! Moves a buffer.
|
||||
//! \param addr [in] destination buffer address
|
||||
//! \param addr [in] source buffer address
|
||||
//! \param size [in] buffer length
|
||||
//! \see ZeroMemory
|
||||
//! \see FillMemory
|
||||
//! \see StoreDwords
|
||||
//! \see CopyMemory
|
||||
inline_ void MoveMemory(void* dest, const void* src, udword size) { memmove(dest, src, size); }
|
||||
|
||||
#define SIZEOFOBJECT sizeof(*this) //!< Gives the size of current object. Avoid some mistakes (e.g. "sizeof(this)").
|
||||
//#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); } //!< Clears current object. Laziness is my business. HANDLE WITH CARE.
|
||||
#define DELETESINGLE(x) if (x) { delete x; x = null; } //!< Deletes an instance of a class.
|
||||
#define DELETEARRAY(x) if (x) { delete []x; x = null; } //!< Deletes an array.
|
||||
#define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; } //!< Safe D3D-style release
|
||||
#define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release
|
||||
|
||||
#ifdef __ICEERROR_H__
|
||||
#define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE.
|
||||
#else
|
||||
#define CHECKALLOC(x) if(!x) return false;
|
||||
#endif
|
||||
|
||||
//! Standard allocation cycle
|
||||
#define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr);
|
||||
|
||||
#endif // __ICEMEMORYMACROS_H__
|
||||
144
Extras/CDTestFramework/Opcode/Ice/_IcePreprocessor.h
Normal file
144
Extras/CDTestFramework/Opcode/Ice/_IcePreprocessor.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains preprocessor stuff. This should be the first included header.
|
||||
* \file IcePreprocessor.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEPREPROCESSOR_H__
|
||||
#define __ICEPREPROCESSOR_H__
|
||||
|
||||
// Check platform
|
||||
#if defined( _WIN32 ) || defined( WIN32 )
|
||||
#pragma message("Compiling on Windows...")
|
||||
#define PLATFORM_WINDOWS
|
||||
#else
|
||||
#pragma message("Compiling on unknown platform...")
|
||||
#endif
|
||||
|
||||
// Check compiler
|
||||
#if defined(_MSC_VER)
|
||||
#pragma message("Compiling with VC++...")
|
||||
#define COMPILER_VISUAL_CPP
|
||||
#else
|
||||
#pragma message("Compiling with unknown compiler...")
|
||||
#endif
|
||||
|
||||
// Check compiler options. If this file is included in user-apps, this
|
||||
// shouldn't be needed, so that they can use what they like best.
|
||||
#ifndef ICE_DONT_CHECK_COMPILER_OPTIONS
|
||||
#ifdef COMPILER_VISUAL_CPP
|
||||
#if defined(_CHAR_UNSIGNED)
|
||||
#endif
|
||||
|
||||
#if defined(_CPPRTTI)
|
||||
#error Please disable RTTI...
|
||||
#endif
|
||||
|
||||
#if defined(_CPPUNWIND)
|
||||
#error Please disable exceptions...
|
||||
#endif
|
||||
|
||||
#if defined(_MT)
|
||||
// Multithreading
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Check debug mode
|
||||
#ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it.
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Here you may define items for debug builds
|
||||
#endif
|
||||
|
||||
#ifndef THIS_FILE
|
||||
#define THIS_FILE __FILE__
|
||||
#endif
|
||||
|
||||
#ifndef ICE_NO_DLL
|
||||
#ifdef ICECORE_EXPORTS
|
||||
#define ICECORE_API __declspec(dllexport)
|
||||
#else
|
||||
#define ICECORE_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define ICECORE_API
|
||||
#endif
|
||||
|
||||
// Don't override new/delete
|
||||
// #define DEFAULT_NEWDELETE
|
||||
#define DONT_TRACK_MEMORY_LEAKS
|
||||
|
||||
#define FUNCTION extern "C"
|
||||
|
||||
// Cosmetic stuff [mainly useful with multiple inheritance]
|
||||
#define override(base_class) virtual
|
||||
|
||||
// Our own inline keyword, so that:
|
||||
// - we can switch to __forceinline to check it's really better or not
|
||||
// - we can remove __forceinline if the compiler doesn't support it
|
||||
// #define inline_ __forceinline
|
||||
// #define inline_ inline
|
||||
|
||||
// Contributed by Bruce Mitchener
|
||||
#if defined(COMPILER_VISUAL_CPP)
|
||||
#define inline_ __forceinline
|
||||
// #define inline_ inline
|
||||
#elif defined(__GNUC__) && __GNUC__ < 3
|
||||
#define inline_ inline
|
||||
#elif defined(__GNUC__)
|
||||
#define inline_ inline __attribute__ ((always_inline))
|
||||
#else
|
||||
#define inline_ inline
|
||||
#endif
|
||||
|
||||
// Down the hatch
|
||||
#pragma inline_depth( 255 )
|
||||
|
||||
#ifdef COMPILER_VISUAL_CPP
|
||||
#pragma intrinsic(memcmp)
|
||||
#pragma intrinsic(memcpy)
|
||||
#pragma intrinsic(memset)
|
||||
#pragma intrinsic(strcat)
|
||||
#pragma intrinsic(strcmp)
|
||||
#pragma intrinsic(strcpy)
|
||||
#pragma intrinsic(strlen)
|
||||
#pragma intrinsic(abs)
|
||||
#pragma intrinsic(labs)
|
||||
#endif
|
||||
|
||||
// ANSI compliance
|
||||
#ifdef _DEBUG
|
||||
// Remove painful warning in debug
|
||||
inline_ bool __False__(){ return false; }
|
||||
#define for if(__False__()){} else for
|
||||
#else
|
||||
#define for if(0){} else for
|
||||
#endif
|
||||
|
||||
#endif // __ICEPREPROCESSOR_H__
|
||||
536
Extras/CDTestFramework/Opcode/Ice/_IceRevisitedRadix.cpp
Normal file
536
Extras/CDTestFramework/Opcode/Ice/_IceRevisitedRadix.cpp
Normal file
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
* \file IceRevisitedRadix.cpp
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Revisited Radix Sort.
|
||||
* This is my new radix routine:
|
||||
* - it uses indices and doesn't recopy the values anymore, hence wasting less ram
|
||||
* - it creates all the histograms in one run instead of four
|
||||
* - it sorts words faster than dwords and bytes faster than words
|
||||
* - it correctly sorts negative floating-point values by patching the offsets
|
||||
* - it automatically takes advantage of temporal coherence
|
||||
* - multiple keys support is a side effect of temporal coherence
|
||||
* - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway]
|
||||
*
|
||||
* History:
|
||||
* - 08.15.98: very first version
|
||||
* - 04.04.00: recoded for the radix article
|
||||
* - 12.xx.00: code lifting
|
||||
* - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here)
|
||||
* - 10.11.01: added local ram support
|
||||
* - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting......
|
||||
* - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all.
|
||||
* - ranks are not "reset" anymore, but implicit on first calls
|
||||
* - 07.05.02: - offsets rewritten with one less indirection.
|
||||
* - 11.03.02: - "bool" replaced with RadixHint enum
|
||||
*
|
||||
* \class RadixSort
|
||||
* \author Pierre Terdiman
|
||||
* \version 1.4
|
||||
* \date August, 15, 1998
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
To do:
|
||||
- add an offset parameter between two input values (avoid some data recopy sometimes)
|
||||
- unroll ? asm ?
|
||||
- 11 bits trick & 3 passes as Michael did
|
||||
- prefetch stuff the day I have a P3
|
||||
- make a version with 16-bits indices ?
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Precompiled Header
|
||||
#include "Stdafx.h"
|
||||
|
||||
using namespace IceCore;
|
||||
|
||||
#define INVALIDATE_RANKS mCurrentSize|=0x80000000
|
||||
#define VALIDATE_RANKS mCurrentSize&=0x7fffffff
|
||||
#define CURRENT_SIZE (mCurrentSize&0x7fffffff)
|
||||
#define INVALID_RANKS (mCurrentSize&0x80000000)
|
||||
|
||||
#define CHECK_RESIZE(n) \
|
||||
if(n!=mPreviousSize) \
|
||||
{ \
|
||||
if(n>mCurrentSize) Resize(n); \
|
||||
else ResetRanks(); \
|
||||
mPreviousSize = n; \
|
||||
}
|
||||
|
||||
#define CREATE_HISTOGRAMS(type, buffer) \
|
||||
/* Clear counters/histograms */ \
|
||||
ZeroMemory(mHistogram, 256*4*sizeof(udword)); \
|
||||
\
|
||||
/* Prepare to count */ \
|
||||
ubyte* p = (ubyte*)input; \
|
||||
ubyte* pe = &p[nb*4]; \
|
||||
udword* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \
|
||||
udword* h1= &mHistogram[256]; /* Histogram for second pass */ \
|
||||
udword* h2= &mHistogram[512]; /* Histogram for third pass */ \
|
||||
udword* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \
|
||||
\
|
||||
bool AlreadySorted = true; /* Optimism... */ \
|
||||
\
|
||||
if(INVALID_RANKS) \
|
||||
{ \
|
||||
/* Prepare for temporal coherence */ \
|
||||
type* Running = (type*)buffer; \
|
||||
type PrevVal = *Running; \
|
||||
\
|
||||
while(p!=pe) \
|
||||
{ \
|
||||
/* Read input buffer in previous sorted order */ \
|
||||
type Val = *Running++; \
|
||||
/* Check whether already sorted or not */ \
|
||||
if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
|
||||
/* Update for next iteration */ \
|
||||
PrevVal = Val; \
|
||||
\
|
||||
/* Create histograms */ \
|
||||
h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
|
||||
} \
|
||||
\
|
||||
/* If all input values are already sorted, we just have to return and leave the */ \
|
||||
/* previous list unchanged. That way the routine may take advantage of temporal */ \
|
||||
/* coherence, for example when used to sort transparent faces. */ \
|
||||
if(AlreadySorted) \
|
||||
{ \
|
||||
mNbHits++; \
|
||||
for(udword i=0;i<nb;i++) mRanks[i] = i; \
|
||||
return *this; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* Prepare for temporal coherence */ \
|
||||
udword* Indices = mRanks; \
|
||||
type PrevVal = (type)buffer[*Indices]; \
|
||||
\
|
||||
while(p!=pe) \
|
||||
{ \
|
||||
/* Read input buffer in previous sorted order */ \
|
||||
type Val = (type)buffer[*Indices++]; \
|
||||
/* Check whether already sorted or not */ \
|
||||
if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
|
||||
/* Update for next iteration */ \
|
||||
PrevVal = Val; \
|
||||
\
|
||||
/* Create histograms */ \
|
||||
h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
|
||||
} \
|
||||
\
|
||||
/* If all input values are already sorted, we just have to return and leave the */ \
|
||||
/* previous list unchanged. That way the routine may take advantage of temporal */ \
|
||||
/* coherence, for example when used to sort transparent faces. */ \
|
||||
if(AlreadySorted) { mNbHits++; return *this; } \
|
||||
} \
|
||||
\
|
||||
/* Else there has been an early out and we must finish computing the histograms */ \
|
||||
while(p!=pe) \
|
||||
{ \
|
||||
/* Create histograms without the previous overhead */ \
|
||||
h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
|
||||
}
|
||||
|
||||
#define CHECK_PASS_VALIDITY(pass) \
|
||||
/* Shortcut to current counters */ \
|
||||
udword* CurCount = &mHistogram[pass<<8]; \
|
||||
\
|
||||
/* Reset flag. The sorting pass is supposed to be performed. (default) */ \
|
||||
bool PerformPass = true; \
|
||||
\
|
||||
/* Check pass validity */ \
|
||||
\
|
||||
/* If all values have the same byte, sorting is useless. */ \
|
||||
/* It may happen when sorting bytes or words instead of dwords. */ \
|
||||
/* This routine actually sorts words faster than dwords, and bytes */ \
|
||||
/* faster than words. Standard running time (O(4*n))is reduced to O(2*n) */ \
|
||||
/* for words and O(n) for bytes. Running time for floats depends on actual values... */ \
|
||||
\
|
||||
/* Get first byte */ \
|
||||
ubyte UniqueVal = *(((ubyte*)input)+pass); \
|
||||
\
|
||||
/* Check that byte's counter */ \
|
||||
if(CurCount[UniqueVal]==nb) PerformPass=false;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort::RadixSort() : mRanks(null), mRanks2(null), mCurrentSize(0), mTotalCalls(0), mNbHits(0)
|
||||
{
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
// Allocate input-independent ram
|
||||
mHistogram = new udword[256*4];
|
||||
mOffset = new udword[256];
|
||||
#endif
|
||||
// Initialize indices
|
||||
INVALIDATE_RANKS;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort::~RadixSort()
|
||||
{
|
||||
// Release everything
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
DELETEARRAY(mOffset);
|
||||
DELETEARRAY(mHistogram);
|
||||
#endif
|
||||
DELETEARRAY(mRanks2);
|
||||
DELETEARRAY(mRanks);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Resizes the inner lists.
|
||||
* \param nb [in] new size (number of dwords)
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool RadixSort::Resize(udword nb)
|
||||
{
|
||||
// Free previously used ram
|
||||
DELETEARRAY(mRanks2);
|
||||
DELETEARRAY(mRanks);
|
||||
|
||||
// Get some fresh one
|
||||
mRanks = new udword[nb]; CHECKALLOC(mRanks);
|
||||
mRanks2 = new udword[nb]; CHECKALLOC(mRanks2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline_ void RadixSort::CheckResize(udword nb)
|
||||
{
|
||||
udword CurSize = CURRENT_SIZE;
|
||||
if(nb!=CurSize)
|
||||
{
|
||||
if(nb>CurSize) Resize(nb);
|
||||
mCurrentSize = nb;
|
||||
INVALIDATE_RANKS;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Main sort routine.
|
||||
* This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
|
||||
* \param input [in] a list of integer values to sort
|
||||
* \param nb [in] number of values to sort, must be < 2^31
|
||||
* \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
|
||||
{
|
||||
// Checkings
|
||||
if(!input || !nb || nb&0x80000000) return *this;
|
||||
|
||||
// Stats
|
||||
mTotalCalls++;
|
||||
|
||||
// Resize lists if needed
|
||||
CheckResize(nb);
|
||||
|
||||
#ifdef RADIX_LOCAL_RAM
|
||||
// Allocate histograms & offsets on the stack
|
||||
udword mHistogram[256*4];
|
||||
// udword mOffset[256];
|
||||
udword* mLink[256];
|
||||
#endif
|
||||
|
||||
// Create histograms (counters). Counters for all passes are created in one run.
|
||||
// Pros: read input buffer once instead of four times
|
||||
// Cons: mHistogram is 4Kb instead of 1Kb
|
||||
// We must take care of signed/unsigned values for temporal coherence.... I just
|
||||
// have 2 code paths even if just a single opcode changes. Self-modifying code, someone?
|
||||
if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(udword, input); }
|
||||
else { CREATE_HISTOGRAMS(sdword, input); }
|
||||
|
||||
// Compute #negative values involved if needed
|
||||
udword NbNegativeValues = 0;
|
||||
if(hint==RADIX_SIGNED)
|
||||
{
|
||||
// An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
|
||||
// last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
|
||||
// responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
|
||||
udword* h3= &mHistogram[768];
|
||||
for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
}
|
||||
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for(udword j=0;j<4;j++)
|
||||
{
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
// Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is
|
||||
// not a problem, numbers are correctly sorted anyway.
|
||||
if(PerformPass)
|
||||
{
|
||||
// Should we care about negative values?
|
||||
if(j!=3 || hint==RADIX_UNSIGNED)
|
||||
{
|
||||
// Here we deal with positive values only
|
||||
|
||||
// Create offsets
|
||||
// mOffset[0] = 0;
|
||||
// for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
mLink[0] = mRanks2;
|
||||
for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place.
|
||||
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
// mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
// for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// Fixing the wrong place for negative values
|
||||
// mOffset[128] = 0;
|
||||
mLink[128] = mRanks2;
|
||||
// for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
}
|
||||
|
||||
// Perform Radix Sort
|
||||
ubyte* InputBytes = (ubyte*)input;
|
||||
InputBytes += j;
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
// for(udword i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
|
||||
for(udword i=0;i<nb;i++) *mLink[InputBytes[i<<2]]++ = i;
|
||||
VALIDATE_RANKS;
|
||||
}
|
||||
else
|
||||
{
|
||||
udword* Indices = mRanks;
|
||||
udword* IndicesEnd = &mRanks[nb];
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
udword id = *Indices++;
|
||||
// mRanks2[mOffset[InputBytes[id<<2]]++] = id;
|
||||
*mLink[InputBytes[id<<2]]++ = id;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Main sort routine.
|
||||
* This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
|
||||
* \param input [in] a list of floating-point values to sort
|
||||
* \param nb [in] number of values to sort, must be < 2^31
|
||||
* \return Self-Reference
|
||||
* \warning only sorts IEEE floating-point values
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort& RadixSort::Sort(const float* input2, udword nb)
|
||||
{
|
||||
// Checkings
|
||||
if(!input2 || !nb || nb&0x80000000) return *this;
|
||||
|
||||
// Stats
|
||||
mTotalCalls++;
|
||||
|
||||
udword* input = (udword*)input2;
|
||||
|
||||
// Resize lists if needed
|
||||
CheckResize(nb);
|
||||
|
||||
#ifdef RADIX_LOCAL_RAM
|
||||
// Allocate histograms & offsets on the stack
|
||||
udword mHistogram[256*4];
|
||||
// udword mOffset[256];
|
||||
udword* mLink[256];
|
||||
#endif
|
||||
|
||||
// Create histograms (counters). Counters for all passes are created in one run.
|
||||
// Pros: read input buffer once instead of four times
|
||||
// Cons: mHistogram is 4Kb instead of 1Kb
|
||||
// Floating-point values are always supposed to be signed values, so there's only one code path there.
|
||||
// Please note the floating point comparison needed for temporal coherence! Although the resulting asm code
|
||||
// is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first
|
||||
// generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just
|
||||
// wouldn't work with mixed positive/negative values....
|
||||
{ CREATE_HISTOGRAMS(float, input2); }
|
||||
|
||||
// Compute #negative values involved if needed
|
||||
udword NbNegativeValues = 0;
|
||||
// An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
|
||||
// last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
|
||||
// responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
|
||||
udword* h3= &mHistogram[768];
|
||||
for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for(udword j=0;j<4;j++)
|
||||
{
|
||||
// Should we care about negative values?
|
||||
if(j!=3)
|
||||
{
|
||||
// Here we deal with positive values only
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
if(PerformPass)
|
||||
{
|
||||
// Create offsets
|
||||
// mOffset[0] = 0;
|
||||
mLink[0] = mRanks2;
|
||||
// for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
|
||||
|
||||
// Perform Radix Sort
|
||||
ubyte* InputBytes = (ubyte*)input;
|
||||
InputBytes += j;
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
// for(i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
|
||||
for(udword i=0;i<nb;i++) *mLink[InputBytes[i<<2]]++ = i;
|
||||
VALIDATE_RANKS;
|
||||
}
|
||||
else
|
||||
{
|
||||
udword* Indices = mRanks;
|
||||
udword* IndicesEnd = &mRanks[nb];
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
udword id = *Indices++;
|
||||
// mRanks2[mOffset[InputBytes[id<<2]]++] = id;
|
||||
*mLink[InputBytes[id<<2]]++ = id;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a special case to correctly handle negative values
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
if(PerformPass)
|
||||
{
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
// mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
|
||||
// for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// We must reverse the sorting order for negative numbers!
|
||||
// mOffset[255] = 0;
|
||||
mLink[255] = mRanks2;
|
||||
// for(i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
for(udword i=0;i<127;i++) mLink[254-i] = mLink[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
// for(i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values
|
||||
for(udword i=128;i<256;i++) mLink[i] += CurCount[i]; // Fixing the wrong place for negative values
|
||||
|
||||
// Perform Radix Sort
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
for(udword i=0;i<nb;i++)
|
||||
{
|
||||
udword Radix = input[i]>>24; // Radix byte, same as above. AND is useless here (udword).
|
||||
// ### cmp to be killed. Not good. Later.
|
||||
// if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above
|
||||
// else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order
|
||||
if(Radix<128) *mLink[Radix]++ = i; // Number is positive, same as above
|
||||
else *(--mLink[Radix]) = i; // Number is negative, flip the sorting order
|
||||
}
|
||||
VALIDATE_RANKS;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(udword i=0;i<nb;i++)
|
||||
{
|
||||
udword Radix = input[mRanks[i]]>>24; // Radix byte, same as above. AND is useless here (udword).
|
||||
// ### cmp to be killed. Not good. Later.
|
||||
// if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above
|
||||
// else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order
|
||||
if(Radix<128) *mLink[Radix]++ = mRanks[i]; // Number is positive, same as above
|
||||
else *(--mLink[Radix]) = mRanks[i]; // Number is negative, flip the sorting order
|
||||
}
|
||||
}
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The pass is useless, yet we still have to reverse the order of current list if all values are negative.
|
||||
if(UniqueVal>=128)
|
||||
{
|
||||
if(INVALID_RANKS)
|
||||
{
|
||||
// ###Possible?
|
||||
for(udword i=0;i<nb;i++) mRanks2[i] = nb-i-1;
|
||||
VALIDATE_RANKS;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(udword i=0;i<nb;i++) mRanks2[i] = mRanks[nb-i-1];
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
|
||||
udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the ram used.
|
||||
* \return memory used in bytes
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
udword RadixSort::GetUsedRam() const
|
||||
{
|
||||
udword UsedRam = sizeof(RadixSort);
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
UsedRam += 256*4*sizeof(udword); // Histograms
|
||||
UsedRam += 256*sizeof(udword); // Offsets
|
||||
#endif
|
||||
UsedRam += 2*CURRENT_SIZE*sizeof(udword); // 2 lists of indices
|
||||
return UsedRam;
|
||||
}
|
||||
81
Extras/CDTestFramework/Opcode/Ice/_IceRevisitedRadix.h
Normal file
81
Extras/CDTestFramework/Opcode/Ice/_IceRevisitedRadix.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
* \file IceRevisitedRadix.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICERADIXSORT_H__
|
||||
#define __ICERADIXSORT_H__
|
||||
|
||||
//! Allocate histograms & offsets locally
|
||||
#define RADIX_LOCAL_RAM
|
||||
|
||||
enum RadixHint
|
||||
{
|
||||
RADIX_SIGNED, //!< Input values are signed
|
||||
RADIX_UNSIGNED, //!< Input values are unsigned
|
||||
|
||||
RADIX_FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
|
||||
class ICECORE_API RadixSort
|
||||
{
|
||||
public:
|
||||
// Constructor/Destructor
|
||||
RadixSort();
|
||||
~RadixSort();
|
||||
// Sorting methods
|
||||
RadixSort& Sort(const udword* input, udword nb, RadixHint hint=RADIX_SIGNED);
|
||||
RadixSort& Sort(const float* input, udword nb);
|
||||
|
||||
//! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
|
||||
inline_ const udword* GetRanks() const { return mRanks; }
|
||||
|
||||
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
|
||||
inline_ udword* GetRecyclable() const { return mRanks2; }
|
||||
|
||||
// Stats
|
||||
udword GetUsedRam() const;
|
||||
//! Returns the total number of calls to the radix sorter.
|
||||
inline_ udword GetNbTotalCalls() const { return mTotalCalls; }
|
||||
//! Returns the number of eraly exits due to temporal coherence.
|
||||
inline_ udword GetNbHits() const { return mNbHits; }
|
||||
|
||||
private:
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
udword* mHistogram; //!< Counters for each byte
|
||||
udword* mOffset; //!< Offsets (nearly a cumulative distribution function)
|
||||
#endif
|
||||
udword mCurrentSize; //!< Current size of the indices list
|
||||
udword* mRanks; //!< Two lists, swapped each pass
|
||||
udword* mRanks2;
|
||||
// Stats
|
||||
udword mTotalCalls; //!< Total number of calls to the sort routine
|
||||
udword mNbHits; //!< Number of early exits due to coherence
|
||||
// Internal methods
|
||||
void CheckResize(udword nb);
|
||||
bool Resize(udword nb);
|
||||
};
|
||||
|
||||
#endif // __ICERADIXSORT_H__
|
||||
173
Extras/CDTestFramework/Opcode/Ice/_IceTypes.h
Normal file
173
Extras/CDTestFramework/Opcode/Ice/_IceTypes.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains custom types.
|
||||
* \file IceTypes.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICETYPES_H__
|
||||
#define __ICETYPES_H__
|
||||
|
||||
#define USE_HANDLE_MANAGER
|
||||
|
||||
// Constants
|
||||
#define PI 3.1415926535897932384626433832795028841971693993751f //!< PI
|
||||
#define HALFPI 1.57079632679489661923f //!< 0.5 * PI
|
||||
#define TWOPI 6.28318530717958647692f //!< 2.0 * PI
|
||||
#define INVPI 0.31830988618379067154f //!< 1.0 / PI
|
||||
|
||||
#define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees
|
||||
#define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians
|
||||
|
||||
#define EXP 2.71828182845904523536f //!< e
|
||||
#define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2)
|
||||
#define LN2 0.693147180559945f //!< ln(2)
|
||||
#define INVLN2 1.44269504089f //!< 1.0f / ln(2)
|
||||
|
||||
#define INV3 0.33333333333333333333f //!< 1/3
|
||||
#define INV6 0.16666666666666666666f //!< 1/6
|
||||
#define INV7 0.14285714285714285714f //!< 1/7
|
||||
#define INV9 0.11111111111111111111f //!< 1/9
|
||||
#define INV255 0.00392156862745098039f //!< 1/255
|
||||
|
||||
#define SQRT2 1.41421356237f //!< sqrt(2)
|
||||
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
|
||||
|
||||
#define SQRT3 1.73205080757f //!< sqrt(3)
|
||||
#define INVSQRT3 0.577350269189f //!< 1 / sqrt(3)
|
||||
|
||||
#define null 0 //!< our own NULL pointer
|
||||
|
||||
// Custom types used in ICE
|
||||
typedef signed char sbyte; //!< sizeof(sbyte) must be 1
|
||||
typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1
|
||||
typedef signed short sword; //!< sizeof(sword) must be 2
|
||||
typedef unsigned short uword; //!< sizeof(uword) must be 2
|
||||
typedef signed int sdword; //!< sizeof(sdword) must be 4
|
||||
typedef unsigned int udword; //!< sizeof(udword) must be 4
|
||||
typedef signed __int64 sqword; //!< sizeof(sqword) must be 8
|
||||
typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8
|
||||
typedef float float32; //!< sizeof(float32) must be 4
|
||||
typedef double float64; //!< sizeof(float64) must be 4
|
||||
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 !
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8);
|
||||
ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8);
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
#define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
|
||||
|
||||
typedef udword DynID; //!< Dynamic identifier
|
||||
#ifdef USE_HANDLE_MANAGER
|
||||
typedef udword KID; //!< Kernel ID
|
||||
// DECLARE_ICE_HANDLE(KID);
|
||||
#else
|
||||
typedef uword KID; //!< Kernel ID
|
||||
#endif
|
||||
typedef udword RTYPE; //!< Relationship-type (!) between owners and references
|
||||
#define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers)
|
||||
#ifdef USE_HANDLE_MANAGER
|
||||
#define INVALID_KID 0xffffffff //!< Invalid Kernel ID
|
||||
#else
|
||||
#define INVALID_KID 0xffff //!< Invalid Kernel ID
|
||||
#endif
|
||||
#define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value
|
||||
|
||||
// Define BOOL if needed
|
||||
#ifndef BOOL
|
||||
typedef int BOOL; //!< Another boolean type.
|
||||
#endif
|
||||
|
||||
//! Union of a float and a sdword
|
||||
typedef union {
|
||||
float f; //!< The float
|
||||
sdword d; //!< The integer
|
||||
}scell;
|
||||
|
||||
//! Union of a float and a udword
|
||||
typedef union {
|
||||
float f; //!< The float
|
||||
udword d; //!< The integer
|
||||
}ucell;
|
||||
|
||||
// Type ranges
|
||||
#define MAX_SBYTE 0x7f //!< max possible sbyte value
|
||||
#define MIN_SBYTE 0x80 //!< min possible sbyte value
|
||||
#define MAX_UBYTE 0xff //!< max possible ubyte value
|
||||
#define MIN_UBYTE 0x00 //!< min possible ubyte value
|
||||
#define MAX_SWORD 0x7fff //!< max possible sword value
|
||||
#define MIN_SWORD 0x8000 //!< min possible sword value
|
||||
#define MAX_UWORD 0xffff //!< max possible uword value
|
||||
#define MIN_UWORD 0x0000 //!< min possible uword value
|
||||
#define MAX_SDWORD 0x7fffffff //!< max possible sdword value
|
||||
#define MIN_SDWORD 0x80000000 //!< min possible sdword value
|
||||
#define MAX_UDWORD 0xffffffff //!< max possible udword value
|
||||
#define MIN_UDWORD 0x00000000 //!< min possible udword value
|
||||
#define MAX_FLOAT FLT_MAX //!< max possible float value
|
||||
#define MIN_FLOAT (-FLT_MAX) //!< min possible loat value
|
||||
#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0
|
||||
#define IEEE_255_0 0x437f0000 //!< integer representation of 255.0
|
||||
#define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT
|
||||
#define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT
|
||||
#define IEEE_UNDERFLOW_LIMIT 0x1a000000
|
||||
|
||||
#define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand()
|
||||
|
||||
typedef int (__stdcall* PROC)(); //!< A standard procedure call.
|
||||
typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call
|
||||
typedef void** VTABLE; //!< A V-Table.
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b
|
||||
#define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c
|
||||
|
||||
template<class T> inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; }
|
||||
template<class T> inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; }
|
||||
template<class T> inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; }
|
||||
template<class T> inline_ void TSetMax (T& a, const T& b) { if(a<b) a = b; }
|
||||
|
||||
#define SQR(x) ((x)*(x)) //!< Returns x square
|
||||
#define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube
|
||||
|
||||
#define AND & //!< ...
|
||||
#define OR | //!< ...
|
||||
#define XOR ^ //!< ...
|
||||
|
||||
#define QUADRAT(x) ((x)*(x)) //!< Returns x square
|
||||
|
||||
#ifdef _WIN32
|
||||
# define srand48(x) srand((unsigned int) (x))
|
||||
# define srandom(x) srand((unsigned int) (x))
|
||||
# define random() ((double) rand())
|
||||
# define drand48() ((double) (((double) rand()) / ((double) RAND_MAX)))
|
||||
#endif
|
||||
|
||||
#endif // __ICETYPES_H__
|
||||
272
Extras/CDTestFramework/Opcode/Ice/_IceUtils.h
Normal file
272
Extras/CDTestFramework/Opcode/Ice/_IceUtils.h
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* ICE / OPCODE - Optimized Collision Detection
|
||||
* http://www.codercorner.com/Opcode.htm
|
||||
*
|
||||
* Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains misc. useful macros & defines.
|
||||
* \file IceUtils.h
|
||||
* \author Pierre Terdiman (collected from various sources)
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef __ICEUTILS_H__
|
||||
#define __ICEUTILS_H__
|
||||
|
||||
#define START_RUNONCE { static bool __RunOnce__ = false; if(!__RunOnce__){
|
||||
#define END_RUNONCE __RunOnce__ = true;}}
|
||||
|
||||
//! Reverse all the bits in a 32 bit word (from Steve Baker's Cute Code Collection)
|
||||
//! (each line can be done in any order.
|
||||
inline_ void ReverseBits(udword& n)
|
||||
{
|
||||
n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
|
||||
n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
|
||||
n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
|
||||
n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
|
||||
n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
|
||||
// Etc for larger intergers (64 bits in Java)
|
||||
// NOTE: the >> operation must be unsigned! (>>> in java)
|
||||
}
|
||||
|
||||
//! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection)
|
||||
inline_ udword CountBits(udword n)
|
||||
{
|
||||
// This relies of the fact that the count of n bits can NOT overflow
|
||||
// an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts
|
||||
// 2 bit interger, 3 bit count requires only a 2 bit interger.
|
||||
// So we add all bit pairs, then each nible, then each byte etc...
|
||||
n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1);
|
||||
n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2);
|
||||
n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4);
|
||||
n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8);
|
||||
n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16);
|
||||
// Etc for larger intergers (64 bits in Java)
|
||||
// NOTE: the >> operation must be unsigned! (>>> in java)
|
||||
return n;
|
||||
}
|
||||
|
||||
//! Even faster?
|
||||
inline_ udword CountBits2(udword bits)
|
||||
{
|
||||
bits = bits - ((bits >> 1) & 0x55555555);
|
||||
bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333);
|
||||
bits = ((bits >> 4) + bits) & 0x0F0F0F0F;
|
||||
return (bits * 0x01010101) >> 24;
|
||||
}
|
||||
|
||||
//! Spread out bits. EG 00001111 -> 0101010101
|
||||
//! 00001010 -> 0100010000
|
||||
//! This is used to interleve to intergers to produce a `Morten Key'
|
||||
//! used in Space Filling Curves (See DrDobbs Journal, July 1999)
|
||||
//! Order is important.
|
||||
inline_ void SpreadBits(udword& n)
|
||||
{
|
||||
n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16);
|
||||
n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8);
|
||||
n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4);
|
||||
n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2);
|
||||
n = ( n & 0x11111111) | (( n & 0x22222222) << 1);
|
||||
}
|
||||
|
||||
// Next Largest Power of 2
|
||||
// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
|
||||
// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
|
||||
// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
|
||||
// largest power of 2. For a 32-bit value:
|
||||
inline_ udword nlpo2(udword x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
return x+1;
|
||||
}
|
||||
|
||||
//! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection)
|
||||
inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); }
|
||||
|
||||
//! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection)
|
||||
inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); }
|
||||
|
||||
//! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection)
|
||||
inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<<n); }
|
||||
|
||||
//! Classic XOR swap (from Steve Baker's Cute Code Collection)
|
||||
//! x ^= y; /* x' = (x^y) */
|
||||
//! y ^= x; /* y' = (y^(x^y)) = x */
|
||||
//! x ^= y; /* x' = (x^y)^x = y */
|
||||
inline_ void Swap(udword& x, udword& y) { x ^= y; y ^= x; x ^= y; }
|
||||
|
||||
//! Little/Big endian (from Steve Baker's Cute Code Collection)
|
||||
//!
|
||||
//! Extra comments by Kenny Hoff:
|
||||
//! Determines the byte-ordering of the current machine (little or big endian)
|
||||
//! by setting an integer value to 1 (so least significant bit is now 1); take
|
||||
//! the address of the int and cast to a byte pointer (treat integer as an
|
||||
//! array of four bytes); check the value of the first byte (must be 0 or 1).
|
||||
//! If the value is 1, then the first byte least significant byte and this
|
||||
//! implies LITTLE endian. If the value is 0, the first byte is the most
|
||||
//! significant byte, BIG endian. Examples:
|
||||
//! integer 1 on BIG endian: 00000000 00000000 00000000 00000001
|
||||
//! integer 1 on LITTLE endian: 00000001 00000000 00000000 00000000
|
||||
//!---------------------------------------------------------------------------
|
||||
//! int IsLittleEndian() { int x=1; return ( ((char*)(&x))[0] ); }
|
||||
inline_ char LittleEndian() { int i = 1; return *((char*)&i); }
|
||||
|
||||
//!< Alternative abs function
|
||||
inline_ udword abs_(sdword x) { sdword y= x >> 31; return (x^y)-y; }
|
||||
|
||||
//!< Alternative min function
|
||||
inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); }
|
||||
|
||||
// Determine if one of the bytes in a 4 byte word is zero
|
||||
inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); }
|
||||
|
||||
// To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0
|
||||
inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); }
|
||||
// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); }
|
||||
|
||||
// Most Significant 1 Bit
|
||||
// Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set)
|
||||
// can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits.
|
||||
// This process yields a bit vector with the same most significant 1 as x, but all 1's below it.
|
||||
// Bitwise AND of the original value with the complement of the "folded" value shifted down by one
|
||||
// yields the most significant bit. For a 32-bit value:
|
||||
inline_ udword msb32(udword x)
|
||||
{
|
||||
x |= (x >> 1);
|
||||
x |= (x >> 2);
|
||||
x |= (x >> 4);
|
||||
x |= (x >> 8);
|
||||
x |= (x >> 16);
|
||||
return (x & ~(x >> 1));
|
||||
}
|
||||
|
||||
/*
|
||||
"Just call it repeatedly with various input values and always with the same variable as "memory".
|
||||
The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1
|
||||
does no filtering at all.
|
||||
|
||||
I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed
|
||||
to the more typical FIR (Finite Impulse Response).
|
||||
|
||||
Also, I'd say that you can make more intelligent and interesting filters than this, for example filters
|
||||
that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter
|
||||
to be applied before this one, of course."
|
||||
|
||||
(JCAB on Flipcode)
|
||||
*/
|
||||
inline_ float FeedbackFilter(float val, float& memory, float sharpness)
|
||||
{
|
||||
ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter");
|
||||
if(sharpness<0.0f) sharpness = 0.0f;
|
||||
else if(sharpness>1.0f) sharpness = 1.0f;
|
||||
return memory = val * sharpness + memory * (1.0f - sharpness);
|
||||
}
|
||||
|
||||
//! If you can guarantee that your input domain (i.e. value of x) is slightly
|
||||
//! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the
|
||||
//! following code to clamp the resulting value into [-32768,+32767] range:
|
||||
inline_ int ClampToInt16(int x)
|
||||
{
|
||||
// ASSERT(abs(x) < (int)((1<<31u)-32767));
|
||||
|
||||
int delta = 32767 - x;
|
||||
x += (delta>>31) & delta;
|
||||
delta = x + 32768;
|
||||
x -= (delta>>31) & delta;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Generic functions
|
||||
template<class Type> inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; }
|
||||
template<class Type> inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((x<lo) ? lo : (x>hi) ? hi : x); }
|
||||
|
||||
template<class Type> inline_ void TSort(Type& a, Type& b)
|
||||
{
|
||||
if(a>b) TSwap(a, b);
|
||||
}
|
||||
|
||||
template<class Type> inline_ void TSort(Type& a, Type& b, Type& c)
|
||||
{
|
||||
if(a>b) TSwap(a, b);
|
||||
if(b>c) TSwap(b, c);
|
||||
if(a>b) TSwap(a, b);
|
||||
if(b>c) TSwap(b, c);
|
||||
}
|
||||
|
||||
// Prevent nasty user-manipulations (strategy borrowed from Charles Bloom)
|
||||
// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); }
|
||||
// ... actually this is better !
|
||||
#define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object);
|
||||
|
||||
//! TO BE DOCUMENTED
|
||||
#define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member)
|
||||
//! TO BE DOCUMENTED
|
||||
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Returns the alignment of the input address.
|
||||
* \fn Alignment()
|
||||
* \param address [in] address to check
|
||||
* \return the best alignment (e.g. 1 for odd addresses, etc)
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
FUNCTION ICECORE_API udword Alignment(udword address);
|
||||
|
||||
#define IS_ALIGNED_2(x) ((x&1)==0)
|
||||
#define IS_ALIGNED_4(x) ((x&3)==0)
|
||||
#define IS_ALIGNED_8(x) ((x&7)==0)
|
||||
|
||||
inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; }
|
||||
|
||||
// Compute implicit coords from an index:
|
||||
// The idea is to get back 2D coords from a 1D index.
|
||||
// For example:
|
||||
//
|
||||
// 0 1 2 ... nbu-1
|
||||
// nbu nbu+1 i ...
|
||||
//
|
||||
// We have i, we're looking for the equivalent (u=2, v=1) location.
|
||||
// i = u + v*nbu
|
||||
// <=> i/nbu = u/nbu + v
|
||||
// Since 0 <= u < nbu, u/nbu = 0 (integer)
|
||||
// Hence: v = i/nbu
|
||||
// Then we simply put it back in the original equation to compute u = i - v*nbu
|
||||
inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu)
|
||||
{
|
||||
v = i / nbu;
|
||||
u = i - (v * nbu);
|
||||
}
|
||||
|
||||
// In 3D: i = u + v*nbu + w*nbu*nbv
|
||||
// <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w
|
||||
// u/(nbu*nbv) is null since u/nbu was null already.
|
||||
// v/nbv is null as well for the same reason.
|
||||
// Hence w = i/(nbu*nbv)
|
||||
// Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu
|
||||
inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv)
|
||||
{
|
||||
w = i / (nbu_nbv);
|
||||
Compute2DCoords(u, v, i - (w * nbu_nbv), nbu);
|
||||
}
|
||||
|
||||
#endif // __ICEUTILS_H__
|
||||
1221
Extras/CDTestFramework/Opcode/OPC_ArraySAP.cpp
Normal file
1221
Extras/CDTestFramework/Opcode/OPC_ArraySAP.cpp
Normal file
File diff suppressed because it is too large
Load Diff
159
Extras/CDTestFramework/Opcode/OPC_ArraySAP.h
Normal file
159
Extras/CDTestFramework/Opcode/OPC_ArraySAP.h
Normal file
@@ -0,0 +1,159 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* OPCODE - Optimized Collision Detection
|
||||
* Copyright (C) 2001 Pierre Terdiman
|
||||
* Homepage: http://www.codercorner.com/Opcode.htm
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains an array-based version of the sweep-and-prune algorithm
|
||||
* \file OPC_ArraySAP.h
|
||||
* \author Pierre Terdiman
|
||||
* \date December, 2, 2007
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef OPC_ARRAYSAP_H
|
||||
#define OPC_ARRAYSAP_H
|
||||
|
||||
#pragma pack(1)
|
||||
struct OPCODE_API ASAP_Pair
|
||||
{
|
||||
uword id0;
|
||||
uword id1;
|
||||
const void* object0;
|
||||
const void* object1;
|
||||
//#ifdef PAIR_USER_DATA
|
||||
void* userData;
|
||||
//#endif
|
||||
inline_ const void* GetObject0() const { return (const void*)(size_t(object0) & ~3); }
|
||||
inline_ const void* GetObject1() const { return (const void*)(size_t(object1) & ~3); }
|
||||
inline_ size_t IsInArray() const { return size_t(object0) & 1; }
|
||||
inline_ size_t IsRemoved() const { return size_t(object1) & 1; }
|
||||
inline_ size_t IsNew() const { return size_t(object0) & 2; }
|
||||
private:
|
||||
inline_ void SetInArray() { object0 = (const void*)(size_t(object0) | 1); }
|
||||
inline_ void SetRemoved() { object1 = (const void*)(size_t(object1) | 1); }
|
||||
inline_ void SetNew() { object0 = (const void*)(size_t(object0) | 2); }
|
||||
inline_ void ClearInArray() { object0 = (const void*)(size_t(object0) & ~1); }
|
||||
inline_ void ClearRemoved() { object1 = (const void*)(size_t(object1) & ~1); }
|
||||
inline_ void ClearNew() { object0 = (const void*)(size_t(object0) & ~2); }
|
||||
|
||||
friend class ArraySAP;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
class OPCODE_API ASAP_PairManager
|
||||
{
|
||||
public:
|
||||
ASAP_PairManager();
|
||||
~ASAP_PairManager();
|
||||
|
||||
void Purge();
|
||||
void ShrinkMemory();
|
||||
|
||||
const ASAP_Pair* AddPair (uword id0, uword id1, const void* object0, const void* object1);
|
||||
bool RemovePair (uword id0, uword id1);
|
||||
bool RemovePairs (const BitArray& array);
|
||||
const ASAP_Pair* FindPair (uword id0, uword id1) const;
|
||||
inline_ udword GetPairIndex(const ASAP_Pair* pair) const
|
||||
{
|
||||
return ((udword)((size_t(pair) - size_t(mActivePairs)))/sizeof(ASAP_Pair));
|
||||
}
|
||||
|
||||
udword mHashSize;
|
||||
udword mMask;
|
||||
udword mNbActivePairs;
|
||||
udword* mHashTable;
|
||||
udword* mNext;
|
||||
ASAP_Pair* mActivePairs;
|
||||
inline_ ASAP_Pair* FindPair(uword id0, uword id1, udword hash_value) const;
|
||||
void RemovePair(uword id0, uword id1, udword hash_value, udword pair_index);
|
||||
void ReallocPairs();
|
||||
};
|
||||
|
||||
typedef void* (*SAP_CreatePair)(const void* object0, const void* object1, void* user_data);
|
||||
typedef void (*SAP_DeletePair)(const void* object0, const void* object1, void* user_data, void* pair_user_data);
|
||||
|
||||
// Forward declarations
|
||||
class ASAP_EndPoint;
|
||||
class ASAP_Box;
|
||||
struct IAABB;
|
||||
struct CreateData;
|
||||
|
||||
class OPCODE_API ArraySAP : public Allocateable
|
||||
{
|
||||
public:
|
||||
ArraySAP();
|
||||
~ArraySAP();
|
||||
|
||||
udword AddObject(void* object, uword guid, const AABB& box);
|
||||
bool RemoveObject(udword handle);
|
||||
bool UpdateObject(udword handle, const AABB& box);
|
||||
|
||||
udword DumpPairs(SAP_CreatePair create_cb, SAP_DeletePair delete_cb, void* cb_user_data, ASAP_Pair** pairs=null);
|
||||
private:
|
||||
Container mData;
|
||||
ASAP_PairManager mPairs;
|
||||
|
||||
inline_ void AddPair(const void* object0, const void* object1, uword id0, uword id1)
|
||||
{
|
||||
ASSERT(object0);
|
||||
ASAP_Pair* UP = (ASAP_Pair*)mPairs.AddPair(id0, id1, null, null);
|
||||
ASSERT(UP);
|
||||
|
||||
if(UP->object0)
|
||||
{
|
||||
// Persistent pair
|
||||
}
|
||||
else
|
||||
{
|
||||
// New pair
|
||||
ASSERT(!(int(object0)&1));
|
||||
ASSERT(!(int(object1)&1));
|
||||
UP->object0 = object0;
|
||||
UP->object1 = object1;
|
||||
UP->SetInArray();
|
||||
mData.Add(mPairs.GetPairIndex(UP));
|
||||
UP->SetNew();
|
||||
}
|
||||
UP->ClearRemoved();
|
||||
}
|
||||
|
||||
inline_ void RemovePair(const void* object0, const void* object1, uword id0, uword id1)
|
||||
{
|
||||
ASAP_Pair* UP = (ASAP_Pair*)mPairs.FindPair(id0, id1);
|
||||
if(UP)
|
||||
{
|
||||
if(!UP->IsInArray())
|
||||
{
|
||||
UP->SetInArray();
|
||||
mData.Add(mPairs.GetPairIndex(UP));
|
||||
}
|
||||
UP->SetRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
udword mNbBoxes;
|
||||
udword mMaxNbBoxes;
|
||||
ASAP_Box* mBoxes;
|
||||
ASAP_EndPoint* mEndPoints[3];
|
||||
udword mFirstFree;
|
||||
|
||||
void ResizeBoxArray();
|
||||
// For batch creation
|
||||
Container mCreated;
|
||||
void BatchCreate();
|
||||
void InsertEndPoints(udword axis, const ASAP_EndPoint* end_points, udword nb_endpoints);
|
||||
bool CompleteBoxPruning2(udword nb, const IAABB* array, const Axes& axes, const CreateData* batched);
|
||||
bool BipartiteBoxPruning2(udword nb0, const IAABB* array0, udword nb1, const IAABB* array1, const Axes& axes, const CreateData* batched, const udword* box_indices);
|
||||
// For batch removal
|
||||
Container mRemoved;
|
||||
void BatchRemove();
|
||||
};
|
||||
|
||||
#endif // OPC_ARRAYSAP_H
|
||||
@@ -67,17 +67,17 @@ static PRUNING_SORTER* gBipartitePruningSorter0 = null;
|
||||
static PRUNING_SORTER* gBipartitePruningSorter1 = null;
|
||||
inline_ PRUNING_SORTER* GetCompletePruningSorter()
|
||||
{
|
||||
if(!gCompletePruningSorter) gCompletePruningSorter = new PRUNING_SORTER;
|
||||
if(!gCompletePruningSorter) gCompletePruningSorter = ICE_NEW(PRUNING_SORTER);
|
||||
return gCompletePruningSorter;
|
||||
}
|
||||
inline_ PRUNING_SORTER* GetBipartitePruningSorter0()
|
||||
{
|
||||
if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = new PRUNING_SORTER;
|
||||
if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = ICE_NEW(PRUNING_SORTER);
|
||||
return gBipartitePruningSorter0;
|
||||
}
|
||||
inline_ PRUNING_SORTER* GetBipartitePruningSorter1()
|
||||
{
|
||||
if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = new PRUNING_SORTER;
|
||||
if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = ICE_NEW(PRUNING_SORTER);
|
||||
return gBipartitePruningSorter1;
|
||||
}
|
||||
void ReleasePruningSorters()
|
||||
|
||||
@@ -56,11 +56,14 @@ subject to the following restrictions:
|
||||
|
||||
namespace IceCore
|
||||
{
|
||||
#include ".\Ice\IceAllocator.h"
|
||||
#include ".\Ice\IceUtils.h"
|
||||
#include ".\Ice\IceBitArray.h"
|
||||
#include ".\Ice\IceContainer.h"
|
||||
#include ".\Ice\IcePairs.h"
|
||||
#include ".\Ice\IceRevisitedRadix.h"
|
||||
#include ".\Ice\IceRandom.h"
|
||||
#include ".\Ice\IceHashing.h"
|
||||
}
|
||||
using namespace IceCore;
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ subject to the following restrictions:
|
||||
// Sweep-and-prune
|
||||
#include "OPC_BoxPruning.h"
|
||||
#include "OPC_SweepAndPrune.h"
|
||||
#include "OPC_ArraySAP.h"
|
||||
|
||||
FUNCTION OPCODE_API bool InitOpcode();
|
||||
FUNCTION OPCODE_API bool CloseOpcode();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Version="8,00"
|
||||
Name="Opcode"
|
||||
ProjectGUID="{DBE44CA3-2912-4441-8D99-AA2242688AD2}"
|
||||
>
|
||||
@@ -825,6 +825,14 @@
|
||||
<Filter
|
||||
Name="SweepAndPrune"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\OPC_ArraySAP.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\OPC_ArraySAP.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="OPC_BoxPruning.cpp"
|
||||
>
|
||||
@@ -945,10 +953,30 @@
|
||||
RelativePath="Ice\IceAABB.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceAllocator.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceAllocator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceAssert.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="Ice\IceAxes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceBitArray.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceBitArray.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="Ice\IceBoundingSphere.h"
|
||||
>
|
||||
@@ -985,6 +1013,10 @@
|
||||
RelativePath="Ice\IceFPU.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Ice\IceHashing.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="Ice\IceHPoint.cpp"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user