diff --git a/KREngine/kraken/forsyth.cpp b/KREngine/3rdparty/forsyth/forsyth.cpp similarity index 100% rename from KREngine/kraken/forsyth.cpp rename to KREngine/3rdparty/forsyth/forsyth.cpp diff --git a/KREngine/kraken/forsyth.h b/KREngine/3rdparty/forsyth/forsyth.h similarity index 100% rename from KREngine/kraken/forsyth.h rename to KREngine/3rdparty/forsyth/forsyth.h diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTArray.h b/KREngine/3rdparty/pvrtexlib/include/PVRTArray.h new file mode 100644 index 0000000..ad58f87 --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTArray.h @@ -0,0 +1,565 @@ +/****************************************************************************** + + @File PVRTArray.h + + @Title PVRTArray + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description Expanding array template class. Allows appending and direct + access. Mixing access methods should be approached with caution. + +******************************************************************************/ +#ifndef __PVRTARRAY_H__ +#define __PVRTARRAY_H__ + +#include "PVRTGlobal.h" +#include "PVRTError.h" + +/*!**************************************************************************** +Class +******************************************************************************/ + +/*!*************************************************************************** +* @Class CPVRTArray +* @Brief Expanding array template class. +* @Description Expanding array template class. +*****************************************************************************/ +template +class CPVRTArray +{ +public: + /*!*************************************************************************** + @Function CPVRTArray + @Description Blank constructor. Makes a default sized array. + *****************************************************************************/ + CPVRTArray() : m_uiSize(0), m_uiCapacity(GetDefaultSize()) + { + m_pArray = new T[m_uiCapacity]; + } + + /*!*************************************************************************** + @Function CPVRTArray + @Input uiSize intial size of array + @Description Constructor taking initial size of array in elements. + *****************************************************************************/ + CPVRTArray(const unsigned int uiSize) : m_uiSize(0), m_uiCapacity(uiSize) + { + _ASSERT(uiSize != 0); + m_pArray = new T[uiSize]; + } + + /*!*************************************************************************** + @Function CPVRTArray + @Input original the other dynamic array + @Description Copy constructor. + *****************************************************************************/ + CPVRTArray(const CPVRTArray& original) : m_uiSize(original.m_uiSize), + m_uiCapacity(original.m_uiCapacity) + { + m_pArray = new T[m_uiCapacity]; + for(unsigned int i=0;i= m_uiSize) // Are we adding to the end + uiIndex = Append(addT); + else + { + unsigned int uiNewCapacity = 0; + T* pArray = m_pArray; + + if(m_uiSize > m_uiCapacity) + { + uiNewCapacity = m_uiCapacity + 10; // Expand the array by 10. + + pArray = new T[uiNewCapacity]; // New Array + + if(!pArray) + return -1; // Failed to allocate memory! + + // Copy the first half to the new array + for(unsigned int i = 0; i < pos; ++i) + { + pArray[i] = m_pArray[i]; + } + } + + // Copy last half to the new array + for(unsigned int i = m_uiSize; i > pos; --i) + { + pArray[i] = m_pArray[i - 1]; + } + + // Insert our new element + pArray[pos] = addT; + uiIndex = pos; + + // Increase our size + ++m_uiSize; + + // Switch pointers and free memory if needed + if(pArray != m_pArray) + { + m_uiCapacity = uiNewCapacity; + delete[] m_pArray; + m_pArray = pArray; + } + } + + return uiIndex; + } + + /*!*************************************************************************** + @Function Append + @Input addT The element to append + @Return The index of the new item. + @Description Appends an element to the end of the array, expanding it + if necessary. + *****************************************************************************/ + unsigned int Append(const T& addT) + { + unsigned int uiIndex = Append(); + m_pArray[uiIndex] = addT; + return uiIndex; + } + + /*!*************************************************************************** + @Function Append + @Return The index of the new item. + @Description Creates space for a new item, but doesn't add. Instead + returns the index of the new item. + *****************************************************************************/ + unsigned int Append() + { + unsigned int uiIndex = m_uiSize; + SetCapacity(m_uiSize+1); + m_uiSize++; + + return uiIndex; + } + + /*!*************************************************************************** + @Function Clear + @Description Clears the array. + *****************************************************************************/ + void Clear() + { + m_uiSize = 0U; + } + + /*!*************************************************************************** + @Function Resize + @Input uiSize New size of array + @Description Changes the array to the new size + *****************************************************************************/ + EPVRTError Resize(const unsigned int uiSize) + { + EPVRTError err = SetCapacity(uiSize); + + if(err != PVR_SUCCESS) + return err; + + m_uiSize = uiSize; + return PVR_SUCCESS; + } + + /*!*************************************************************************** + @Function SetCapacity + @Input uiSize New capacity of array + @Description Expands array to new capacity + *****************************************************************************/ + EPVRTError SetCapacity(const unsigned int uiSize) + { + if(uiSize <= m_uiCapacity) + return PVR_SUCCESS; // nothing to be done + + unsigned int uiNewCapacity; + if(uiSize < m_uiCapacity*2) + { + uiNewCapacity = m_uiCapacity*2; // Ignore the new size. Expand to twice the previous size. + } + else + { + uiNewCapacity = uiSize; + } + + T* pNewArray = new T[uiNewCapacity]; // New Array + if(!pNewArray) + return PVR_FAIL; // Failed to allocate memory! + + // Copy source data to new array + for(unsigned int i = 0; i < m_uiSize; ++i) + { + pNewArray[i] = m_pArray[i]; + } + + // Switch pointers and free memory + m_uiCapacity = uiNewCapacity; + T* pOldArray = m_pArray; + m_pArray = pNewArray; + delete [] pOldArray; + return PVR_SUCCESS; + } + + /*!*************************************************************************** + @Function Copy + @Input other The CPVRTArray needing copied + @Description A copy function. Will attempt to copy from other CPVRTArrays + if this is possible. + *****************************************************************************/ + template + void Copy(const CPVRTArray& other) + { + T* pNewArray = new T[other.GetCapacity()]; + if(pNewArray) + { + // Copy data + for(unsigned int i = 0; i < other.GetSize(); i++) + { + pNewArray[i] = other[i]; + } + + // Free current array + if(m_pArray) + delete [] m_pArray; + + // Swap pointers + m_pArray = pNewArray; + + m_uiCapacity = other.GetCapacity(); + m_uiSize = other.GetSize(); + } + } + + /*!*************************************************************************** + @Function = + @Input other The CPVRTArray needing copied + @Description assignment operator. + *****************************************************************************/ + CPVRTArray& operator=(const CPVRTArray& other) + { + if(&other != this) + Copy(other); + + return *this; + } + + /*!*************************************************************************** + @Function operator+= + @Input other the array to append. + @Description appends an existing CPVRTArray on to this one. + *****************************************************************************/ + CPVRTArray& operator+=(const CPVRTArray& other) + { + if(&other != this) + { + for(unsigned int uiIndex = 0; uiIndex < other.GetSize(); ++uiIndex) + { + Append(other[uiIndex]); + } + } + + return *this; + } + + /*!*************************************************************************** + @Function [] + @Input uiIndex index of element in array + @Return the element indexed + @Description indexed access into array. Note that this has no error + checking whatsoever + *****************************************************************************/ + T& operator[](const unsigned int uiIndex) + { + _ASSERT(uiIndex < m_uiCapacity); + return m_pArray[uiIndex]; + } + + /*!*************************************************************************** + @Function [] + @Input uiIndex index of element in array + @Return The element indexed + @Description Indexed access into array. Note that this has no error + checking whatsoever + *****************************************************************************/ + const T& operator[](const unsigned int uiIndex) const + { + _ASSERT(uiIndex < m_uiCapacity); + return m_pArray[uiIndex]; + } + + /*!*************************************************************************** + @Function GetSize + @Return Size of array + @Description Gives current size of array/number of elements + *****************************************************************************/ + unsigned int GetSize() const + { + return m_uiSize; + } + + /*!*************************************************************************** + @Function GetDefaultSize + @Return Default size of array + @Description Gives the default size of array/number of elements + *****************************************************************************/ + static unsigned int GetDefaultSize() + { + return 16U; + } + + /*!*************************************************************************** + @Function GetCapacity + @Return Capacity of array + @Description Gives current allocated size of array/number of elements + *****************************************************************************/ + unsigned int GetCapacity() const + { + return m_uiCapacity; + } + + /*!*************************************************************************** + @Function Contains + @Input object The object to check in the array + @Return true if object is contained in this array. + @Description Indicates whether the given object resides inside the + array. + *****************************************************************************/ + bool Contains(const T& object) const + { + for(unsigned int uiIndex = 0; uiIndex < m_uiSize; ++uiIndex) + { + if(m_pArray[uiIndex] == object) + return true; + } + return false; + } + + /*!*************************************************************************** + @Function Find + @Input object The object to check in the array + @Return pointer to the found object or NULL. + @Description Attempts to find the object in the array and returns a + pointer if it is found, or NULL if not found. The time + taken is O(N). + *****************************************************************************/ + T* Find(const T& object) const + { + for(unsigned int uiIndex = 0; uiIndex < m_uiSize; ++uiIndex) + { + if(m_pArray[uiIndex] == object) + return &m_pArray[uiIndex]; + } + return NULL; + } + + /*!*************************************************************************** + @Function Sort + @Input predicate The object which defines "bool operator()" + @Description Simple bubble-sort of the array. Pred should be an object that + defines a bool operator(). + *****************************************************************************/ + template + void Sort(Pred predicate) + { + bool bSwap; + for(unsigned int i=0; i < m_uiSize; ++i) + { + bSwap = false; + for(unsigned int j=0; j < m_uiSize-1; ++j) + { + if(predicate(m_pArray[j], m_pArray[j+1])) + { + PVRTswap(m_pArray[j], m_pArray[j+1]); + bSwap = true; + } + } + + if(!bSwap) + return; + } + } + + /*!*************************************************************************** + @Function Remove + @Input uiIndex The index to remove + @Return success or failure + @Description Removes an element from the array. + *****************************************************************************/ + virtual EPVRTError Remove(unsigned int uiIndex) + { + _ASSERT(uiIndex < m_uiSize); + if(m_uiSize == 0) + return PVR_FAIL; + + if(uiIndex == m_uiSize-1) + { + return RemoveLast(); + } + + m_uiSize--; + // Copy the data. memmove will only work for built-in types. + for(unsigned int uiNewIdx = uiIndex; uiNewIdx < m_uiSize; ++uiNewIdx) + { + m_pArray[uiNewIdx] = m_pArray[uiNewIdx+1]; + } + + return PVR_SUCCESS; + } + + /*!*************************************************************************** + @Function RemoveLast + @Return success or failure + @Description Removes the last element. Simply decrements the size value + *****************************************************************************/ + virtual EPVRTError RemoveLast() + { + if(m_uiSize > 0) + { + m_uiSize--; + return PVR_SUCCESS; + } + else + { + return PVR_FAIL; + } + } + +protected: + unsigned int m_uiSize; /*! current size of contents of array */ + unsigned int m_uiCapacity; /*! currently allocated size of array */ + T *m_pArray; /*! the actual array itself */ +}; + +// note "this" is required for ISO standard C++ and gcc complains otherwise +// http://lists.apple.com/archives/Xcode-users//2005/Dec/msg00644.html +template +class CPVRTArrayManagedPointers : public CPVRTArray +{ +public: + virtual ~CPVRTArrayManagedPointers() + { + if(this->m_pArray) + { + for(unsigned int i=0;im_uiSize;i++) + { + delete(this->m_pArray[i]); + } + } + } + + /*!*************************************************************************** + @Function Remove + @Input uiIndex The index to remove + @Return success or failure + @Description Removes an element from the array. + *****************************************************************************/ + virtual EPVRTError Remove(unsigned int uiIndex) + { + _ASSERT(uiIndex < this->m_uiSize); + if(this->m_uiSize == 0) + return PVR_FAIL; + + if(uiIndex == this->m_uiSize-1) + { + return this->RemoveLast(); + } + + unsigned int uiSize = (this->m_uiSize - (uiIndex+1)) * sizeof(T*); + + delete this->m_pArray[uiIndex]; + memmove(this->m_pArray + uiIndex, this->m_pArray + (uiIndex+1), uiSize); + + this->m_uiSize--; + return PVR_SUCCESS; + } + + /*!*************************************************************************** + @Function RemoveLast + @Return success or failure + @Description Removes the last element. Simply decrements the size value + *****************************************************************************/ + virtual EPVRTError RemoveLast() + { + if(this->m_uiSize > 0 && this->m_pArray) + { + delete this->m_pArray[this->m_uiSize-1]; + this->m_uiSize--; + return PVR_SUCCESS; + } + else + { + return PVR_FAIL; + } + } +}; + +#endif // __PVRTARRAY_H__ + +/***************************************************************************** +End of file (PVRTArray.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTDecompress.h b/KREngine/3rdparty/pvrtexlib/include/PVRTDecompress.h new file mode 100644 index 0000000..71a008b --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTDecompress.h @@ -0,0 +1,58 @@ +/****************************************************************************** + + @File PVRTDecompress.h + + @Title PVRTDecompress + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description PVRTC and ETC Texture Decompression. + +******************************************************************************/ + +#ifndef _PVRTDECOMPRESS_H_ +#define _PVRTDECOMPRESS_H_ + +/*!*********************************************************************** + @Function PVRTDecompressPVRTC + @Input pCompressedData The PVRTC texture data to decompress + @Input Do2bitMode Signifies whether the data is PVRTC2 or PVRTC4 + @Input XDim X dimension of the texture + @Input YDim Y dimension of the texture + @Return Returns the amount of data that was decompressed. + @Modified pResultImage The decompressed texture data + @Description Decompresses PVRTC to RGBA 8888 +*************************************************************************/ +int PVRTDecompressPVRTC(const void *pCompressedData, + const int Do2bitMode, + const int XDim, + const int YDim, + unsigned char* pResultImage); + +/*!*********************************************************************** +@Function PVRTDecompressETC +@Input pSrcData The ETC texture data to decompress +@Input x X dimension of the texture +@Input y Y dimension of the texture +@Modified pDestData The decompressed texture data +@Input nMode The format of the data +@Returns The number of bytes of ETC data decompressed +@Description Decompresses ETC to RGBA 8888 +*************************************************************************/ +int PVRTDecompressETC(const void * const pSrcData, + const unsigned int &x, + const unsigned int &y, + void *pDestData, + const int &nMode); + + +#endif /* _PVRTDECOMPRESS_H_ */ + +/***************************************************************************** + End of file (PVRTBoneBatch.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTError.h b/KREngine/3rdparty/pvrtexlib/include/PVRTError.h new file mode 100644 index 0000000..357a1ab --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTError.h @@ -0,0 +1,71 @@ +/****************************************************************************** + + @File PVRTError.h + + @Title PVRTError + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description + +******************************************************************************/ +#ifndef _PVRTERROR_H_ +#define _PVRTERROR_H_ + +#if defined(ANDROID) + #include +#else + #if defined(_WIN32) + #include + #else + #include + #endif +#endif +/*!*************************************************************************** + Macros +*****************************************************************************/ + +/*! Outputs a string to the standard error if built for debugging. */ +#if !defined(PVRTERROR_OUTPUT_DEBUG) + #if defined(_DEBUG) || defined(DEBUG) + #if defined(ANDROID) + #define PVRTERROR_OUTPUT_DEBUG(A) __android_log_print(ANDROID_LOG_INFO, "PVRTools", A); + #elif defined(_WIN32) && !defined(UNDER_CE) + #define PVRTERROR_OUTPUT_DEBUG(A) OutputDebugStringA(A); + #else + #define PVRTERROR_OUTPUT_DEBUG(A) fprintf(stderr,A); + #endif + #else + #define PVRTERROR_OUTPUT_DEBUG(A) + #endif +#endif + + +/*!*************************************************************************** + Enums +*****************************************************************************/ +/*! Enum error codes */ +enum EPVRTError +{ + PVR_SUCCESS = 0, + PVR_FAIL = 1, + PVR_OVERFLOW = 2 +}; + +/*!*************************************************************************** + @Function PVRTErrorOutputDebug + @Input format printf style format followed by arguments it requires + @Description Outputs a string to the standard error. +*****************************************************************************/ +void PVRTErrorOutputDebug(char const * const format, ...); + +#endif // _PVRTERROR_H_ + +/***************************************************************************** +End of file (PVRTError.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTGlobal.h b/KREngine/3rdparty/pvrtexlib/include/PVRTGlobal.h new file mode 100644 index 0000000..b7f64a5 --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTGlobal.h @@ -0,0 +1,296 @@ +/****************************************************************************** + + @File PVRTGlobal.h + + @Title PVRTGlobal + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description Global defines and typedefs for PVRTools + +******************************************************************************/ +#ifndef _PVRTGLOBAL_H_ +#define _PVRTGLOBAL_H_ + +/*!*************************************************************************** + Macros +*****************************************************************************/ +#define PVRT_MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define PVRT_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define PVRT_CLAMP(x, l, h) (PVRT_MIN((h), PVRT_MAX((x), (l)))) + +// avoid warning about unused parameter +#define PVRT_UNREFERENCED_PARAMETER(x) ((void) x) + +#if defined(_WIN32) && !defined(__QT__) && !defined(UNDER_CE) /* Windows desktop */ +#if !defined(_CRTDBG_MAP_ALLOC) + #define _CRTDBG_MAP_ALLOC +#endif + #include + #include + #include +#endif + +#if defined(UNDER_CE) + #include + +#ifndef _ASSERT + #ifdef _DEBUG + #define _ASSERT(X) { (X) ? 0 : DebugBreak(); } + #else + #define _ASSERT(X) + #endif +#endif + +#ifndef _ASSERTE + #ifdef _DEBUG + #define _ASSERTE _ASSERT + #else + #define _ASSERTE(X) + #endif +#endif + #define _RPT0(a,b) + #define _RPT1(a,b,c) + #define _RPT2(a,b,c,d) + #define _RPT3(a,b,c,d,e) + #define _RPT4(a,b,c,d,e,f) +#else + +#if defined(_WIN32) && !defined(__QT__) + +#else +#if defined(__linux__) || defined(__APPLE__) + #define _ASSERT(a)((void)0) + #define _ASSERTE(a)((void)0) + #ifdef _DEBUG + #ifndef _RPT0 + #define _RPT0(a,b) printf(b) + #endif + #ifndef _RPT1 + #define _RPT1(a,b,c) printf(b,c) + #endif + #else + #ifndef _RPT0 + #define _RPT0(a,b)((void)0) + #endif + #ifndef _RPT1 + #define _RPT1(a,b,c)((void)0) + #endif + #endif + #define _RPT2(a,b,c,d)((void)0) + #define _RPT3(a,b,c,d,e)((void)0) + #define _RPT4(a,b,c,d,e,f)((void)0) + #include + #include + #define BYTE unsigned char + #define WORD unsigned short + #define DWORD unsigned int + typedef struct tagRGBQUAD { + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; + BYTE rgbReserved; + } RGBQUAD; + #define BOOL int +#if !defined(TRUE) + #define TRUE 1 +#endif +#if !defined(FALSE) + #define FALSE 0 +#endif +#else + #define _CRT_WARN 0 + #define _RPT0(a,b) + #define _RPT1(a,b,c) + #define _RPT2(a,b,c,d) + #define _RPT3(a,b,c,d,e) + #define _RPT4(a,b,c,d,e,f) + #define _ASSERT(X) + #define _ASSERTE(X) +#endif +#endif +#endif + +#include + +#define FREE(X) { if(X) { free(X); (X) = 0; } } + +// This macro is used to check at compile time that types are of a certain size +// If the size does not equal the expected size, this typedefs an array of size 0 +// which causes a compile error +#define PVRTSIZEASSERT(T, size) typedef int (sizeof_##T)[sizeof(T) == (size)] +#define PVRTCOMPILEASSERT(T, expr) typedef int (assert_##T)[expr] + + +/**************************************************************************** +** Integer types +****************************************************************************/ + +typedef char PVRTchar8; +typedef signed char PVRTint8; +typedef signed short PVRTint16; +typedef signed int PVRTint32; +typedef unsigned char PVRTuint8; +typedef unsigned short PVRTuint16; +typedef unsigned int PVRTuint32; + +typedef float PVRTfloat32; + +#if (defined(__int64) || defined(_WIN32)) +typedef signed __int64 PVRTint64; +typedef unsigned __int64 PVRTuint64; +#elif defined(TInt64) +typedef TInt64 PVRTint64; +typedef TUInt64 PVRTuint64; +#else +typedef signed long long PVRTint64; +typedef unsigned long long PVRTuint64; +#endif + +#if __SIZEOF_WCHAR_T__ == 4 || __WCHAR_MAX__ > 0x10000 + #define PVRTSIZEOFWCHAR 4 +#else + #define PVRTSIZEOFWCHAR 2 +#endif + +PVRTSIZEASSERT(PVRTchar8, 1); +PVRTSIZEASSERT(PVRTint8, 1); +PVRTSIZEASSERT(PVRTuint8, 1); +PVRTSIZEASSERT(PVRTint16, 2); +PVRTSIZEASSERT(PVRTuint16, 2); +PVRTSIZEASSERT(PVRTint32, 4); +PVRTSIZEASSERT(PVRTuint32, 4); +PVRTSIZEASSERT(PVRTint64, 8); +PVRTSIZEASSERT(PVRTuint64, 8); +PVRTSIZEASSERT(PVRTfloat32, 4); + +/*!************************************************************************** +@Enum ETextureFilter +@Brief Enum values for defining texture filtering +****************************************************************************/ +enum ETextureFilter +{ + eFilter_Nearest, + eFilter_Linear, + eFilter_None, + + eFilter_Size, + eFilter_Default = eFilter_Linear, + eFilter_MipDefault = eFilter_None +}; + +/*!************************************************************************** +@Enum ETextureWrap +@Brief Enum values for defining texture wrapping +****************************************************************************/ +enum ETextureWrap +{ + eWrap_Clamp, + eWrap_Repeat, + + eWrap_Size, + eWrap_Default = eWrap_Repeat +}; + +/**************************************************************************** +** swap template function +****************************************************************************/ +/*!*************************************************************************** + @Function PVRTswap + @Input a Type a + @Input b Type b + @Description A swap template function that swaps a and b +*****************************************************************************/ + +template +inline void PVRTswap(T& a, T& b) +{ + T temp = a; + a = b; + b = temp; +} + +/*!*************************************************************************** + @Function PVRTClamp + @Input val Value to clamp + @Input min Minimum legal value + @Input max Maximum legal value + @Description A clamp template function that clamps val between min and max. +*****************************************************************************/ +template +inline T PVRTClamp(const T& val, const T& min, const T& max) +{ + if(val > max) + return max; + if(val < min) + return min; + return val; +} + +/*!*************************************************************************** + @Function PVRTByteSwap + @Input pBytes A number + @Input i32ByteNo Number of bytes in pBytes + @Description Swaps the endianness of pBytes in place +*****************************************************************************/ +inline void PVRTByteSwap(unsigned char* pBytes, int i32ByteNo) +{ + int i = 0, j = i32ByteNo - 1; + + while(i < j) + PVRTswap(pBytes[i++], pBytes[j--]); +} + +/*!*************************************************************************** + @Function PVRTByteSwap32 + @Input ui32Long A number + @Returns ui32Long with its endianness changed + @Description Converts the endianness of an unsigned int +*****************************************************************************/ +inline unsigned int PVRTByteSwap32(unsigned int ui32Long) +{ + return ((ui32Long&0x000000FF)<<24) + ((ui32Long&0x0000FF00)<<8) + ((ui32Long&0x00FF0000)>>8) + ((ui32Long&0xFF000000) >> 24); +} + +/*!*************************************************************************** + @Function PVRTByteSwap16 + @Input ui16Short A number + @Returns ui16Short with its endianness changed + @Description Converts the endianness of a unsigned short +*****************************************************************************/ +inline unsigned short PVRTByteSwap16(unsigned short ui16Short) +{ + return (ui16Short>>8) | (ui16Short<<8); +} + +/*!*************************************************************************** + @Function PVRTIsLittleEndian + @Returns True if the platform the code is ran on is little endian + @Description Returns true if the platform the code is ran on is little endian +*****************************************************************************/ +inline bool PVRTIsLittleEndian() +{ + static bool bLittleEndian; + static bool bIsInit = false; + + if(!bIsInit) + { + short int word = 0x0001; + char *byte = (char*) &word; + bLittleEndian = byte[0] ? true : false; + bIsInit = true; + } + + return bLittleEndian; +} + +#endif // _PVRTGLOBAL_H_ + +/***************************************************************************** + End of file (Tools.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTMap.h b/KREngine/3rdparty/pvrtexlib/include/PVRTMap.h new file mode 100644 index 0000000..fff8252 --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTMap.h @@ -0,0 +1,225 @@ +/****************************************************************************** + + @File PVRTMap.h + + @Title PVRTArray + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description A simple and easy to use implementation of a map. + +******************************************************************************/ +#ifndef __PVRTMAP_H__ +#define __PVRTMAP_H__ + +#include "PVRTArray.h" + +/*!**************************************************************************** +Class +******************************************************************************/ + +/*!*************************************************************************** +* @Class CPVRTMap +* @Brief Expanding map template class. +* @Description A simple and easy to use implementation of a map. +*****************************************************************************/ +template +class CPVRTMap +{ +public: + + /*!*********************************************************************** + @Function CPVRTMap + @Return A new CPVRTMap. + @Description Constructor for a CPVRTMap. + *************************************************************************/ + CPVRTMap() : m_Keys(), m_Data(), m_uiSize(0) + {} + + /*!*********************************************************************** + @Function ~CPVRTMap + @Description Destructor for a CPVRTMap. + *************************************************************************/ + ~CPVRTMap() + { + //Clear the map, that's enough - the CPVRTArray members will tidy everything else up. + Clear(); + } + + EPVRTError Reserve(const PVRTuint32 uiSize) + { + //Sets the capacity of each member array to the requested size. The array used will only expand. + //Returns the most serious error from either method. + return PVRT_MAX(m_Keys.SetCapacity(uiSize),m_Data.SetCapacity(uiSize)); + } + + /*!*********************************************************************** + @Function GetSize + @Return Number of meaningful members in the map. + @Description Returns the number of meaningful members in the map. + *************************************************************************/ + PVRTuint32 GetSize() const + { + //Return the size. + return m_uiSize; + } + + /*!*********************************************************************** + @Function GetIndexOf + @Input key + @Return The index value for a mapped item. + @Description Gets the position of a particular key/data within the map. + If the return value is exactly equal to the value of + GetSize() then the item has not been found. + *************************************************************************/ + PVRTuint32 GetIndexOf(const KeyType key) const + { + //Loop through all the valid keys. + for (PVRTuint32 i=0; i=m_uiSize) + return NULL; + + return &(m_Data[uiIndex]); + } + + /*!*********************************************************************** + @Function operator[] + @Input key + @Return Data that is mapped to 'key'. + @Description If a mapping already exists for 'key' then it will return + the associated data. If no mapping currently exists, a new + element is created in place. + *************************************************************************/ + DataType& operator[] (const KeyType key) + { + //Get the index of the key. + PVRTuint32 uiIndex = GetIndexOf(key); + + //Check the index is valid + if (uiIndex != m_uiSize) + { + //Return mapped data if the index is valid. + return m_Data[uiIndex]; + } + else + { + //Append the key to the Keys array. + m_Keys.Append(key); + + //Create a new DataType. + DataType sNewData; + + //Append the new pointer to the Data array. + m_Data.Append(sNewData); + + //Increment the size of meaningful data. + ++m_uiSize; + + //Return the contents of pNewData. + return m_Data[m_Keys.GetSize()-1]; + } + } + + /*!*********************************************************************** + @Function Remove + @Input key + @Return Returns PVR_FAIL if item doesn't exist. + Otherwise returns PVR_SUCCESS. + @Description Removes an element from the map if it exists. + *************************************************************************/ + EPVRTError Remove(const KeyType key) + { + //Finds the index of the key. + PVRTuint32 uiIndex=GetIndexOf(key); + + //If the key is invalid, fail. + if (uiIndex==m_uiSize) + { + //Return failure. + return PVR_FAIL; + } + + //Decrement the size of the map to ignore the last element in each array. + m_uiSize--; + + //Copy the last key over the deleted key. There are now two copies of one element, + //but the one at the end of the array is ignored. + m_Keys[uiIndex]=m_Keys[m_uiSize-1]; + + //Copy the last data over the deleted data in the same way as the keys. + m_Data[uiIndex]=m_Data[m_uiSize-1]; + + //Return success. + return PVR_SUCCESS; + } + + /*!*********************************************************************** + @Function Clear + @Description Clears the Map of all data values. + *************************************************************************/ + void Clear() + { + //Set the size to 0. + m_uiSize=0; + m_Keys.Clear(); + m_Data.Clear(); + } + + /*!*********************************************************************** + @Function Exists + @Input key + @Return Whether data exists for the specified key or not. + @Description Checks whether or not data exists for the specified key. + *************************************************************************/ + bool Exists(const KeyType key) const + { + //Checks for a valid index for key, if not, returns false. + return (GetIndexOf(key) != m_uiSize); + } + +private: + + //Array of all the keys. Indices match m_Data. + CPVRTArray m_Keys; + + //Array of pointers to all the allocated data. + CPVRTArray m_Data; + + //The number of meaningful members in the map. + PVRTuint32 m_uiSize; +}; + +#endif // __PVRTMAP_H__ + +/***************************************************************************** +End of file (PVRTMap.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTString.h b/KREngine/3rdparty/pvrtexlib/include/PVRTString.h new file mode 100644 index 0000000..759aa8b --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTString.h @@ -0,0 +1,982 @@ +/****************************************************************************** + + @File PVRTString.h + + @Title PVRTString + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description A string class that can be used as drop-in replacement for + std::string on platforms/compilers that don't provide a full C++ + standard library. + +******************************************************************************/ +#ifndef _PVRTSTRING_H_ +#define _PVRTSTRING_H_ + +#include +#define _USING_PVRTSTRING_ + +/*!*************************************************************************** +@Class CPVRTString +@Brief A string class +*****************************************************************************/ +class CPVRTString +{ + +private: + + // Checking printf and scanf format strings +#if defined(_CC_GNU_) || defined(__GNUG__) || defined(__GNUC__) +#define FX_PRINTF(fmt,arg) __attribute__((format(printf,fmt,arg))) +#define FX_SCANF(fmt,arg) __attribute__((format(scanf,fmt,arg))) +#else +#define FX_PRINTF(fmt,arg) +#define FX_SCANF(fmt,arg) +#endif + +public: + typedef size_t size_type; + typedef char value_type; + typedef char& reference; + typedef const char& const_reference; + + static const size_type npos; + + + + + /*!*********************************************************************** + @Function CPVRTString + @Input _Ptr A string + @Input _Count Length of _Ptr + @Description Constructor + ************************************************************************/ + CPVRTString(const char* _Ptr, size_t _Count = npos); + + /*!*********************************************************************** + @Function CPVRTString + @Input _Right A string + @Input _Roff Offset into _Right + @Input _Count Number of chars from _Right to assign to the new string + @Description Constructor + ************************************************************************/ + CPVRTString(const CPVRTString& _Right, size_t _Roff = 0, size_t _Count = npos); + + /*!*********************************************************************** + @Function CPVRTString + @Input _Count Length of new string + @Input _Ch A char to fill it with + @Description Constructor + *************************************************************************/ + CPVRTString(size_t _Count, const char _Ch); + + /*!*********************************************************************** + @Function CPVRTString + @Input _Ch A char + @Description Constructor + *************************************************************************/ + CPVRTString(const char _Ch); + + /*!*********************************************************************** + @Function CPVRTString + @Description Constructor + ************************************************************************/ + CPVRTString(); + + /*!*********************************************************************** + @Function ~CPVRTString + @Description Destructor + ************************************************************************/ + virtual ~CPVRTString(); + + /*!*********************************************************************** + @Function append + @Input _Ptr A string + @Returns Updated string + @Description Appends a string + *************************************************************************/ + CPVRTString& append(const char* _Ptr); + + /*!*********************************************************************** + @Function append + @Input _Ptr A string + @Input _Count String length + @Returns Updated string + @Description Appends a string of length _Count + *************************************************************************/ + CPVRTString& append(const char* _Ptr, size_t _Count); + + /*!*********************************************************************** + @Function append + @Input _Str A string + @Returns Updated string + @Description Appends a string + *************************************************************************/ + CPVRTString& append(const CPVRTString& _Str); + + /*!*********************************************************************** + @Function append + @Input _Str A string + @Input _Off A position in string + @Input _Count Number of letters to append + @Returns Updated string + @Description Appends _Count letters of _Str from _Off in _Str + *************************************************************************/ + CPVRTString& append(const CPVRTString& _Str, size_t _Off, size_t _Count); + + /*!*********************************************************************** + @Function append + @Input _Ch A char + @Input _Count Number of times to append _Ch + @Returns Updated string + @Description Appends _Ch _Count times + *************************************************************************/ + CPVRTString& append(size_t _Count, const char _Ch); + + //template CPVRTString& append(InputIterator _First, InputIterator _Last); + + /*!*********************************************************************** + @Function assign + @Input _Ptr A string + @Returns Updated string + @Description Assigns the string to the string _Ptr + *************************************************************************/ + CPVRTString& assign(const char* _Ptr); + + /*!*********************************************************************** + @Function assign + @Input _Ptr A string + @Input _Count Length of _Ptr + @Returns Updated string + @Description Assigns the string to the string _Ptr + *************************************************************************/ + CPVRTString& assign(const char* _Ptr, size_t _Count); + + /*!*********************************************************************** + @Function assign + @Input _Str A string + @Returns Updated string + @Description Assigns the string to the string _Str + *************************************************************************/ + CPVRTString& assign(const CPVRTString& _Str); + + /*!*********************************************************************** + @Function assign + @Input _Str A string + @Input _Off First char to start assignment from + @Input _Count Length of _Str + @Returns Updated string + @Description Assigns the string to _Count characters in string _Str starting at _Off + *************************************************************************/ + CPVRTString& assign(const CPVRTString& _Str, size_t _Off, size_t _Count=npos); + + /*!*********************************************************************** + @Function assign + @Input _Ch A string + @Input _Count Number of times to repeat _Ch + @Returns Updated string + @Description Assigns the string to _Count copies of _Ch + *************************************************************************/ + CPVRTString& assign(size_t _Count, char _Ch); + + //template CPVRTString& assign(InputIterator _First, InputIterator _Last); + + //const_reference at(size_t _Off) const; + //reference at(size_t _Off); + + // const_iterator begin() const; + // iterator begin(); + + /*!*********************************************************************** + @Function c_str + @Returns const char* pointer of the string + @Description Returns a const char* pointer of the string + *************************************************************************/ + const char* c_str() const; + + /*!*********************************************************************** + @Function capacity + @Returns The size of the character array reserved + @Description Returns the size of the character array reserved + *************************************************************************/ + size_t capacity() const; + + /*!*********************************************************************** + @Function clear + @Description Clears the string + *************************************************************************/ + void clear(); + + /*!*********************************************************************** + @Function compare + @Input _Str A string to compare with + @Returns 0 if the strings match + @Description Compares the string with _Str + *************************************************************************/ + int compare(const CPVRTString& _Str) const; + + /*!*********************************************************************** + @Function compare + @Input _Pos1 Position to start comparing from + @Input _Num1 Number of chars to compare + @Input _Str A string to compare with + @Returns 0 if the strings match + @Description Compares the string with _Str + *************************************************************************/ + int compare(size_t _Pos1, size_t _Num1, const CPVRTString& _Str) const; + + /*!*********************************************************************** + @Function compare + @Input _Pos1 Position to start comparing from + @Input _Num1 Number of chars to compare + @Input _Str A string to compare with + @Input _Off Position in _Str to compare from + @Input _Count Number of chars in _Str to compare with + @Returns 0 if the strings match + @Description Compares the string with _Str + *************************************************************************/ + int compare(size_t _Pos1, size_t _Num1, const CPVRTString& _Str, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function compare + @Input _Ptr A string to compare with + @Returns 0 if the strings match + @Description Compares the string with _Ptr + *************************************************************************/ + int compare(const char* _Ptr) const; + + /*!*********************************************************************** + @Function compare + @Input _Pos1 Position to start comparing from + @Input _Num1 Number of chars to compare + @Input _Ptr A string to compare with + @Returns 0 if the strings match + @Description Compares the string with _Ptr + *************************************************************************/ + int compare(size_t _Pos1, size_t _Num1, const char* _Ptr) const; + + /*!*********************************************************************** + @Function compare + @Input _Pos1 Position to start comparing from + @Input _Num1 Number of chars to compare + @Input _Ptr A string to compare with + @Input _Count Number of chars to compare + @Returns 0 if the strings match + @Description Compares the string with _Str + *************************************************************************/ + int compare(size_t _Pos1, size_t _Num1, const char* _Ptr, size_t _Count) const; + + /*!*********************************************************************** + @Function < + @Input _Str A string to compare with + @Returns True on success + @Description Less than operator + *************************************************************************/ + bool operator<(const CPVRTString & _Str) const; + + /*!*********************************************************************** + @Function == + @Input _Str A string to compare with + @Returns True if they match + @Description == Operator + *************************************************************************/ + bool operator==(const CPVRTString& _Str) const; + + /*!*********************************************************************** + @Function == + @Input _Ptr A string to compare with + @Returns True if they match + @Description == Operator + *************************************************************************/ + bool operator==(const char* const _Ptr) const; + + /*!*********************************************************************** + @Function != + @Input _Str A string to compare with + @Returns True if they don't match + @Description != Operator + *************************************************************************/ + bool operator!=(const CPVRTString& _Str) const; + + /*!*********************************************************************** + @Function != + @Input _Ptr A string to compare with + @Returns True if they don't match + @Description != Operator + *************************************************************************/ + bool operator!=(const char* const _Ptr) const; + + /*!*********************************************************************** + @Function copy + @Modified _Ptr A string to copy to + @Input _Count Size of _Ptr + @Input _Off Position to start copying from + @Returns Number of bytes copied + @Description Copies the string to _Ptr + *************************************************************************/ + size_t copy(char* _Ptr, size_t _Count, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function data + @Returns A const char* version of the string + @Description Returns a const char* version of the string + *************************************************************************/ + const char* data( ) const; + + /*!*********************************************************************** + @Function empty + @Returns True if the string is empty + @Description Returns true if the string is empty + *************************************************************************/ + bool empty() const; + + // const_iterator end() const; + // iterator end(); + + //iterator erase(iterator _First, iterator _Last); + //iterator erase(iterator _It); + + /*!*********************************************************************** + @Function erase + @Input _Pos The position to start erasing from + @Input _Count Number of chars to erase + @Returns An updated string + @Description Erases a portion of the string + *************************************************************************/ + CPVRTString& erase(size_t _Pos = 0, size_t _Count = npos); + + /*!*********************************************************************** + @Function substitute + @Input _src Character to search + @Input _subDes Character to substitute for + @Input _all Substitute all + @Returns An updated string + @Description Erases a portion of the string + *************************************************************************/ + CPVRTString& substitute(char _src,char _subDes, bool _all = true); + + /*!*********************************************************************** + @Function substitute + @Input _src Character to search + @Input _subDes Character to substitute for + @Input _all Substitute all + @Returns An updated string + @Description Erases a portion of the string + *************************************************************************/ + CPVRTString& substitute(const char* _src, const char* _subDes, bool _all = true); + + //size_t find(char _Ch, size_t _Off = 0) const; + //size_t find(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find + @Input _Ptr String to search. + @Input _Off Offset to search from. + @Input _Count Number of characters in this string. + @Returns Position of the first matched string. + @Description Finds a substring within this string. + *************************************************************************/ + size_t find(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find + @Input _Str String to search. + @Input _Off Offset to search from. + @Returns Position of the first matched string. + @Description Finds a substring within this string. + *************************************************************************/ + size_t find(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_not_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Position of the first char that is not _Ch + @Description Returns the position of the first char that is not _Ch + *************************************************************************/ + size_t find_first_not_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_not_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Position of the first char that is not in _Ptr + @Description Returns the position of the first char that is not in _Ptr + *************************************************************************/ + size_t find_first_not_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_not_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Number of chars in _Ptr + @Returns Position of the first char that is not in _Ptr + @Description Returns the position of the first char that is not in _Ptr + *************************************************************************/ + size_t find_first_not_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_first_not_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Position of the first char that is not in _Str + @Description Returns the position of the first char that is not in _Str + *************************************************************************/ + size_t find_first_not_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Position of the first char that is _Ch + @Description Returns the position of the first char that is _Ch + *************************************************************************/ + size_t find_first_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Position of the first char that matches a char in _Ptr + @Description Returns the position of the first char that matches a char in _Ptr + *************************************************************************/ + size_t find_first_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_first_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Size of _Ptr + @Returns Position of the first char that matches a char in _Ptr + @Description Returns the position of the first char that matches a char in _Ptr + *************************************************************************/ + size_t find_first_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_first_ofn + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Size of _Ptr + @Returns Position of the first char that matches a char in _Ptr + @Description Returns the position of the first char that matches all chars in _Ptr + *************************************************************************/ + size_t find_first_ofn(const char* _Ptr, size_t _Off, size_t _Count) const; + + + /*!*********************************************************************** + @Function find_first_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Position of the first char that matches a char in _Str + @Description Returns the position of the first char that matches a char in _Str + *************************************************************************/ + size_t find_first_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_not_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Position of the last char that is not _Ch + @Description Returns the position of the last char that is not _Ch + *************************************************************************/ + size_t find_last_not_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_not_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Position of the last char that is not in _Ptr + @Description Returns the position of the last char that is not in _Ptr + *************************************************************************/ + size_t find_last_not_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_not_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Length of _Ptr + @Returns Position of the last char that is not in _Ptr + @Description Returns the position of the last char that is not in _Ptr + *************************************************************************/ + size_t find_last_not_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_last_not_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Position of the last char that is not in _Str + @Description Returns the position of the last char that is not in _Str + *************************************************************************/ + size_t find_last_not_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Position of the last char that is _Ch + @Description Returns the position of the last char that is _Ch + *************************************************************************/ + size_t find_last_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Position of the last char that is in _Ptr + @Description Returns the position of the last char that is in _Ptr + *************************************************************************/ + size_t find_last_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_last_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Length of _Ptr + @Returns Position of the last char that is in _Ptr + @Description Returns the position of the last char that is in _Ptr + *************************************************************************/ + size_t find_last_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_last_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Position of the last char that is in _Str + @Description Returns the position of the last char that is in _Str + *************************************************************************/ + size_t find_last_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_number_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Number of occurances of _Ch in the parent string. + @Description Returns the number of occurances of _Ch in the parent string. + *************************************************************************/ + size_t find_number_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_number_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Number of occurances of _Ptr in the parent string. + @Description Returns the number of occurances of _Ptr in the parent string. + *************************************************************************/ + size_t find_number_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_number_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Size of _Ptr + @Returns Number of occurances of _Ptr in the parent string. + @Description Returns the number of occurances of _Ptr in the parent string. + *************************************************************************/ + size_t find_number_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_number_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Number of occurances of _Str in the parent string. + @Description Returns the number of occurances of _Str in the parent string. + *************************************************************************/ + size_t find_number_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_next_occurance_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Next occurance of _Ch in the parent string. + @Description Returns the next occurance of _Ch in the parent string + after or at _Off. If not found, returns the length of the string. + *************************************************************************/ + int find_next_occurance_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_next_occurance_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Next occurance of _Ptr in the parent string. + @Description Returns the next occurance of _Ptr in the parent string + after or at _Off. If not found, returns the length of the string. + *************************************************************************/ + int find_next_occurance_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_next_occurance_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Size of _Ptr + @Returns Next occurance of _Ptr in the parent string. + @Description Returns the next occurance of _Ptr in the parent string + after or at _Off. If not found, returns the length of the string. + *************************************************************************/ + int find_next_occurance_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_next_occurance_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Next occurance of _Str in the parent string. + @Description Returns the next occurance of _Str in the parent string + after or at _Off. If not found, returns the length of the string. + *************************************************************************/ + int find_next_occurance_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_previous_occurance_of + @Input _Ch A char + @Input _Off Start position of the find + @Returns Previous occurance of _Ch in the parent string. + @Description Returns the previous occurance of _Ch in the parent string + before _Off. If not found, returns -1. + *************************************************************************/ + int find_previous_occurance_of(char _Ch, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_previous_occurance_of + @Input _Ptr A string + @Input _Off Start position of the find + @Returns Previous occurance of _Ptr in the parent string. + @Description Returns the previous occurance of _Ptr in the parent string + before _Off. If not found, returns -1. + *************************************************************************/ + int find_previous_occurance_of(const char* _Ptr, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function find_previous_occurance_of + @Input _Ptr A string + @Input _Off Start position of the find + @Input _Count Size of _Ptr + @Returns Previous occurance of _Ptr in the parent string. + @Description Returns the previous occurance of _Ptr in the parent string + before _Off. If not found, returns -1. + *************************************************************************/ + int find_previous_occurance_of(const char* _Ptr, size_t _Off, size_t _Count) const; + + /*!*********************************************************************** + @Function find_previous_occurance_of + @Input _Str A string + @Input _Off Start position of the find + @Returns Previous occurance of _Str in the parent string. + @Description Returns the previous occurance of _Str in the parent string + before _Off. If not found, returns -1. + *************************************************************************/ + int find_previous_occurance_of(const CPVRTString& _Str, size_t _Off = 0) const; + + /*!*********************************************************************** + @Function left + @Input iSize number of characters to return (excluding null character) + @Returns The leftmost 'iSize' characters of the string. + @Description Returns the leftmost characters of the string (excluding + the null character) in a new CPVRTString. If iSize is + larger than the string, a copy of the original string is returned. + *************************************************************************/ + CPVRTString left(size_t iSize) const; + + /*!*********************************************************************** + @Function right + @Input iSize number of characters to return (excluding null character) + @Returns The rightmost 'iSize' characters of the string. + @Description Returns the rightmost characters of the string (excluding + the null character) in a new CPVRTString. If iSize is + larger than the string, a copy of the original string is returned. + *************************************************************************/ + CPVRTString right(size_t iSize) const; + + //allocator_type get_allocator( ) const; + + //CPVRTString& insert(size_t _P0, const char* _Ptr); + //CPVRTString& insert(size_t _P0, const char* _Ptr, size_t _Count); + //CPVRTString& insert(size_t _P0, const CPVRTString& _Str); + //CPVRTString& insert(size_t _P0, const CPVRTString& _Str, size_t _Off, size_t _Count); + //CPVRTString& insert(size_t _P0, size_t _Count, char _Ch); + //iterator insert(iterator _It, char _Ch = char()); + //template void insert(iterator _It, InputIterator _First, InputIterator _Last); + //void insert(iterator _It, size_t _Count, char _Ch); + + /*!*********************************************************************** + @Function length + @Returns Length of the string + @Description Returns the length of the string + *************************************************************************/ + size_t length() const; + + /*!*********************************************************************** + @Function max_size + @Returns The maximum number of chars that the string can contain + @Description Returns the maximum number of chars that the string can contain + *************************************************************************/ + size_t max_size() const; + + /*!*********************************************************************** + @Function push_back + @Input _Ch A char to append + @Description Appends _Ch to the string + *************************************************************************/ + void push_back(char _Ch); + + // const_reverse_iterator rbegin() const; + // reverse_iterator rbegin(); + + // const_reverse_iterator rend() const; + // reverse_iterator rend(); + + //CPVRTString& replace(size_t _Pos1, size_t _Num1, const char* _Ptr); + //CPVRTString& replace(size_t _Pos1, size_t _Num1, const CPVRTString& _Str); + //CPVRTString& replace(size_t _Pos1, size_t _Num1, const char* _Ptr, size_t _Num2); + //CPVRTString& replace(size_t _Pos1, size_t _Num1, const CPVRTString& _Str, size_t _Pos2, size_t _Num2); + //CPVRTString& replace(size_t _Pos1, size_t _Num1, size_t _Count, char _Ch); + + //CPVRTString& replace(iterator _First0, iterator _Last0, const char* _Ptr); + //CPVRTString& replace(iterator _First0, iterator _Last0, const CPVRTString& _Str); + //CPVRTString& replace(iterator _First0, iterator _Last0, const char* _Ptr, size_t _Num2); + //CPVRTString& replace(iterator _First0, iterator _Last0, size_t _Num2, char _Ch); + //template CPVRTString& replace(iterator _First0, iterator _Last0, InputIterator _First, InputIterator _Last); + + /*!*********************************************************************** + @Function reserve + @Input _Count Size of string to reserve + @Description Reserves space for _Count number of chars + *************************************************************************/ + void reserve(size_t _Count = 0); + + /*!*********************************************************************** + @Function resize + @Input _Count Size of string to resize to + @Input _Ch Character to use to fill any additional space + @Description Resizes the string to _Count in length + *************************************************************************/ + void resize(size_t _Count, char _Ch = char()); + + //size_t rfind(char _Ch, size_t _Off = npos) const; + //size_t rfind(const char* _Ptr, size_t _Off = npos) const; + //size_t rfind(const char* _Ptr, size_t _Off = npos, size_t _Count) const; + //size_t rfind(const CPVRTString& _Str, size_t _Off = npos) const; + + /*!*********************************************************************** + @Function size + @Returns Size of the string + @Description Returns the size of the string + *************************************************************************/ + size_t size() const; + + /*!*********************************************************************** + @Function substr + @Input _Off Start of the substring + @Input _Count Length of the substring + @Returns A substring of the string + @Description Returns the size of the string + *************************************************************************/ + CPVRTString substr(size_t _Off = 0, size_t _Count = npos) const; + + /*!*********************************************************************** + @Function swap + @Input _Str A string to swap with + @Description Swaps the contents of the string with _Str + *************************************************************************/ + void swap(CPVRTString& _Str); + + /*!*********************************************************************** + @Function toLower + @Returns An updated string + @Description Converts the string to lower case + *************************************************************************/ + CPVRTString& toLower(); + + /*!*********************************************************************** + @Function toUpper + @Returns An updated string + @Description Converts the string to upper case + *************************************************************************/ + CPVRTString& toUpper(); + + /*!*********************************************************************** + @Function format + @Input pFormat A string containing the formating + @Returns A formatted string + @Description return the formatted string + ************************************************************************/ + CPVRTString format(const char *pFormat, ...); + + /*!*********************************************************************** + @Function += + @Input _Ch A char + @Returns An updated string + @Description += Operator + *************************************************************************/ + CPVRTString& operator+=(char _Ch); + + /*!*********************************************************************** + @Function += + @Input _Ptr A string + @Returns An updated string + @Description += Operator + *************************************************************************/ + CPVRTString& operator+=(const char* _Ptr); + + /*!*********************************************************************** + @Function += + @Input _Right A string + @Returns An updated string + @Description += Operator + *************************************************************************/ + CPVRTString& operator+=(const CPVRTString& _Right); + + /*!*********************************************************************** + @Function = + @Input _Ch A char + @Returns An updated string + @Description = Operator + *************************************************************************/ + CPVRTString& operator=(char _Ch); + + /*!*********************************************************************** + @Function = + @Input _Ptr A string + @Returns An updated string + @Description = Operator + *************************************************************************/ + CPVRTString& operator=(const char* _Ptr); + + /*!*********************************************************************** + @Function = + @Input _Right A string + @Returns An updated string + @Description = Operator + *************************************************************************/ + CPVRTString& operator=(const CPVRTString& _Right); + + /*!*********************************************************************** + @Function [] + @Input _Off An index into the string + @Returns A character + @Description [] Operator + *************************************************************************/ + const_reference operator[](size_t _Off) const; + + /*!*********************************************************************** + @Function [] + @Input _Off An index into the string + @Returns A character + @Description [] Operator + *************************************************************************/ + reference operator[](size_t _Off); + + /*!*********************************************************************** + @Function + + @Input _Left A string + @Input _Right A string + @Returns An updated string + @Description + Operator + *************************************************************************/ + friend CPVRTString operator+ (const CPVRTString& _Left, const CPVRTString& _Right); + + /*!*********************************************************************** + @Function + + @Input _Left A string + @Input _Right A string + @Returns An updated string + @Description + Operator + *************************************************************************/ + friend CPVRTString operator+ (const CPVRTString& _Left, const char* _Right); + + /*!*********************************************************************** + @Function + + @Input _Left A string + @Input _Right A string + @Returns An updated string + @Description + Operator + *************************************************************************/ + friend CPVRTString operator+ (const CPVRTString& _Left, const char _Right); + + /*!*********************************************************************** + @Function + + @Input _Left A string + @Input _Right A string + @Returns An updated string + @Description + Operator + *************************************************************************/ + friend CPVRTString operator+ (const char* _Left, const CPVRTString& _Right); + + + /*!*********************************************************************** + @Function + + @Input _Left A string + @Input _Right A string + @Returns An updated string + @Description + Operator + *************************************************************************/ + friend CPVRTString operator+ (const char _Left, const CPVRTString& _Right); + +protected: + char* m_pString; + size_t m_Size; + size_t m_Capacity; +}; + +/************************************************************************* +* MISCELLANEOUS UTILITY FUNCTIONS +*************************************************************************/ +/*!*********************************************************************** +@Function PVRTStringGetFileExtension +@Input strFilePath A string +@Returns Extension +@Description Extracts the file extension from a file path. +Returns an empty CPVRTString if no extension is found. +************************************************************************/ +CPVRTString PVRTStringGetFileExtension(const CPVRTString& strFilePath); + +/*!*********************************************************************** +@Function PVRTStringGetContainingDirectoryPath +@Input strFilePath A string +@Returns Directory +@Description Extracts the directory portion from a file path. +************************************************************************/ +CPVRTString PVRTStringGetContainingDirectoryPath(const CPVRTString& strFilePath); + +/*!*********************************************************************** +@Function PVRTStringGetFileName +@Input strFilePath A string +@Returns FileName +@Description Extracts the name and extension portion from a file path. +************************************************************************/ +CPVRTString PVRTStringGetFileName(const CPVRTString& strFilePath); + +/*!*********************************************************************** +@Function PVRTStringStripWhiteSpaceFromStartOf +@Input strLine A string +@Returns Result of the white space stripping +@Description strips white space characters from the beginning of a CPVRTString. +************************************************************************/ +CPVRTString PVRTStringStripWhiteSpaceFromStartOf(const CPVRTString& strLine); + +/*!*********************************************************************** +@Function PVRTStringStripWhiteSpaceFromEndOf +@Input strLine A string +@Returns Result of the white space stripping +@Description strips white space characters from the end of a CPVRTString. +************************************************************************/ +CPVRTString PVRTStringStripWhiteSpaceFromEndOf(const CPVRTString& strLine); + +/*!*********************************************************************** +@Function PVRTStringFromFormattedStr +@Input pFormat A string containing the formating +@Returns A formatted string +@Description Creates a formatted string +************************************************************************/ +CPVRTString PVRTStringFromFormattedStr(const char *pFormat, ...); + +#endif // _PVRTSTRING_H_ + + +/***************************************************************************** +End of file (PVRTString.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTTexture.h b/KREngine/3rdparty/pvrtexlib/include/PVRTTexture.h new file mode 100644 index 0000000..114549f --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTTexture.h @@ -0,0 +1,700 @@ +/****************************************************************************** + + @File PVRTTexture.h + + @Title PVRTTexture + + @Version + + @Copyright Copyright (c) Imagination Technologies Limited. + + @Platform ANSI compatible + + @Description Texture loading. + +******************************************************************************/ +#ifndef _PVRTTEXTURE_H_ +#define _PVRTTEXTURE_H_ + +#include "PVRTGlobal.h" + +/***************************************************************************** +* Texture related constants and enumerations. +*****************************************************************************/ +// V3 Header Identifiers. +const PVRTuint32 PVRTEX3_IDENT = 0x03525650; // 'P''V''R'3 +const PVRTuint32 PVRTEX3_IDENT_REV = 0x50565203; +// If endianness is backwards then PVR3 will read as 3RVP, hence why it is written as an int. + +//Current version texture identifiers +const PVRTuint32 PVRTEX_CURR_IDENT = PVRTEX3_IDENT; +const PVRTuint32 PVRTEX_CURR_IDENT_REV = PVRTEX3_IDENT_REV; + +// PVR Header file flags. Condition if true. If false, opposite is true unless specified. +const PVRTuint32 PVRTEX3_FILE_COMPRESSED = (1<<0); // Texture has been file compressed using PVRTexLib (currently unused) +const PVRTuint32 PVRTEX3_PREMULTIPLIED = (1<<1); // Texture has been premultiplied by alpha value. + +// Mip Map level specifier constants. Other levels are specified by 1,2...n +const PVRTint32 PVRTEX_TOPMIPLEVEL = 0; +const PVRTint32 PVRTEX_ALLMIPLEVELS = -1; //This is a special number used simply to return a total of all MIP levels when dealing with data sizes. + +//values for each meta data type that we know about. Texture arrays hinge on each surface being identical in all but content, including meta data. +//If the meta data varies even slightly then a new texture should be used. It is possible to write your own extension to get around this however. +enum EPVRTMetaData +{ + ePVRTMetaDataTextureAtlasCoords=0, + ePVRTMetaDataBumpData, + ePVRTMetaDataCubeMapOrder, + ePVRTMetaDataTextureOrientation, + ePVRTMetaDataBorderData, + ePVRTMetaDataPadding, + ePVRTMetaDataNumMetaDataTypes +}; + +enum EPVRTAxis +{ + ePVRTAxisX = 0, + ePVRTAxisY = 1, + ePVRTAxisZ = 2 +}; + +enum EPVRTOrientation +{ + ePVRTOrientLeft = 1< +class CPVRTMap; + + +/*!*********************************************************************** + @Function PVRTGetBitsPerPixel + @Input u64PixelFormat A PVR Pixel Format ID. + @Return const PVRTuint32 Number of bits per pixel. + @Description Returns the number of bits per pixel in a PVR Pixel Format + identifier. +*************************************************************************/ +PVRTuint32 PVRTGetBitsPerPixel(PVRTuint64 u64PixelFormat); + +/*!*********************************************************************** + @Function PVRTGetFormatMinDims + @Input u64PixelFormat A PVR Pixel Format ID. + @Modified minX Returns the minimum width. + @Modified minY Returns the minimum height. + @Modified minZ Returns the minimum depth. + @Description Gets the minimum dimensions (x,y,z) for a given pixel format. +*************************************************************************/ +void PVRTGetFormatMinDims(PVRTuint64 u64PixelFormat, PVRTuint32 &minX, PVRTuint32 &minY, PVRTuint32 &minZ); + +/*!*********************************************************************** + @Function PVRTConvertOldTextureHeaderToV3 + @Input LegacyHeader Legacy header for conversion. + @Modified NewHeader New header to output into. + @Modified pMetaData MetaData Map to output into. + @Description Converts a legacy texture header (V1 or V2) to a current + generation header (V3) +*************************************************************************/ +void PVRTConvertOldTextureHeaderToV3(const PVR_Texture_Header* LegacyHeader, PVRTextureHeaderV3& NewHeader, CPVRTMap >* pMetaData); + +/*!*********************************************************************** + @Function PVRTMapLegacyTextureEnumToNewFormat + @Input OldFormat Legacy Enumeration Value + @Modified newType New PixelType identifier. + @Modified newCSpace New ColourSpace + @Modified newChanType New Channel Type + @Modified isPreMult Whether format is pre-multiplied + @Description Maps a legacy enumeration value to the new PVR3 style format. +*************************************************************************/ +void PVRTMapLegacyTextureEnumToNewFormat(PVRTPixelType OldFormat, PVRTuint64& newType, EPVRTColourSpace& newCSpace, EPVRTVariableType& newChanType, bool& isPreMult); + +/*!*************************************************************************** +@Function PVRTTextureLoadTiled +@Modified pDst Texture to place the tiled data +@Input nWidthDst Width of destination texture +@Input nHeightDst Height of destination texture +@Input pSrc Texture to tile +@Input nWidthSrc Width of source texture +@Input nHeightSrc Height of source texture +@Input nElementSize Bytes per pixel +@Input bTwiddled True if the data is twiddled +@Description Needed by PVRTTextureTile() in the various PVRTTextureAPIs +*****************************************************************************/ +void PVRTTextureLoadTiled( + PVRTuint8 * const pDst, + const unsigned int nWidthDst, + const unsigned int nHeightDst, + const PVRTuint8 * const pSrc, + const unsigned int nWidthSrc, + const unsigned int nHeightSrc, + const unsigned int nElementSize, + const bool bTwiddled); + + +/*!*************************************************************************** +@Function PVRTTextureTwiddle +@Output a Twiddled value +@Input u Coordinate axis 0 +@Input v Coordinate axis 1 +@Description Combine a 2D coordinate into a twiddled value +*****************************************************************************/ +void PVRTTextureTwiddle(unsigned int &a, const unsigned int u, const unsigned int v); + +/*!*************************************************************************** +@Function PVRTTextureDeTwiddle +@Output u Coordinate axis 0 +@Output v Coordinate axis 1 +@Input a Twiddled value +@Description Extract 2D coordinates from a twiddled value. +*****************************************************************************/ +void PVRTTextureDeTwiddle(unsigned int &u, unsigned int &v, const unsigned int a); + +/*!*********************************************************************** +@Function PVRTGetTextureDataSize +@Input sTextureHeader Specifies the texture header. +@Input iMipLevel Specifies a mip level to check, 'PVRTEX_ALLMIPLEVELS' + can be passed to get the size of all MIP levels. +@Input bAllSurfaces Size of all surfaces is calculated if true, + only a single surface if false. +@Input bAllFaces Size of all faces is calculated if true, + only a single face if false. +@Return PVRTuint32 Size in BYTES of the specified texture area. +@Description Gets the size in BYTES of the texture, given various input + parameters. User can retrieve the size of either all + surfaces or a single surface, all faces or a single face and + all MIP-Maps or a single specified MIP level. +*************************************************************************/ +PVRTuint32 PVRTGetTextureDataSize(PVRTextureHeaderV3 sTextureHeader, PVRTint32 iMipLevel=PVRTEX_ALLMIPLEVELS, bool bAllSurfaces = true, bool bAllFaces = true); + +#endif /* _PVRTTEXTURE_H_ */ + +/***************************************************************************** +End of file (PVRTTexture.h) +*****************************************************************************/ + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTexture.h b/KREngine/3rdparty/pvrtexlib/include/PVRTexture.h new file mode 100644 index 0000000..a03043b --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTexture.h @@ -0,0 +1,208 @@ +#ifndef _PVRTEXTURE_H +#define _PVRTEXTURE_H + +#include "PVRTextureDefines.h" +#include "PVRTextureHeader.h" +#include "PVRTString.h" + +namespace pvrtexture +{ + class PVR_DLL CPVRTexture : public CPVRTextureHeader + { + public: + /******************************************************************************* + * Construction methods for a texture. + *******************************************************************************/ + /*!*********************************************************************** + @Function CPVRTexture + @Return CPVRTexture A new texture. + @Description Creates a new empty texture + *************************************************************************/ + CPVRTexture(); + /*!*********************************************************************** + @Function CPVRTexture + @Input sHeader + @Input pData + @Return CPVRTexture A new texture. + @Description Creates a new texture based on a texture header, + pre-allocating the correct amount of memory. If data is + supplied, it will be copied into memory. + *************************************************************************/ + CPVRTexture(const CPVRTextureHeader& sHeader, const void* pData=NULL); + + /*!*********************************************************************** + @Function CPVRTexture + @Input szFilePath + @Return CPVRTexture A new texture. + @Description Creates a new texture from a filepath. + *************************************************************************/ + CPVRTexture(const char* szFilePath); + + /*!*********************************************************************** + @Function CPVRTexture + @Input pTexture + @Return CPVRTexture A new texture. + @Description Creates a new texture from a pointer that includes a header + structure, meta data and texture data as laid out in a file. + This functionality is primarily for user defined file loading. + Header may be any version of pvr. + *************************************************************************/ + CPVRTexture( const void* pTexture ); + + /*!*********************************************************************** + @Function CPVRTexture + @Input texture + @Return CPVRTexture A new texture + @Description Creates a new texture as a copy of another. + *************************************************************************/ + CPVRTexture(const CPVRTexture& texture); + + /*!*********************************************************************** + @Function ~CPVRTexture + @Description Deconstructor for CPVRTextures. + *************************************************************************/ + ~CPVRTexture(); + + /*!*********************************************************************** + @Function operator= + @Input rhs + @Return CPVRTexture& This texture. + @Description Will copy the contents and information of another texture into this one. + *************************************************************************/ + CPVRTexture& operator=(const CPVRTexture& rhs); + + /******************************************************************************* + * Texture accessor functions - others are inherited from CPVRTextureHeader. + *******************************************************************************/ + /*!*********************************************************************** + @Function getDataPtr + @Input uiMIPLevel + @Input uiArrayMember + @Input uiFaceNumber + @Return void* Pointer to a location in the texture. + @Description Returns a pointer into the texture's data. + It is possible to specify an offset to specific array members, + faces and MIP Map levels. + *************************************************************************/ + void* getDataPtr(uint32 uiMIPLevel = 0, uint32 uiArrayMember = 0, uint32 uiFaceNumber = 0) const; + + /*!*********************************************************************** + @Function getHeader + @Return const CPVRTextureHeader& Returns the header only for this texture. + @Description Gets the header for this texture, allowing you to create a new + texture based on this one with some changes. Useful for passing + information about a texture without passing all of its data. + *************************************************************************/ + const CPVRTextureHeader& getHeader() const; + + /******************************************************************************* + * File io. + *******************************************************************************/ + + /*!*********************************************************************** + @Function setPaddedMetaData + @Input uiPadding + @Description When writing the texture out to a PVR file, it is often + desirable to pad the meta data so that the start of the + texture data aligns to a given boundary. + This function pads to a boundary value equal to "uiPadding". + For example setting uiPadding=8 will align the start of the + texture data to an 8 byte boundary. + Note - this should be called immediately before saving as + the value is worked out based on the current meta data size. + *************************************************************************/ + void addPaddingMetaData( uint32 uiPadding ); + + /*!*********************************************************************** + @Function saveFile + @Input filepath + @Return bool Whether the method succeeds or not. + @Description Writes out to a file, given a filename and path. + File type will be determined by the extension present in the string. + If no extension is present, PVR format will be selected. + Unsupported formats will result in failure. + *************************************************************************/ + bool saveFile(const CPVRTString& filepath) const; + + /*!*********************************************************************** + @Function saveFileLegacyPVR + @Input filepath + @Input eApi + @Return bool Whether the method succeeds or not. + @Description Writes out to a file, stripping any extensions specified + and appending .pvr. This function is for legacy support only + and saves out to PVR Version 2 file. The target api must be + specified in order to save to this format. + *************************************************************************/ + bool saveFileLegacyPVR(const CPVRTString& filepath, ELegacyApi eApi) const; + + private: + size_t m_stDataSize; // Size of the texture data. + uint8* m_pTextureData; // Pointer to texture data. + + /******************************************************************************* + * Private IO functions + *******************************************************************************/ + /*!*********************************************************************** + @Function loadPVRFile + @Input pTextureFile + @Description Loads a PVR file. + *************************************************************************/ + bool privateLoadPVRFile(FILE* pTextureFile); + + /*!*********************************************************************** + @Function privateSavePVRFile + @Input pTextureFile + @Description Saves a PVR File. + *************************************************************************/ + bool privateSavePVRFile(FILE* pTextureFile) const; + + /*!*********************************************************************** + @Function loadKTXFile + @Input pTextureFile + @Description Loads a KTX file. + *************************************************************************/ + bool privateLoadKTXFile(FILE* pTextureFile); + + /*!*********************************************************************** + @Function privateSaveKTXFile + @Input pTextureFile + @Description Saves a KTX File. + *************************************************************************/ + bool privateSaveKTXFile(FILE* pTextureFile) const; + + /*!*********************************************************************** + @Function loadDDSFile + @Input pTextureFile + @Description Loads a DDS file. + *************************************************************************/ + bool privateLoadDDSFile(FILE* pTextureFile); + + /*!*********************************************************************** + @Function privateSaveDDSFile + @Input pTextureFile + @Description Saves a DDS File. + *************************************************************************/ + bool privateSaveDDSFile(FILE* pTextureFile) const; + + //Legacy IO + /*!*********************************************************************** + @Function privateSavePVRFile + @Input pTextureFile + @Input filename + @Description Saves a .h File. + *************************************************************************/ + bool privateSaveCHeaderFile(FILE* pTextureFile, CPVRTString filename) const; + + /*!*********************************************************************** + @Function privateSaveLegacyPVRFile + @Input pTextureFile + @Input eApi + @Description Saves a legacy PVR File - Uses version 2 file format. + *************************************************************************/ + bool privateSaveLegacyPVRFile(FILE* pTextureFile, ELegacyApi eApi) const; + }; +}; + +#endif //_PVRTEXTURE_H + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTextureDefines.h b/KREngine/3rdparty/pvrtexlib/include/PVRTextureDefines.h new file mode 100644 index 0000000..cadbd25 --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTextureDefines.h @@ -0,0 +1,98 @@ +#ifndef _PVRTEXTURE_DEFINES_H +#define _PVRTEXTURE_DEFINES_H + +//To use the PVRTexLib .dll on Windows, you need to define _WINDLL_IMPORT +#ifndef PVR_DLL +#if defined(_WINDLL_EXPORT) +#define PVR_DLL __declspec(dllexport) +//Forward declaration of various classes/structs used by this library. This exports their interfaces for DLLs. +struct PVR_DLL PVRTextureHeaderV3; +struct PVR_DLL MetaDataBlock; +template +class PVR_DLL CPVRTMap; +template +class PVR_DLL CPVRTArray; +class PVR_DLL CPVRTString; +#elif defined(_WINDLL_IMPORT) +#define PVR_DLL __declspec(dllimport) +//Forward declaration of various classes/structs used by this library. This imports their interfaces for DLLs. +struct PVR_DLL PVRTextureHeaderV3; +struct PVR_DLL MetaDataBlock; +template +class PVR_DLL CPVRTMap; +template +class PVR_DLL CPVRTArray; +class PVR_DLL CPVRTString; +#else +#define PVR_DLL +#endif +#endif + + +#include "PVRTTexture.h" + +namespace pvrtexture +{ + /***************************************************************************** + * Type defines for standard variable sizes. + *****************************************************************************/ + typedef signed char int8; + typedef signed short int16; + typedef signed int int32; + typedef signed long long int64; + typedef unsigned char uint8; + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef unsigned long long uint64; + + /***************************************************************************** + * Texture related constants and enumerations. + *****************************************************************************/ + enum ECompressorQuality + { + ePVRTCFast=0, + ePVRTCNormal, + ePVRTCHigh, + ePVRTCBest, + eNumPVRTCModes, + + eETCFast=0, + eETCFastPerceptual, + eETCSlow, + eETCSlowPerceptual, + eNumETCModes + }; + + enum EResizeMode + { + eResizeNearest, + eResizeLinear, + eResizeCubic, + eNumResizeModes + }; + + // Legacy - API enums. + enum ELegacyApi + { + eOGLES=1, + eOGLES2, + eD3DM, + eOGL, + eDX9, + eDX10, + eOVG, + eMGL, + }; + + /***************************************************************************** + * Useful macros. + *****************************************************************************/ + #define TEXOFFSET2D(x,y,width) ( ((x)+(y)*(width)) ) + #define TEXOFFSET3D(x,y,z,width,height) ( ((x)+(y)*(width)+(z)*(width)*(height)) ) + + /***************************************************************************** + * Useful typedef for Meta Data Maps + *****************************************************************************/ + typedef CPVRTMap > MetaDataMap; +}; +#endif //_PVRTEXTURE_DEFINES_H diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTextureFormat.h b/KREngine/3rdparty/pvrtexlib/include/PVRTextureFormat.h new file mode 100644 index 0000000..48627ec --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTextureFormat.h @@ -0,0 +1,73 @@ +#ifndef _PVRT_PIXEL_FORMAT_H +#define _PVRT_PIXEL_FORMAT_H + +#include "PVRTextureDefines.h" +#include "PVRTString.h" + +namespace pvrtexture +{ + //Channel Names + enum EChannelName + { + eNoChannel, + eRed, + eGreen, + eBlue, + eAlpha, + eLuminance, + eIntensity, + eUnspecified, + eNumChannels + }; + + //PixelType union + union PVR_DLL PixelType + { + /*!*********************************************************************** + @Function PixelType + @Return A new PixelType + @Description Creates an empty pixeltype. + *************************************************************************/ + PixelType(); + + /*!*********************************************************************** + @Function PixelType + @Input Type + @Return A new PixelType + @Description Initialises a new pixel type from a 64 bit integer value. + *************************************************************************/ + PixelType(uint64 Type); + + /*!*********************************************************************** + @Function PixelType + @Input C1Name + @Input C2Name + @Input C3Name + @Input C4Name + @Input C1Bits + @Input C2Bits + @Input C3Bits + @Input C4Bits + @Return A new PixelType + @Description Takes up to 4 characters (CnName) and 4 values (CnBits) + to create a new PixelType. Any unused channels should be set to 0. + For example: PixelType('r','g','b',0,8,8,8,0); + *************************************************************************/ + PixelType(uint8 C1Name, uint8 C2Name, uint8 C3Name, uint8 C4Name, uint8 C1Bits, uint8 C2Bits, uint8 C3Bits, uint8 C4Bits); + + struct PVR_DLL LowHigh + { + uint32 Low; + uint32 High; + } Part; + + uint64 PixelTypeID; + uint8 PixelTypeChar[8]; + }; + + static const PixelType PVRStandard8PixelType = PixelType('r','g','b','a',8,8,8,8); + static const PixelType PVRStandard16PixelType = PixelType('r','g','b','a',16,16,16,16); + static const PixelType PVRStandard32PixelType = PixelType('r','g','b','a',32,32,32,32); +} + +#endif diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTextureHeader.h b/KREngine/3rdparty/pvrtexlib/include/PVRTextureHeader.h new file mode 100644 index 0000000..52e318c --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTextureHeader.h @@ -0,0 +1,586 @@ +#ifndef _PVRTEXTURE_HEADER_H +#define _PVRTEXTURE_HEADER_H + +#include "PVRTextureDefines.h" +#include "PVRTextureFormat.h" +#include "PVRTString.h" +#include "PVRTMap.h" + +namespace pvrtexture +{ + //Wrapper class for PVRTextureHeaderV3, adds 'smart' accessor functions. + class PVR_DLL CPVRTextureHeader + { + protected: + PVRTextureHeaderV3 m_sHeader; //Texture header as laid out in a file. + CPVRTMap > m_MetaData; //Map of all the meta data stored for a texture. + + public: + /******************************************************************************* + * Construction methods for a texture header. + *******************************************************************************/ + /*!*********************************************************************** + @Function CPVRTextureHeader + @Return CPVRTextureHeader A new texture header. + @Description Default constructor for a CPVRTextureHeader. Returns an empty header. + *************************************************************************/ + CPVRTextureHeader(); + + /*!*********************************************************************** + @Function CPVRTextureHeader + @Input fileHeader + @Input metaDataCount + @Input metaData + @Return CPVRTextureHeader A new texture header. + @Description Creates a new texture header from a PVRTextureHeaderV3, + and appends Meta data if any is supplied. + *************************************************************************/ + CPVRTextureHeader( PVRTextureHeaderV3 fileHeader, + uint32 metaDataCount=0, + MetaDataBlock* metaData=NULL); + + /*!*********************************************************************** + @Function CPVRTextureHeader + @Input u64PixelFormat + @Input u32Height + @Input u32Width + @Input u32Depth + @Input u32NumMipMaps + @Input u32NumArrayMembers + @Input u32NumFaces + @Input eColourSpace + @Input eChannelType + @Input bPreMultiplied + @Return CPVRTextureHeader A new texture header. + @Description Creates a new texture header based on individual header + variables. + *************************************************************************/ + CPVRTextureHeader( uint64 u64PixelFormat, + uint32 u32Height=1, + uint32 u32Width=1, + uint32 u32Depth=1, + uint32 u32NumMipMaps=1, + uint32 u32NumArrayMembers=1, + uint32 u32NumFaces=1, + EPVRTColourSpace eColourSpace=ePVRTCSpacelRGB, + EPVRTVariableType eChannelType=ePVRTVarTypeUnsignedByteNorm, + bool bPreMultiplied=false); + + /*!*********************************************************************** + @Function operator= + @Input rhs + @Return CPVRTextureHeader& This header. + @Description Will copy the contents and information of another header into this one. + *************************************************************************/ + CPVRTextureHeader& operator=(const CPVRTextureHeader& rhs); + + /******************************************************************************* + * Accessor Methods for a texture's properties - getters. + *******************************************************************************/ + + /*!*********************************************************************** + @Function getFileHeader + @Return PVRTextureHeaderV3 The file header. + @Description Gets the file header structure. + *************************************************************************/ + const PVRTextureHeaderV3 getFileHeader() const; + + /*!*********************************************************************** + @Function getPixelType + @Return PixelType 64-bit pixel type ID. + @Description Gets the 64-bit pixel type ID of the texture. + *************************************************************************/ + const PixelType getPixelType() const; + + /*!*********************************************************************** + @Function getBitsPerPixel + @Return uint32 Number of bits per pixel + @Description Gets the bits per pixel of the texture format. + *************************************************************************/ + const uint32 getBitsPerPixel() const; + + /*!*********************************************************************** + @Function getColourSpace + @Return EPVRTColourSpace enum representing colour space. + @Description Returns the colour space of the texture. + *************************************************************************/ + const EPVRTColourSpace getColourSpace() const; + + /*!*********************************************************************** + @Function getChannelType + @Return EPVRTVariableType enum representing the type of the texture. + @Description Returns the variable type that the texture's data is stored in. + *************************************************************************/ + const EPVRTVariableType getChannelType() const; + + /*!*********************************************************************** + @Function getWidth + @Input uiMipLevel MIP level that user is interested in. + @Return uint32 Width of the specified MIP-Map level. + @Description Gets the width of the user specified MIP-Map + level for the texture + *************************************************************************/ + const uint32 getWidth(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const; + + /*!*********************************************************************** + @Function getHeight + @Input uiMipLevel MIP level that user is interested in. + @Return uint32 Height of the specified MIP-Map level. + @Description Gets the height of the user specified MIP-Map + level for the texture + *************************************************************************/ + const uint32 getHeight(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const; + + /*!*********************************************************************** + @Function getDepth + @Input uiMipLevel MIP level that user is interested in. + @Return Depth of the specified MIP-Map level. + @Description Gets the depth of the user specified MIP-Map + level for the texture + *************************************************************************/ + const uint32 getDepth(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const; + + /*!*********************************************************************** + @Function getTextureSize + @Input iMipLevel Specifies a MIP level to check, + 'PVRTEX_ALLMIPLEVELS' can be passed to get + the size of all MIP levels. + @Input bAllSurfaces Size of all surfaces is calculated if true, + only a single surface if false. + @Input bAllFaces Size of all faces is calculated if true, + only a single face if false. + @Return uint32 Size in PIXELS of the specified texture area. + @Description Gets the size in PIXELS of the texture, given various input + parameters. User can retrieve the total size of either all + surfaces or a single surface, all faces or a single face and + all MIP-Maps or a single specified MIP level. All of these + *************************************************************************/ + const uint32 getTextureSize(int32 iMipLevel=PVRTEX_ALLMIPLEVELS, bool bAllSurfaces = true, bool bAllFaces = true) const; + + /*!*********************************************************************** + @Function getDataSize + @Input iMipLevel Specifies a mip level to check, + 'PVRTEX_ALLMIPLEVELS' can be passed to get + the size of all MIP levels. + @Input bAllSurfaces Size of all surfaces is calculated if true, + only a single surface if false. + @Input bAllFaces Size of all faces is calculated if true, + only a single face if false. + @Return uint32 Size in BYTES of the specified texture area. + @Description Gets the size in BYTES of the texture, given various input + parameters. User can retrieve the size of either all + surfaces or a single surface, all faces or a single face + and all MIP-Maps or a single specified MIP level. + *************************************************************************/ + const uint32 getDataSize(int32 iMipLevel=PVRTEX_ALLMIPLEVELS, bool bAllSurfaces = true, bool bAllFaces = true) const; + + /*!*********************************************************************** + @Function getNumArrayMembers + @Return uint32 Number of array members in this texture. + @Description Gets the number of array members stored in this texture. + *************************************************************************/ + const uint32 getNumArrayMembers() const; + + /*!*********************************************************************** + @Function getNumMIPLevels + @Return uint32 Number of MIP-Map levels in this texture. + @Description Gets the number of MIP-Map levels stored in this texture. + *************************************************************************/ + const uint32 getNumMIPLevels() const; + + /*!*********************************************************************** + @Function getNumFaces + @Return uint32 Number of faces in this texture. + @Description Gets the number of faces stored in this texture. + *************************************************************************/ + const uint32 getNumFaces() const; + + /*!*********************************************************************** + @Function getOrientation + @Input axis EPVRTAxis type specifying the axis to examine. + @Return EPVRTOrientation Enum orientation of the axis. + @Description Gets the data orientation for this texture. + *************************************************************************/ + const EPVRTOrientation getOrientation(EPVRTAxis axis) const; + + /*!*********************************************************************** + @Function isFileCompressed + @Return bool True if it is file compressed. + @Description Returns whether or not the texture is compressed using + PVRTexLib's FILE compression - this is independent of + any texture compression. + *************************************************************************/ + const bool isFileCompressed() const; + + /*!*********************************************************************** + @Function isPreMultiplied + @Return bool True if texture is premultiplied. + @Description Returns whether or not the texture's colour has been + pre-multiplied by the alpha values. + *************************************************************************/ + const bool isPreMultiplied() const; + + /*!*********************************************************************** + @Function getMetaDataSize + @Return const uint32 Size, in bytes, of the meta data stored in the header. + @Description Returns the total size of the meta data stored in the header. + This includes the size of all information stored in all MetaDataBlocks. + *************************************************************************/ + const uint32 getMetaDataSize() const; + + /*!*********************************************************************** + @Function getOGLFormat + @Modified internalformat + @Modified format + @Modified type + @Description Gets the OpenGL equivalent values of internal format, format + and type for this texture. This will return any supported + OpenGL texture values, it is up to the user to decide if + these are valid for their current platform. + *************************************************************************/ + const void getOGLFormat(uint32& internalformat, uint32& format, uint32& type) const; + + /*!*********************************************************************** + @Function getOGLESFormat + @Modified internalformat + @Modified format + @Modified type + @Description Gets the OpenGLES equivalent values of internal format, + format and type for this texture. This will return any + supported OpenGLES texture values, it is up to the user + to decide if these are valid for their current platform. + *************************************************************************/ + const void getOGLESFormat(uint32& internalformat, uint32& format, uint32& type) const; + + /*!*********************************************************************** + @Function getD3DFormat + @Return const uint32 + @Description Gets the D3DFormat (up to DirectX 9 and Direct 3D Mobile) + equivalent values for this texture. This will return any + supported D3D texture formats, it is up to the user to + decide if this is valid for their current platform. + *************************************************************************/ + const uint32 getD3DFormat() const; + + /*!*********************************************************************** + @Function getDXGIFormat + @Return const uint32 + @Description Gets the DXGIFormat (DirectX 10 onward) equivalent values + for this texture. This will return any supported DX texture + formats, it is up to the user to decide if this is valid + for their current platform. + *************************************************************************/ + const uint32 getDXGIFormat() const; + + /*!*********************************************************************** + * Accessor Methods for a texture's properties - setters. + *************************************************************************/ + + /*!*********************************************************************** + @Function setPixelFormat + @Input uPixelFormat The format of the pixel. + @Description Sets the pixel format for this texture. + *************************************************************************/ + void setPixelFormat(PixelType uPixelFormat); + + /*!*********************************************************************** + @Function setColourSpace + @Input eColourSpace A colour space enum. + @Description Sets the colour space for this texture. Default is lRGB. + *************************************************************************/ + void setColourSpace(EPVRTColourSpace eColourSpace); + + /*!*********************************************************************** + @Function setChannelType + @Input eVarType A variable type enum. + @Description Sets the variable type for the channels in this texture. + *************************************************************************/ + void setChannelType(EPVRTVariableType eVarType); + + /*!*********************************************************************** + @Function setOGLFormat + @Input internalformat + @Input format + @Input type + @Return bool Whether the format is valid or not. + @Description Sets the format of the texture to PVRTexLib's internal + representation of the OGL format. + *************************************************************************/ + bool setOGLFormat(const uint32& internalformat, const uint32& format, const uint32& type); + + /*!*********************************************************************** + @Function setOGLESFormat + @Input internalformat + @Input format + @Input type + @Return bool Whether the format is valid or not. + @Description Sets the format of the texture to PVRTexLib's internal + representation of the OGLES format. + *************************************************************************/ + bool setOGLESFormat(const uint32& internalformat, const uint32& format, const uint32& type); + + /*!*********************************************************************** + @Function setD3DFormat + @Return bool Whether the format is valid or not. + @Description Sets the format of the texture to PVRTexLib's internal + representation of the D3D format. + *************************************************************************/ + bool setD3DFormat(const uint32& DWORD_D3D_FORMAT); + + /*!*********************************************************************** + @Function setDXGIFormat + @Return bool Whether the format is valid or not. + @Description Sets the format of the texture to PVRTexLib's internal + representation of the DXGI format. + *************************************************************************/ + bool setDXGIFormat(const uint32& DWORD_DXGI_FORMAT); + + /*!*********************************************************************** + @Function setWidth + @Input newWidth The new width. + @Description Sets the width. + *************************************************************************/ + void setWidth(uint32 newWidth); + + /*!*********************************************************************** + @Function setHeight + @Input newHeight The new height. + @Description Sets the height. + *************************************************************************/ + void setHeight(uint32 newHeight); + + /*!*********************************************************************** + @Function setDepth + @Input newDepth The new depth. + @Description Sets the depth. + *************************************************************************/ + void setDepth(uint32 newDepth); + + /*!*********************************************************************** + @Function setNumArrayMembers + @Input newNumMembers The new number of members in this array. + @Description Sets the depth. + *************************************************************************/ + void setNumArrayMembers(uint32 newNumMembers); + + /*!*********************************************************************** + @Function setNumMIPLevels + @Input newNumMIPLevels New number of MIP-Map levels. + @Description Sets the number of MIP-Map levels in this texture. + *************************************************************************/ + void setNumMIPLevels(uint32 newNumMIPLevels); + + /*!*********************************************************************** + @Function setNumFaces + @Input newNumFaces New number of faces for this texture. + @Description Sets the number of faces stored in this texture. + *************************************************************************/ + void setNumFaces(uint32 newNumFaces); + + /*!*********************************************************************** + @Function setOrientation + @Input eAxisOrientation Enum specifying axis and orientation. + @Description Sets the data orientation for a given axis in this texture. + *************************************************************************/ + void setOrientation(EPVRTOrientation eAxisOrientation); + + /*!*********************************************************************** + @Function setIsFileCompressed + @Input isFileCompressed Sets file compression to true/false. + @Description Sets whether or not the texture is compressed using + PVRTexLib's FILE compression - this is independent of + any texture compression. Currently unsupported. + *************************************************************************/ + void setIsFileCompressed(bool isFileCompressed); + + /*!*********************************************************************** + @Function isPreMultiplied + @Return isPreMultiplied Sets if texture is premultiplied. + @Description Sets whether or not the texture's colour has been + pre-multiplied by the alpha values. + *************************************************************************/ + void setIsPreMultiplied(bool isPreMultiplied); + + /*!*********************************************************************** + Meta Data functions - Getters. + *************************************************************************/ + + /*!*********************************************************************** + @Function isBumpMap + @Return bool True if it is a bump map. + @Description Returns whether the texture is a bump map or not. + *************************************************************************/ + const bool isBumpMap() const; + + /*!*********************************************************************** + @Function getBumpMapScale + @Return float Returns the bump map scale. + @Description Gets the bump map scaling value for this texture. If the + texture is not a bump map, 0.0f is returned. If the + texture is a bump map but no meta data is stored to + specify its scale, then 1.0f is returned. + *************************************************************************/ + const float getBumpMapScale() const; + + /*!*********************************************************************** + @Function getBumpMapOrder + @Return CPVRTString Returns bump map order relative to rgba. + @Description Gets the bump map channel order relative to rgba. For + example, an RGB texture with bumps mapped to XYZ returns + 'xyz'. A BGR texture with bumps in the order ZYX will also + return 'xyz' as the mapping is the same: R=X, G=Y, B=Z. + If the letter 'h' is present in the string, it means that + the height map has been stored here. + Other characters are possible if the bump map was created + manually, but PVRTexLib will ignore these characters. They + are returned simply for completeness. + *************************************************************************/ + const CPVRTString getBumpMapOrder() const; + + /*!*********************************************************************** + @Function getNumTextureAtlasMembers + @Return int Returns number of sub textures defined by meta data. + @Description Works out the number of possible texture atlas members in + the texture based on the w/h/d and the data size. + *************************************************************************/ + const int getNumTextureAtlasMembers() const; + + /*!*********************************************************************** + @Function getTextureAtlasData + @Return float* Returns a pointer directly to the texture atlas data. + @Description Returns a pointer to the texture atlas data. + *************************************************************************/ + const float* getTextureAtlasData() const; + + /*!*********************************************************************** + @Function getCubeMapOrder + @Return CPVRTString Returns cube map order. + @Description Gets the cube map face order. Returned string will be in + the form "ZzXxYy" with capitals representing positive and + small letters representing negative. I.e. Z=Z-Positive, + z=Z-Negative. + *************************************************************************/ + const CPVRTString getCubeMapOrder() const; + + /*!*********************************************************************** + @Function getBorder + @Input uiBorderWidth + @Input uiBorderHeight + @Input uiBorderDepth + @Description Obtains the border size in each dimension for this texture. + *************************************************************************/ + void getBorder(uint32& uiBorderWidth, uint32& uiBorderHeight, uint32& uiBorderDepth) const; + + /*!*********************************************************************** + @Function getMetaData + @Input DevFOURCC + @Input u32Key + @Return pvrtexture::MetaDataBlock A copy of the meta data from the texture. + @Description Returns a block of meta data from the texture. If the meta data doesn't exist, a block with data size 0 will be returned. + *************************************************************************/ + const MetaDataBlock getMetaData(uint32 DevFOURCC, uint32 u32Key) const; + + /*!*********************************************************************** + @Function hasMetaData + @Input DevFOURCC + @Input u32Key + @Return bool Whether or not the meta data bock specified exists + @Description Returns whether or not the specified meta data exists as + part of this texture header. + *************************************************************************/ + bool hasMetaData(uint32 DevFOURCC, uint32 u32Key) const; + + /*!*********************************************************************** + @Function getMetaDataMap + @Return MetaDataMap* A direct pointer to the MetaData map. + @Description A pointer directly to the Meta Data Map, to allow users to read out data. + *************************************************************************/ + const MetaDataMap* const getMetaDataMap() const; + + /*!*********************************************************************** + Meta Data functions - Setters. + *************************************************************************/ + + /*!*********************************************************************** + @Function setBumpMap + @Input bumpScale Floating point "height" value to scale the bump map. + @Input bumpOrder Up to 4 character string, with values x,y,z,h in + some combination. Not all values need to be present. + Denotes channel order; x,y,z refer to the + corresponding axes, h indicates presence of the + original height map. It is possible to have only some + of these values rather than all. For example if 'h' + is present alone it will be considered a height map. + The values should be presented in RGBA order, regardless + of the texture format, so a zyxh order in a bgra texture + should still be passed as 'xyzh'. Capitals are allowed. + Any character stored here that is not one of x,y,z,h + or a NULL character will be ignored when PVRTexLib + reads the data, but will be preserved. This is useful + if you wish to define a custom data channel for instance. + In these instances PVRTexLib will assume it is simply + colour data. + @Description Sets a texture's bump map data. + *************************************************************************/ + void setBumpMap(float bumpScale, CPVRTString bumpOrder="xyz"); + + /*!*********************************************************************** + @Function setTextureAtlas + @Input pAtlasData Pointer to an array of atlas data. + @Input dataSize Number of floats that the data pointer contains. + @Description Sets the texture atlas coordinate meta data for later display. + It is up to the user to make sure that this texture atlas + data actually makes sense in the context of the header. It is + suggested that the "generateTextureAtlas" method in the tools + is used to create a texture atlas, manually setting one up is + possible but should be done with care. + *************************************************************************/ + void setTextureAtlas(float* pAtlasData, uint32 dataSize); + + /*!*********************************************************************** + @Function setCubeMapOrder + @Input cubeMapOrder Up to 6 character string, with values + x,X,y,Y,z,Z in some combination. Not all + values need to be present. Denotes face + order; Capitals refer to positive axis + positions and small letters refer to + negative axis positions. E.g. x=X-Negative, + X=X-Positive. It is possible to have only + some of these values rather than all, as + long as they are NULL terminated. + NB: Values past the 6th character are not read. + @Description Sets a texture's bump map data. + *************************************************************************/ + void setCubeMapOrder(CPVRTString cubeMapOrder="XxYyZz"); + + /*!*********************************************************************** + @Function setBorder + @Input uiBorderWidth + @Input uiBorderHeight + @Input uiBorderDepth + @Return void + @Description Sets a texture's border size data. This value is subtracted + from the current texture height/width/depth to get the valid + texture data. + *************************************************************************/ + void setBorder(uint32 uiBorderWidth, uint32 uiBorderHeight, uint32 uiBorderDepth); + + /*!*********************************************************************** + @Function addMetaData + @Input MetaBlock Meta data block to be added. + @Description Adds an arbitrary piece of meta data. + *************************************************************************/ + void addMetaData(const MetaDataBlock& MetaBlock); + + /*!*********************************************************************** + @Function removeMetaData + @Input DevFourCC + @Input u32Key + @Return void + @Description Removes a specified piece of meta data, if it exists. + *************************************************************************/ + void removeMetaData(const uint32& DevFourCC, const uint32& u32Key); + }; +}; + +#endif diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTextureUtilities.h b/KREngine/3rdparty/pvrtexlib/include/PVRTextureUtilities.h new file mode 100644 index 0000000..20da6db --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTextureUtilities.h @@ -0,0 +1,157 @@ +#ifndef _PVRTEXTURE_UTILITIES_H +#define _PVRTEXTURE_UTILITIES_H + +#include "PVRTextureFormat.h" +#include "PVRTexture.h" + +namespace pvrtexture +{ + /*!*********************************************************************** + @Function Resize + @Input sTexture + @Input u32NewWidth + @Input u32NewHeight + @Input u32NewDepth + @Input eResizeMode + @Return bool Whether the method succeeds or not. + @Description Resizes the texture to new specified dimensions. Filtering + mode is specified with "eResizeMode". + *************************************************************************/ + bool PVR_DLL Resize(CPVRTexture& sTexture, const uint32& u32NewWidth, const uint32& u32NewHeight, const uint32& u32NewDepth, const EResizeMode eResizeMode); + + /*!*********************************************************************** + @Function Rotate90 + @Input sTexture + @Input eRotationAxis + @Input bForward + @Return bool Whether the method succeeds or not. + @Description Rotates a texture by 90 degrees around the given axis. bForward controls direction of rotation. + *************************************************************************/ + bool PVR_DLL Rotate90(CPVRTexture& sTexture, const EPVRTAxis eRotationAxis, const bool bForward); + + /*!*********************************************************************** + @Function Flip + @Input sTexture + @Input eFlipDirection + @Return bool Whether the method succeeds or not. + @Description Flips a texture in a given direction. + *************************************************************************/ + bool PVR_DLL Flip(CPVRTexture& sTexture, const EPVRTAxis eFlipDirection); + + /*!*********************************************************************** + @Function Border + @Input sTexture + @Input uiBorderX + @Input uiBorderY + @Input uiBorderZ + @Return bool Whether the method succeeds or not. + @Description Adds a user specified border to the texture. + *************************************************************************/ + bool PVR_DLL Border(CPVRTexture& sTexture, uint32 uiBorderX, uint32 uiBorderY, uint32 uiBorderZ); + + /*!*********************************************************************** + @Function PreMultiplyAlpha + @Input sTexture + @Return bool Whether the method succeeds or not. + @Description Pre-multiplies a texture's colours by its alpha values. + *************************************************************************/ + bool PVR_DLL PreMultiplyAlpha(CPVRTexture& sTexture); + + /*!*********************************************************************** + @Function Bleed + @Input sTexture + @Return bool Whether the method succeeds or not. + @Description Allows a texture's colours to run into any fully transparent areas. + *************************************************************************/ + bool PVR_DLL Bleed(CPVRTexture& sTexture); + + /*!*********************************************************************** + @Function SetChannels + @Input sTexture + @Input uiNumChannelSets + @Input eChannels + @Input pValues + @Return bool Whether the method succeeds or not. + @Description Sets the specified number of channels to values specified in pValues. + *************************************************************************/ + bool PVR_DLL SetChannels(CPVRTexture& sTexture, uint32 uiNumChannelSets, EChannelName *eChannels, uint32 *pValues); + bool PVR_DLL SetChannelsFloat(CPVRTexture& sTexture, uint32 uiNumChannelSets, EChannelName *eChannels, float *pValues); + + /*!*********************************************************************** + @Function CopyChannels + @Input sTexture + @Input sTextureSource + @Input uiNumChannelCopies + @Input eChannels + @Input eChannelsSource + @Return bool Whether the method succeeds or not. + @Description Copies the specified channels from sTextureSource into sTexture. + sTextureSource is not modified so it is possible to use the + same texture as both input and output. When using the same + texture as source and destination, channels are preserved + between swaps (e.g. copying Red to Green and then Green to Red + will result in the two channels trading places correctly). + Channels in eChannels are set to the value of the channels + in eChannelSource. + *************************************************************************/ + bool PVR_DLL CopyChannels(CPVRTexture& sTexture, const CPVRTexture& sTextureSource, uint32 uiNumChannelCopies, EChannelName *eChannels, EChannelName *eChannelsSource); + + /*!*********************************************************************** + @Function GenerateNormalMap + @Input sTexture + @Input fScale + @Input sChannelOrder + @Return bool Whether the method succeeds or not. + @Description Generates a Normal Map from a given height map. + Assumes the red channel has the height values. + By default outputs to red/green/blue = x/y/z, + this can be overridden by specifying a channel + order in sChannelOrder. The channels specified + will output to red/green/blue/alpha in that order. + So "xyzh" maps x to red, y to green, z to blue + and h to alpha. 'h' is used to specify that the + original height map data should be preserved in + the given channel. + *************************************************************************/ + bool PVR_DLL GenerateNormalMap(CPVRTexture& sTexture, const float fScale, CPVRTString sChannelOrder); + + /*!*********************************************************************** + @Function GenerateMIPMaps + @Input sTexture + @Input eFilterMode + @Input uiMIPMapsToDo + @Return bool Whether the method succeeds or not. + @Description Generates MIPMaps for a source texture. Default is to + create a complete MIPMap chain, however this can be + overridden with uiMIPMapsToDo. + *************************************************************************/ + bool PVR_DLL GenerateMIPMaps(CPVRTexture& sTexture, const EResizeMode eFilterMode, const uint32 uiMIPMapsToDo=PVRTEX_ALLMIPLEVELS); + + /*!*********************************************************************** + @Function ColourMIPMaps + @Input sTexture + @Return bool Whether the method succeeds or not. + @Description Colours a texture's MIPMap levels with artificial colours + for debugging. MIP levels are coloured in the order: + Red, Green, Blue, Cyan, Magenta and Yellow + in a repeating pattern. + *************************************************************************/ + bool PVR_DLL ColourMIPMaps(CPVRTexture& sTexture); + + /*!*********************************************************************** + @Function Transcode + @Input sTexture + @Input ptFormat + @Input eChannelType + @Input eColourspace + @Input eQuality + @Input bDoDither + @Return bool Whether the method succeeds or not. + @Description Transcodes a texture from its original format into a newly specified format. + Will either quantise or dither to lower precisions based on bDoDither. + uiQuality specifies the quality for PVRTC and ETC compression. + *************************************************************************/ + bool PVR_DLL Transcode(CPVRTexture& sTexture, const PixelType ptFormat, const EPVRTVariableType eChannelType, const EPVRTColourSpace eColourspace, const ECompressorQuality eQuality=ePVRTCNormal, const bool bDoDither=false); +}; +#endif //_PVRTEXTURE_UTILTIES_H + diff --git a/KREngine/3rdparty/pvrtexlib/include/PVRTextureVersion.h b/KREngine/3rdparty/pvrtexlib/include/PVRTextureVersion.h new file mode 100644 index 0000000..38ca378 --- /dev/null +++ b/KREngine/3rdparty/pvrtexlib/include/PVRTextureVersion.h @@ -0,0 +1,7 @@ +#ifndef PVRTEXLIBVERSION_H +#define PVRTEXLIBVERSION_H +#define PVRTLMAJORVERSION 4 +#define PVRTLMINORVERSION 6 +#define PVRTLSTRINGVERSION "4.6" +#define PVRTLVERSIONDESCRIPTOR "" //"BETA" //"ALPHA" //"ENGINEERING DROP" +#endif diff --git a/KREngine/3rdparty/pvrtexlib/static_osx/libPVRTexLib.a b/KREngine/3rdparty/pvrtexlib/static_osx/libPVRTexLib.a new file mode 100644 index 0000000..2615b1f Binary files /dev/null and b/KREngine/3rdparty/pvrtexlib/static_osx/libPVRTexLib.a differ diff --git a/KREngine/3rdparty/recast/include/Recast.h b/KREngine/3rdparty/recast/include/Recast.h new file mode 100755 index 0000000..336837e --- /dev/null +++ b/KREngine/3rdparty/recast/include/Recast.h @@ -0,0 +1,1135 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#ifndef RECAST_H +#define RECAST_H + +/// The value of PI used by Recast. +static const float RC_PI = 3.14159265f; + +/// Recast log categories. +/// @see rcContext +enum rcLogCategory +{ + RC_LOG_PROGRESS = 1, ///< A progress log entry. + RC_LOG_WARNING, ///< A warning log entry. + RC_LOG_ERROR, ///< An error log entry. +}; + +/// Recast performance timer categories. +/// @see rcContext +enum rcTimerLabel +{ + /// The user defined total time of the build. + RC_TIMER_TOTAL, + /// A user defined build time. + RC_TIMER_TEMP, + /// The time to rasterize the triangles. (See: #rcRasterizeTriangle) + RC_TIMER_RASTERIZE_TRIANGLES, + /// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield) + RC_TIMER_BUILD_COMPACTHEIGHTFIELD, + /// The total time to build the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS, + /// The time to trace the boundaries of the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_TRACE, + /// The time to simplify the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_SIMPLIFY, + /// The time to filter ledge spans. (See: #rcFilterLedgeSpans) + RC_TIMER_FILTER_BORDER, + /// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans) + RC_TIMER_FILTER_WALKABLE, + /// The time to apply the median filter. (See: #rcMedianFilterWalkableArea) + RC_TIMER_MEDIAN_AREA, + /// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles) + RC_TIMER_FILTER_LOW_OBSTACLES, + /// The time to build the polygon mesh. (See: #rcBuildPolyMesh) + RC_TIMER_BUILD_POLYMESH, + /// The time to merge polygon meshes. (See: #rcMergePolyMeshes) + RC_TIMER_MERGE_POLYMESH, + /// The time to erode the walkable area. (See: #rcErodeWalkableArea) + RC_TIMER_ERODE_AREA, + /// The time to mark a box area. (See: #rcMarkBoxArea) + RC_TIMER_MARK_BOX_AREA, + /// The time to mark a cylinder area. (See: #rcMarkCylinderArea) + RC_TIMER_MARK_CYLINDER_AREA, + /// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea) + RC_TIMER_MARK_CONVEXPOLY_AREA, + /// The total time to build the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD, + /// The time to build the distances of the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_DIST, + /// The time to blur the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_BLUR, + /// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS, + /// The total time to apply the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_WATERSHED, + /// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_EXPAND, + /// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_FLOOD, + /// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS_FILTER, + /// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers) + RC_TIMER_BUILD_LAYERS, + /// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail) + RC_TIMER_BUILD_POLYMESHDETAIL, + /// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails) + RC_TIMER_MERGE_POLYMESHDETAIL, + /// The maximum number of timers. (Used for iterating timers.) + RC_MAX_TIMERS +}; + +/// Provides an interface for optional logging and performance tracking of the Recast +/// build process. +/// @ingroup recast +class rcContext +{ +public: + + /// Contructor. + /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true] + inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {} + virtual ~rcContext() {} + + /// Enables or disables logging. + /// @param[in] state TRUE if logging should be enabled. + inline void enableLog(bool state) { m_logEnabled = state; } + + /// Clears all log entries. + inline void resetLog() { if (m_logEnabled) doResetLog(); } + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] format The message. + void log(const rcLogCategory category, const char* format, ...); + + /// Enables or disables the performance timers. + /// @param[in] state TRUE if timers should be enabled. + inline void enableTimer(bool state) { m_timerEnabled = state; } + + /// Clears all peformance timers. (Resets all to unused.) + inline void resetTimers() { if (m_timerEnabled) doResetTimers(); } + + /// Starts the specified performance timer. + /// @param label The category of timer. + inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); } + + /// Stops the specified performance timer. + /// @param label The category of the timer. + inline void stopTimer(const rcTimerLabel label) { if (m_timerEnabled) doStopTimer(label); } + + /// Returns the total accumulated time of the specified performance timer. + /// @param label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } + +protected: + + /// Clears all log entries. + virtual void doResetLog() {} + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] msg The formatted message. + /// @param[in] len The length of the formatted message. + virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} + + /// Clears all timers. (Resets all to unused.) + virtual void doResetTimers() {} + + /// Starts the specified performance timer. + /// @param[in] label The category of timer. + virtual void doStartTimer(const rcTimerLabel /*label*/) {} + + /// Stops the specified performance timer. + /// @param[in] label The category of the timer. + virtual void doStopTimer(const rcTimerLabel /*label*/) {} + + /// Returns the total accumulated time of the specified performance timer. + /// @param[in] label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } + + /// True if logging is enabled. + bool m_logEnabled; + + /// True if the performance timers are enabled. + bool m_timerEnabled; +}; + +/// Specifies a configuration to use when performing Recast builds. +/// @ingroup recast +struct rcConfig +{ + /// The width of the field along the x-axis. [Limit: >= 0] [Units: vx] + int width; + + /// The height of the field along the z-axis. [Limit: >= 0] [Units: vx] + int height; + + /// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx] + int tileSize; + + /// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] + int borderSize; + + /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu] + float cs; + + /// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu] + float ch; + + /// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmin[3]; + + /// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmax[3]; + + /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees] + float walkableSlopeAngle; + + /// Minimum floor to 'ceiling' height that will still allow the floor area to + /// be considered walkable. [Limit: >= 3] [Units: vx] + int walkableHeight; + + /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx] + int walkableClimb; + + /// The distance to erode/shrink the walkable area of the heightfield away from + /// obstructions. [Limit: >=0] [Units: vx] + int walkableRadius; + + /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx] + int maxEdgeLen; + + /// The maximum distance a simplfied contour's border edges should deviate + /// the original raw contour. [Limit: >=0] [Units: vx] + float maxSimplificationError; + + /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] + int minRegionArea; + + /// Any regions with a span count smaller than this value will, if possible, + /// be merged with larger regions. [Limit: >=0] [Units: vx] + int mergeRegionArea; + + /// The maximum number of vertices allowed for polygons generated during the + /// contour to polygon conversion process. [Limit: >= 3] + int maxVertsPerPoly; + + /// Sets the sampling distance to use when generating the detail mesh. + /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu] + float detailSampleDist; + + /// The maximum distance the detail mesh surface should deviate from heightfield + /// data. (For height detail only.) [Limit: >=0] [Units: wu] + float detailSampleMaxError; +}; + +/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_HEIGHT_BITS = 13; +/// Defines the maximum value for rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_MAX_HEIGHT = (1< void rcIgnoreUnused(const T&) { } + +/// Swaps the values of the two parameters. +/// @param[in,out] a Value A +/// @param[in,out] b Value B +template inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; } + +/// Returns the minimum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The minimum of the two values. +template inline T rcMin(T a, T b) { return a < b ? a : b; } + +/// Returns the maximum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The maximum of the two values. +template inline T rcMax(T a, T b) { return a > b ? a : b; } + +/// Returns the absolute value. +/// @param[in] a The value. +/// @return The absolute value of the specified value. +template inline T rcAbs(T a) { return a < 0 ? -a : a; } + +/// Returns the square of the value. +/// @param[in] a The value. +/// @return The square of the value. +template inline T rcSqr(T a) { return a*a; } + +/// Clamps the value to the specified range. +/// @param[in] v The value to clamp. +/// @param[in] mn The minimum permitted return value. +/// @param[in] mx The maximum permitted return value. +/// @return The value, clamped to the specified range. +template inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); } + +/// Returns the square root of the value. +/// @param[in] x The value. +/// @return The square root of the vlaue. +float rcSqrt(float x); + +/// @} +/// @name Vector helper functions. +/// @{ + +/// Derives the cross product of two vectors. (@p v1 x @p v2) +/// @param[out] dest The cross product. [(x, y, z)] +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +inline void rcVcross(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[1]*v2[2] - v1[2]*v2[1]; + dest[1] = v1[2]*v2[0] - v1[0]*v2[2]; + dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/// Derives the dot product of two vectors. (@p v1 . @p v2) +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +/// @return The dot product. +inline float rcVdot(const float* v1, const float* v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s)) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] +/// @param[in] s The amount to scale @p v2 by before adding to @p v1. +inline void rcVmad(float* dest, const float* v1, const float* v2, const float s) +{ + dest[0] = v1[0]+v2[0]*s; + dest[1] = v1[1]+v2[1]*s; + dest[2] = v1[2]+v2[2]*s; +} + +/// Performs a vector addition. (@p v1 + @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to add to @p v1. [(x, y, z)] +inline void rcVadd(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[0]+v2[0]; + dest[1] = v1[1]+v2[1]; + dest[2] = v1[2]+v2[2]; +} + +/// Performs a vector subtraction. (@p v1 - @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector. [(x, y, z)] +/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)] +inline void rcVsub(float* dest, const float* v1, const float* v2) +{ + dest[0] = v1[0]-v2[0]; + dest[1] = v1[1]-v2[1]; + dest[2] = v1[2]-v2[2]; +} + +/// Selects the minimum value of each element from the specified vectors. +/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmin(float* mn, const float* v) +{ + mn[0] = rcMin(mn[0], v[0]); + mn[1] = rcMin(mn[1], v[1]); + mn[2] = rcMin(mn[2], v[2]); +} + +/// Selects the maximum value of each element from the specified vectors. +/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmax(float* mx, const float* v) +{ + mx[0] = rcMax(mx[0], v[0]); + mx[1] = rcMax(mx[1], v[1]); + mx[2] = rcMax(mx[2], v[2]); +} + +/// Performs a vector copy. +/// @param[out] dest The result. [(x, y, z)] +/// @param[in] v The vector to copy. [(x, y, z)] +inline void rcVcopy(float* dest, const float* v) +{ + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; +} + +/// Returns the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The distance between the two points. +inline float rcVdist(const float* v1, const float* v2) +{ + float dx = v2[0] - v1[0]; + float dy = v2[1] - v1[1]; + float dz = v2[2] - v1[2]; + return rcSqrt(dx*dx + dy*dy + dz*dz); +} + +/// Returns the square of the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The square of the distance between the two points. +inline float rcVdistSqr(const float* v1, const float* v2) +{ + float dx = v2[0] - v1[0]; + float dy = v2[1] - v1[1]; + float dz = v2[2] - v1[2]; + return dx*dx + dy*dy + dz*dz; +} + +/// Normalizes the vector. +/// @param[in,out] v The vector to normalize. [(x, y, z)] +inline void rcVnormalize(float* v) +{ + float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2])); + v[0] *= d; + v[1] *= d; + v[2] *= d; +} + +/// @} +/// @name Heightfield Functions +/// @see rcHeightfield +/// @{ + +/// Calculates the bounding box of an array of vertices. +/// @ingroup recast +/// @param[in] verts An array of vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices in the @p verts array. +/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax); + +/// Calculates the grid size based on the bounding box and grid cell size. +/// @ingroup recast +/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu] +/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx] +void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h); + +/// Initializes a new heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf The allocated heightfield to initialize. +/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx] +/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu] +/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu] +bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, + const float* bmin, const float* bmax, + float cs, float ch); + +/// Sets the area id of all triangles with a slope below the specified value +/// to #RC_WALKABLE_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. +/// [Limits: 0 <= value < 90] [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. +/// [Limits: 0 <= value < 90] [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Adds a span to the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf An initialized heightfield. +/// @param[in] x The width index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::width] +/// @param[in] y The height index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::height] +/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx] +/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx] +/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA) +/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx] +void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr); + +/// Rasterizes a triangle into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] v0 Triangle vertex 0 [(x, y, z)] +/// @param[in] v1 Triangle vertex 1 [(x, y, z)] +/// @param[in] v2 Triangle vertex 2 [(x, y, z)] +/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& solid, + const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const int* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const unsigned short* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes triangles into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in,out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid); + +/// Marks spans that are ledges as not-walkable. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, + const int walkableClimb, rcHeightfield& solid); + +/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid); + +/// Returns the number of spans contained in the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] hf An initialized heightfield. +/// @returns The number of spans in the heightfield. +int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf); + +/// @} +/// @name Compact Heightfield Functions +/// @see rcCompactHeightfield +/// @{ + +/// Builds a compact heightfield representing open space, from a heightfield representing solid space. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in] hf The heightfield to be compacted. +/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& hf, rcCompactHeightfield& chf); + +/// Erodes the walkable area within the heightfield by the specified radius. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx] +/// @param[in,out] chf The populated compact heightfield to erode. +/// @returns True if the operation completed successfully. +bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf); + +/// Applies a median filter to walkable area types (based on area id), removing noise. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf); + +/// Applies an area id to all spans within the specified bounding box. (AABB) +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] bmin The minimum of the bounding box. [(x, y, z)] +/// @param[in] bmax The maximum of the bounding box. [(x, y, z)] +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Applies the area id to the all spans within the specified convex polygon. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts] +/// @param[in] nverts The number of vertices in the polygon. +/// @param[in] hmin The height of the base of the polygon. +/// @param[in] hmax The height of the top of the polygon. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, + const float hmin, const float hmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Helper function to offset voncex polygons for rcMarkConvexPolyArea. +/// @ingroup recast +/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts] +/// @param[in] nverts The number of vertices in the polygon. +/// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value] +/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts. +/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts. +int rcOffsetPoly(const float* verts, const int nverts, const float offset, + float* outVerts, const int maxOutVerts); + +/// Applies the area id to all spans within the specified cylinder. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)] +/// @param[in] r The radius of the cylinder. +/// @param[in] h The height of the cylinder. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkCylinderArea(rcContext* ctx, const float* pos, + const float r, const float h, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Builds the distance field for the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf); + +/// Builds region data for the heightfield using watershed partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. +/// [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. +/// [Limit: >=0] [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + +/// Builds region data for the heightfield using simple monotone partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. +/// [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. +/// [Limit: >=0] [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + + +/// Sets the neighbor connection data for the specified direction. +/// @param[in] s The span to update. +/// @param[in] dir The direction to set. [Limits: 0 <= value < 4] +/// @param[in] i The index of the neighbor span. +inline void rcSetCon(rcCompactSpan& s, int dir, int i) +{ + const unsigned int shift = (unsigned int)dir*6; + unsigned int con = s.con; + s.con = (con & ~(0x3f << shift)) | (((unsigned int)i & 0x3f) << shift); +} + +/// Gets neighbor connection data for the specified direction. +/// @param[in] s The span to check. +/// @param[in] dir The direction to check. [Limits: 0 <= value < 4] +/// @return The neighbor connection data for the specified direction, +/// or #RC_NOT_CONNECTED if there is no connection. +inline int rcGetCon(const rcCompactSpan& s, int dir) +{ + const unsigned int shift = (unsigned int)dir*6; + return (s.con >> shift) & 0x3f; +} + +/// Gets the standard width (x-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The width offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetX(int dir) +{ + const int offset[4] = { -1, 0, 1, 0, }; + return offset[dir&0x03]; +} + +/// Gets the standard height (z-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The height offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetY(int dir) +{ + const int offset[4] = { 0, 1, 0, -1 }; + return offset[dir&0x03]; +} + +/// @} +/// @name Layer, Contour, Polymesh, and Detail Mesh Functions +/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail +/// @{ + +/// Builds a layer set from the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] +/// [Units: vx] +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[out] lset The resulting layer set. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int walkableHeight, + rcHeightfieldLayerSet& lset); + +/// Builds a contour set from the region outlines in the provided compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate +/// the original raw contour. [Limit: >=0] [Units: wu] +/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh. +/// [Limit: >=0] [Units: vx] +/// @param[out] cset The resulting contour set. (Must be pre-allocated.) +/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags) +/// @returns True if the operation completed successfully. +bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, + const float maxError, const int maxEdgeLen, + rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES); + +/// Builds a polygon mesh from the provided contours. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] cset A fully built contour set. +/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the +/// contour to polygon conversion process. [Limit: >= 3] +/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh); + +/// Merges multiple polygon meshes into a single mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of polygon meshes in the meshes array. +/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh); + +/// Builds a detail mesh from the provided polygon mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] mesh A fully built polygon mesh. +/// @param[in] chf The compact heightfield used to build the polygon mesh. +/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu] +/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from +/// heightfield data. [Limit: >=0] [Units: wu] +/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, + const float sampleDist, const float sampleMaxError, + rcPolyMeshDetail& dmesh); + +/// Copies the poly mesh data from src to dst. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] src The source mesh to copy from. +/// @param[out] dst The resulting detail mesh. (Must be pre-allocated, must be empty mesh.) +/// @returns True if the operation completed successfully. +bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst); + +/// Merges multiple detail meshes into a single detail mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of detail meshes in the meshes array. +/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); + +/// @} + +#endif // RECAST_H + +/////////////////////////////////////////////////////////////////////////// + +// Due to the large amount of detail documentation for this file, +// the content normally located at the end of the header file has been separated +// out to a file in /Docs/Extern. diff --git a/KREngine/3rdparty/recast/include/RecastAlloc.h b/KREngine/3rdparty/recast/include/RecastAlloc.h new file mode 100755 index 0000000..438be9e --- /dev/null +++ b/KREngine/3rdparty/recast/include/RecastAlloc.h @@ -0,0 +1,124 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#ifndef RECASTALLOC_H +#define RECASTALLOC_H + +/// Provides hint values to the memory allocator on how long the +/// memory is expected to be used. +enum rcAllocHint +{ + RC_ALLOC_PERM, ///< Memory will persist after a function call. + RC_ALLOC_TEMP ///< Memory used temporarily within a function. +}; + +/// A memory allocation function. +// @param[in] size The size, in bytes of memory, to allocate. +// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use. +// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +/// @see rcAllocSetCustom +typedef void* (rcAllocFunc)(int size, rcAllocHint hint); + +/// A memory deallocation function. +/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc. +/// @see rcAllocSetCustom +typedef void (rcFreeFunc)(void* ptr); + +/// Sets the base custom allocation functions to be used by Recast. +/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc +/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree +void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc); + +/// Allocates a memory block. +/// @param[in] size The size, in bytes of memory, to allocate. +/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use. +/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +/// @see rcFree +void* rcAlloc(int size, rcAllocHint hint); + +/// Deallocates a memory block. +/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc. +/// @see rcAlloc +void rcFree(void* ptr); + + +/// A simple dynamic array of integers. +class rcIntArray +{ + int* m_data; + int m_size, m_cap; + inline rcIntArray(const rcIntArray&); + inline rcIntArray& operator=(const rcIntArray&); +public: + + /// Constructs an instance with an initial array size of zero. + inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {} + + /// Constructs an instance initialized to the specified size. + /// @param[in] n The initial size of the integer array. + inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); } + inline ~rcIntArray() { rcFree(m_data); } + + /// Specifies the new size of the integer array. + /// @param[in] n The new size of the integer array. + void resize(int n); + + /// Push the specified integer onto the end of the array and increases the size by one. + /// @param[in] item The new value. + inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; } + + /// Returns the value at the end of the array and reduces the size by one. + /// @return The value at the end of the array. + inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline const int& operator[](int i) const { return m_data[i]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline int& operator[](int i) { return m_data[i]; } + + /// The current size of the integer array. + inline int size() const { return m_size; } +}; + +/// A simple helper class used to delete an array when it goes out of scope. +/// @note This class is rarely if ever used by the end user. +template class rcScopedDelete +{ + T* ptr; + inline T* operator=(T* p); +public: + + /// Constructs an instance with a null pointer. + inline rcScopedDelete() : ptr(0) {} + + /// Constructs an instance with the specified pointer. + /// @param[in] p An pointer to an allocated array. + inline rcScopedDelete(T* p) : ptr(p) {} + inline ~rcScopedDelete() { rcFree(ptr); } + + /// The root array pointer. + /// @return The root array pointer. + inline operator T*() { return ptr; } +}; + +#endif diff --git a/KREngine/3rdparty/recast/include/RecastAssert.h b/KREngine/3rdparty/recast/include/RecastAssert.h new file mode 100755 index 0000000..2aca0d9 --- /dev/null +++ b/KREngine/3rdparty/recast/include/RecastAssert.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#ifndef RECASTASSERT_H +#define RECASTASSERT_H + +// Note: This header file's only purpose is to include define assert. +// Feel free to change the file and include your own implementation instead. + +#ifdef NDEBUG +// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ +# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false) +#else +# include +# define rcAssert assert +#endif + +#endif // RECASTASSERT_H diff --git a/KREngine/3rdparty/recast/source/Recast.cpp b/KREngine/3rdparty/recast/source/Recast.cpp new file mode 100755 index 0000000..b9d8603 --- /dev/null +++ b/KREngine/3rdparty/recast/source/Recast.cpp @@ -0,0 +1,489 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + +float rcSqrt(float x) +{ + return sqrtf(x); +} + +/// @class rcContext +/// @par +/// +/// This class does not provide logging or timer functionality on its +/// own. Both must be provided by a concrete implementation +/// by overriding the protected member functions. Also, this class does not +/// provide an interface for extracting log messages. (Only adding them.) +/// So concrete implementations must provide one. +/// +/// If no logging or timers are required, just pass an instance of this +/// class through the Recast build process. +/// + +/// @par +/// +/// Example: +/// @code +/// // Where ctx is an instance of rcContext and filepath is a char array. +/// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath); +/// @endcode +void rcContext::log(const rcLogCategory category, const char* format, ...) +{ + if (!m_logEnabled) + return; + static const int MSG_SIZE = 512; + char msg[MSG_SIZE]; + va_list ap; + va_start(ap, format); + int len = vsnprintf(msg, MSG_SIZE, format, ap); + if (len >= MSG_SIZE) + { + len = MSG_SIZE-1; + msg[MSG_SIZE-1] = '\0'; + } + va_end(ap); + doLog(category, msg, len); +} + +rcHeightfield* rcAllocHeightfield() +{ + rcHeightfield* hf = (rcHeightfield*)rcAlloc(sizeof(rcHeightfield), RC_ALLOC_PERM); + memset(hf, 0, sizeof(rcHeightfield)); + return hf; +} + +void rcFreeHeightField(rcHeightfield* hf) +{ + if (!hf) return; + // Delete span array. + rcFree(hf->spans); + // Delete span pools. + while (hf->pools) + { + rcSpanPool* next = hf->pools->next; + rcFree(hf->pools); + hf->pools = next; + } + rcFree(hf); +} + +rcCompactHeightfield* rcAllocCompactHeightfield() +{ + rcCompactHeightfield* chf = (rcCompactHeightfield*)rcAlloc(sizeof(rcCompactHeightfield), RC_ALLOC_PERM); + memset(chf, 0, sizeof(rcCompactHeightfield)); + return chf; +} + +void rcFreeCompactHeightfield(rcCompactHeightfield* chf) +{ + if (!chf) return; + rcFree(chf->cells); + rcFree(chf->spans); + rcFree(chf->dist); + rcFree(chf->areas); + rcFree(chf); +} + + +rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet() +{ + rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM); + memset(lset, 0, sizeof(rcHeightfieldLayerSet)); + return lset; +} + +void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset) +{ + if (!lset) return; + for (int i = 0; i < lset->nlayers; ++i) + { + rcFree(lset->layers[i].heights); + rcFree(lset->layers[i].areas); + rcFree(lset->layers[i].cons); + } + rcFree(lset->layers); + rcFree(lset); +} + + +rcContourSet* rcAllocContourSet() +{ + rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM); + memset(cset, 0, sizeof(rcContourSet)); + return cset; +} + +void rcFreeContourSet(rcContourSet* cset) +{ + if (!cset) return; + for (int i = 0; i < cset->nconts; ++i) + { + rcFree(cset->conts[i].verts); + rcFree(cset->conts[i].rverts); + } + rcFree(cset->conts); + rcFree(cset); +} + +rcPolyMesh* rcAllocPolyMesh() +{ + rcPolyMesh* pmesh = (rcPolyMesh*)rcAlloc(sizeof(rcPolyMesh), RC_ALLOC_PERM); + memset(pmesh, 0, sizeof(rcPolyMesh)); + return pmesh; +} + +void rcFreePolyMesh(rcPolyMesh* pmesh) +{ + if (!pmesh) return; + rcFree(pmesh->verts); + rcFree(pmesh->polys); + rcFree(pmesh->regs); + rcFree(pmesh->flags); + rcFree(pmesh->areas); + rcFree(pmesh); +} + +rcPolyMeshDetail* rcAllocPolyMeshDetail() +{ + rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM); + memset(dmesh, 0, sizeof(rcPolyMeshDetail)); + return dmesh; +} + +void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh) +{ + if (!dmesh) return; + rcFree(dmesh->meshes); + rcFree(dmesh->verts); + rcFree(dmesh->tris); + rcFree(dmesh); +} + +void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax) +{ + // Calculate bounding box. + rcVcopy(bmin, verts); + rcVcopy(bmax, verts); + for (int i = 1; i < nv; ++i) + { + const float* v = &verts[i*3]; + rcVmin(bmin, v); + rcVmax(bmax, v); + } +} + +void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h) +{ + *w = (int)((bmax[0] - bmin[0])/cs+0.5f); + *h = (int)((bmax[2] - bmin[2])/cs+0.5f); +} + +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocHeightfield, rcHeightfield +bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, + const float* bmin, const float* bmax, + float cs, float ch) +{ + rcIgnoreUnused(ctx); + + hf.width = width; + hf.height = height; + rcVcopy(hf.bmin, bmin); + rcVcopy(hf.bmax, bmax); + hf.cs = cs; + hf.ch = ch; + hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM); + if (!hf.spans) + return false; + memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height); + return true; +} + +static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm) +{ + float e0[3], e1[3]; + rcVsub(e0, v1, v0); + rcVsub(e1, v2, v0); + rcVcross(norm, e0, e1); + rcVnormalize(norm); +} + +/// @par +/// +/// Only sets the aread id's for the walkable triangles. Does not alter the +/// area id's for unwalkable triangles. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles +void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, + const float* verts, int /*nv*/, + const int* tris, int nt, + unsigned char* areas) +{ + rcIgnoreUnused(ctx); + + const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); + + float norm[3]; + + for (int i = 0; i < nt; ++i) + { + const int* tri = &tris[i*3]; + calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm); + // Check if the face is walkable. + if (norm[1] > walkableThr) + areas[i] = RC_WALKABLE_AREA; + } +} + +/// @par +/// +/// Only sets the aread id's for the unwalkable triangles. Does not alter the +/// area id's for walkable triangles. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles +void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, + const float* verts, int /*nv*/, + const int* tris, int nt, + unsigned char* areas) +{ + rcIgnoreUnused(ctx); + + const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); + + float norm[3]; + + for (int i = 0; i < nt; ++i) + { + const int* tri = &tris[i*3]; + calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm); + // Check if the face is walkable. + if (norm[1] <= walkableThr) + areas[i] = RC_NULL_AREA; + } +} + +int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf) +{ + rcIgnoreUnused(ctx); + + const int w = hf.width; + const int h = hf.height; + int spanCount = 0; + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next) + { + if (s->area != RC_NULL_AREA) + spanCount++; + } + } + } + return spanCount; +} + +/// @par +/// +/// This is just the beginning of the process of fully building a compact heightfield. +/// Various filters may be applied applied, then the distance field and regions built. +/// E.g: #rcBuildDistanceField and #rcBuildRegions +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig +bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& hf, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD); + + const int w = hf.width; + const int h = hf.height; + const int spanCount = rcGetHeightFieldSpanCount(ctx, hf); + + // Fill in header. + chf.width = w; + chf.height = h; + chf.spanCount = spanCount; + chf.walkableHeight = walkableHeight; + chf.walkableClimb = walkableClimb; + chf.maxRegions = 0; + rcVcopy(chf.bmin, hf.bmin); + rcVcopy(chf.bmax, hf.bmax); + chf.bmax[1] += walkableHeight*hf.ch; + chf.cs = hf.cs; + chf.ch = hf.ch; + chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM); + if (!chf.cells) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h); + return false; + } + memset(chf.cells, 0, sizeof(rcCompactCell)*w*h); + chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM); + if (!chf.spans) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount); + return false; + } + memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount); + chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM); + if (!chf.areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount); + return false; + } + memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount); + + const int MAX_HEIGHT = 0xffff; + + // Fill in cells and spans. + int idx = 0; + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcSpan* s = hf.spans[x + y*w]; + // If there are no spans at this cell, just leave the data to index=0, count=0. + if (!s) continue; + rcCompactCell& c = chf.cells[x+y*w]; + c.index = idx; + c.count = 0; + while (s) + { + if (s->area != RC_NULL_AREA) + { + const int bot = (int)s->smax; + const int top = s->next ? (int)s->next->smin : MAX_HEIGHT; + chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff); + chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff); + chf.areas[idx] = s->area; + idx++; + c.count++; + } + s = s->next; + } + } + } + + // Find neighbour connections. + const int MAX_LAYERS = RC_NOT_CONNECTED-1; + int tooHighNeighbour = 0; + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + + for (int dir = 0; dir < 4; ++dir) + { + rcSetCon(s, dir, RC_NOT_CONNECTED); + const int nx = x + rcGetDirOffsetX(dir); + const int ny = y + rcGetDirOffsetY(dir); + // First check that the neighbour cell is in bounds. + if (nx < 0 || ny < 0 || nx >= w || ny >= h) + continue; + + // Iterate over all neighbour spans and check if any of the is + // accessible from current cell. + const rcCompactCell& nc = chf.cells[nx+ny*w]; + for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k) + { + const rcCompactSpan& ns = chf.spans[k]; + const int bot = rcMax(s.y, ns.y); + const int top = rcMin(s.y+s.h, ns.y+ns.h); + + // Check that the gap between the spans is walkable, + // and that the climb height between the gaps is not too high. + if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb) + { + // Mark direction as walkable. + const int lidx = k - (int)nc.index; + if (lidx < 0 || lidx > MAX_LAYERS) + { + tooHighNeighbour = rcMax(tooHighNeighbour, lidx); + continue; + } + rcSetCon(s, dir, lidx); + break; + } + } + + } + } + } + } + + if (tooHighNeighbour > MAX_LAYERS) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)", + tooHighNeighbour, MAX_LAYERS); + } + + ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD); + + return true; +} + +/* +static int getHeightfieldMemoryUsage(const rcHeightfield& hf) +{ + int size = 0; + size += sizeof(hf); + size += hf.width * hf.height * sizeof(rcSpan*); + + rcSpanPool* pool = hf.pools; + while (pool) + { + size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL; + pool = pool->next; + } + return size; +} + +static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf) +{ + int size = 0; + size += sizeof(rcCompactHeightfield); + size += sizeof(rcCompactSpan) * chf.spanCount; + size += sizeof(rcCompactCell) * chf.width * chf.height; + return size; +} +*/ \ No newline at end of file diff --git a/KREngine/3rdparty/recast/source/RecastAlloc.cpp b/KREngine/3rdparty/recast/source/RecastAlloc.cpp new file mode 100755 index 0000000..b5ec151 --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastAlloc.cpp @@ -0,0 +1,88 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#include +#include "RecastAlloc.h" + +static void *rcAllocDefault(int size, rcAllocHint) +{ + return malloc(size); +} + +static void rcFreeDefault(void *ptr) +{ + free(ptr); +} + +static rcAllocFunc* sRecastAllocFunc = rcAllocDefault; +static rcFreeFunc* sRecastFreeFunc = rcFreeDefault; + +/// @see rcAlloc, rcFree +void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc) +{ + sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault; + sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault; +} + +/// @see rcAllocSetCustom +void* rcAlloc(int size, rcAllocHint hint) +{ + return sRecastAllocFunc(size, hint); +} + +/// @par +/// +/// @warning This function leaves the value of @p ptr unchanged. So it still +/// points to the same (now invalid) location, and not to null. +/// +/// @see rcAllocSetCustom +void rcFree(void* ptr) +{ + if (ptr) + sRecastFreeFunc(ptr); +} + +/// @class rcIntArray +/// +/// While it is possible to pre-allocate a specific array size during +/// construction or by using the #resize method, certain methods will +/// automatically resize the array as needed. +/// +/// @warning The array memory is not initialized to zero when the size is +/// manually set during construction or when using #resize. + +/// @par +/// +/// Using this method ensures the array is at least large enough to hold +/// the specified number of elements. This can improve performance by +/// avoiding auto-resizing during use. +void rcIntArray::resize(int n) +{ + if (n > m_cap) + { + if (!m_cap) m_cap = n; + while (m_cap < n) m_cap *= 2; + int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP); + if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int)); + rcFree(m_data); + m_data = newData; + } + m_size = n; +} + diff --git a/KREngine/3rdparty/recast/source/RecastArea.cpp b/KREngine/3rdparty/recast/source/RecastArea.cpp new file mode 100755 index 0000000..1a338cd --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastArea.cpp @@ -0,0 +1,602 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + +/// @par +/// +/// Basically, any spans that are closer to a boundary or obstruction than the specified radius +/// are marked as unwalkable. +/// +/// This method is usually called immediately after the heightfield has been built. +/// +/// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius +bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + const int w = chf.width; + const int h = chf.height; + + ctx->startTimer(RC_TIMER_ERODE_AREA); + + unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!dist) + { + ctx->log(RC_LOG_ERROR, "erodeWalkableArea: Out of memory 'dist' (%d).", chf.spanCount); + return false; + } + + // Init distance. + memset(dist, 0xff, sizeof(unsigned char)*chf.spanCount); + + // Mark boundary cells. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (chf.areas[i] == RC_NULL_AREA) + { + dist[i] = 0; + } + else + { + const rcCompactSpan& s = chf.spans[i]; + int nc = 0; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int nx = x + rcGetDirOffsetX(dir); + const int ny = y + rcGetDirOffsetY(dir); + const int nidx = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir); + if (chf.areas[nidx] != RC_NULL_AREA) + { + nc++; + } + } + } + // At least one missing neighbour. + if (nc != 4) + dist[i] = 0; + } + } + } + } + + unsigned char nd; + + // Pass 1 + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + // (-1,0) + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (-1,-1) + if (rcGetCon(as, 3) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(3); + const int aay = ay + rcGetDirOffsetY(3); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + if (rcGetCon(s, 3) != RC_NOT_CONNECTED) + { + // (0,-1) + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (1,-1) + if (rcGetCon(as, 2) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(2); + const int aay = ay + rcGetDirOffsetY(2); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + } + } + } + + // Pass 2 + for (int y = h-1; y >= 0; --y) + { + for (int x = w-1; x >= 0; --x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 2) != RC_NOT_CONNECTED) + { + // (1,0) + const int ax = x + rcGetDirOffsetX(2); + const int ay = y + rcGetDirOffsetY(2); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (1,1) + if (rcGetCon(as, 1) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(1); + const int aay = ay + rcGetDirOffsetY(1); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + if (rcGetCon(s, 1) != RC_NOT_CONNECTED) + { + // (0,1) + const int ax = x + rcGetDirOffsetX(1); + const int ay = y + rcGetDirOffsetY(1); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (-1,1) + if (rcGetCon(as, 0) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(0); + const int aay = ay + rcGetDirOffsetY(0); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + } + } + } + + const unsigned char thr = (unsigned char)(radius*2); + for (int i = 0; i < chf.spanCount; ++i) + if (dist[i] < thr) + chf.areas[i] = RC_NULL_AREA; + + rcFree(dist); + + ctx->stopTimer(RC_TIMER_ERODE_AREA); + + return true; +} + +static void insertSort(unsigned char* a, const int n) +{ + int i, j; + for (i = 1; i < n; i++) + { + const unsigned char value = a[i]; + for (j = i - 1; j >= 0 && a[j] > value; j--) + a[j+1] = a[j]; + a[j+1] = value; + } +} + +/// @par +/// +/// This filter is usually applied after applying area id's using functions +/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea. +/// +/// @see rcCompactHeightfield +bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + const int w = chf.width; + const int h = chf.height; + + ctx->startTimer(RC_TIMER_MEDIAN_AREA); + + unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!areas) + { + ctx->log(RC_LOG_ERROR, "medianFilterWalkableArea: Out of memory 'areas' (%d).", chf.spanCount); + return false; + } + + // Init distance. + memset(areas, 0xff, sizeof(unsigned char)*chf.spanCount); + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) + { + areas[i] = chf.areas[i]; + continue; + } + + unsigned char nei[9]; + for (int j = 0; j < 9; ++j) + nei[j] = chf.areas[i]; + + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + if (chf.areas[ai] != RC_NULL_AREA) + nei[dir*2+0] = chf.areas[ai]; + + const rcCompactSpan& as = chf.spans[ai]; + const int dir2 = (dir+1) & 0x3; + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dir2); + const int ay2 = ay + rcGetDirOffsetY(dir2); + const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); + if (chf.areas[ai2] != RC_NULL_AREA) + nei[dir*2+1] = chf.areas[ai2]; + } + } + } + insertSort(nei, 9); + areas[i] = nei[4]; + } + } + } + + memcpy(chf.areas, areas, sizeof(unsigned char)*chf.spanCount); + + rcFree(areas); + + ctx->stopTimer(RC_TIMER_MEDIAN_AREA); + + return true; +} + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_BOX_AREA); + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + if ((int)s.y >= miny && (int)s.y <= maxy) + { + if (chf.areas[i] != RC_NULL_AREA) + chf.areas[i] = areaId; + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_BOX_AREA); + +} + + +static int pointInPoly(int nvert, const float* verts, const float* p) +{ + int i, j, c = 0; + for (i = 0, j = nvert-1; i < nvert; j = i++) + { + const float* vi = &verts[i*3]; + const float* vj = &verts[j*3]; + if (((vi[2] > p[2]) != (vj[2] > p[2])) && + (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) ) + c = !c; + } + return c; +} + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// The y-values of the polygon vertices are ignored. So the polygon is effectively +/// projected onto the xz-plane at @p hmin, then extruded to @p hmax. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, + const float hmin, const float hmax, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_CONVEXPOLY_AREA); + + float bmin[3], bmax[3]; + rcVcopy(bmin, verts); + rcVcopy(bmax, verts); + for (int i = 1; i < nverts; ++i) + { + rcVmin(bmin, &verts[i*3]); + rcVmax(bmax, &verts[i*3]); + } + bmin[1] = hmin; + bmax[1] = hmax; + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + + // TODO: Optimize. + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) + continue; + if ((int)s.y >= miny && (int)s.y <= maxy) + { + float p[3]; + p[0] = chf.bmin[0] + (x+0.5f)*chf.cs; + p[1] = 0; + p[2] = chf.bmin[2] + (z+0.5f)*chf.cs; + + if (pointInPoly(nverts, verts, p)) + { + chf.areas[i] = areaId; + } + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA); +} + +int rcOffsetPoly(const float* verts, const int nverts, const float offset, + float* outVerts, const int maxOutVerts) +{ + const float MITER_LIMIT = 1.20f; + + int n = 0; + + for (int i = 0; i < nverts; i++) + { + const int a = (i+nverts-1) % nverts; + const int b = i; + const int c = (i+1) % nverts; + const float* va = &verts[a*3]; + const float* vb = &verts[b*3]; + const float* vc = &verts[c*3]; + float dx0 = vb[0] - va[0]; + float dy0 = vb[2] - va[2]; + float d0 = dx0*dx0 + dy0*dy0; + if (d0 > 1e-6f) + { + d0 = 1.0f/rcSqrt(d0); + dx0 *= d0; + dy0 *= d0; + } + float dx1 = vc[0] - vb[0]; + float dy1 = vc[2] - vb[2]; + float d1 = dx1*dx1 + dy1*dy1; + if (d1 > 1e-6f) + { + d1 = 1.0f/rcSqrt(d1); + dx1 *= d1; + dy1 *= d1; + } + const float dlx0 = -dy0; + const float dly0 = dx0; + const float dlx1 = -dy1; + const float dly1 = dx1; + float cross = dx1*dy0 - dx0*dy1; + float dmx = (dlx0 + dlx1) * 0.5f; + float dmy = (dly0 + dly1) * 0.5f; + float dmr2 = dmx*dmx + dmy*dmy; + bool bevel = dmr2 * MITER_LIMIT*MITER_LIMIT < 1.0f; + if (dmr2 > 1e-6f) + { + const float scale = 1.0f / dmr2; + dmx *= scale; + dmy *= scale; + } + + if (bevel && cross < 0.0f) + { + if (n+2 >= maxOutVerts) + return 0; + float d = (1.0f - (dx0*dx1 + dy0*dy1))*0.5f; + outVerts[n*3+0] = vb[0] + (-dlx0+dx0*d)*offset; + outVerts[n*3+1] = vb[1]; + outVerts[n*3+2] = vb[2] + (-dly0+dy0*d)*offset; + n++; + outVerts[n*3+0] = vb[0] + (-dlx1-dx1*d)*offset; + outVerts[n*3+1] = vb[1]; + outVerts[n*3+2] = vb[2] + (-dly1-dy1*d)*offset; + n++; + } + else + { + if (n+1 >= maxOutVerts) + return 0; + outVerts[n*3+0] = vb[0] - dmx*offset; + outVerts[n*3+1] = vb[1]; + outVerts[n*3+2] = vb[2] - dmy*offset; + n++; + } + } + + return n; +} + + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkCylinderArea(rcContext* ctx, const float* pos, + const float r, const float h, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA); + + float bmin[3], bmax[3]; + bmin[0] = pos[0] - r; + bmin[1] = pos[1]; + bmin[2] = pos[2] - r; + bmax[0] = pos[0] + r; + bmax[1] = pos[1] + h; + bmax[2] = pos[2] + r; + const float r2 = r*r; + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + + if (chf.areas[i] == RC_NULL_AREA) + continue; + + if ((int)s.y >= miny && (int)s.y <= maxy) + { + const float sx = chf.bmin[0] + (x+0.5f)*chf.cs; + const float sz = chf.bmin[2] + (z+0.5f)*chf.cs; + const float dx = sx - pos[0]; + const float dz = sz - pos[2]; + + if (dx*dx + dz*dz < r2) + { + chf.areas[i] = areaId; + } + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA); +} diff --git a/KREngine/3rdparty/recast/source/RecastContour.cpp b/KREngine/3rdparty/recast/source/RecastContour.cpp new file mode 100755 index 0000000..5c324bc --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastContour.cpp @@ -0,0 +1,851 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#define _USE_MATH_DEFINES +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + + +static int getCornerHeight(int x, int y, int i, int dir, + const rcCompactHeightfield& chf, + bool& isBorderVertex) +{ + const rcCompactSpan& s = chf.spans[i]; + int ch = (int)s.y; + int dirp = (dir+1) & 0x3; + + unsigned int regs[4] = {0,0,0,0}; + + // Combine region and area codes in order to prevent + // border vertices which are in between two areas to be removed. + regs[0] = chf.spans[i].reg | (chf.areas[i] << 16); + + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); + const rcCompactSpan& as = chf.spans[ai]; + ch = rcMax(ch, (int)as.y); + regs[1] = chf.spans[ai].reg | (chf.areas[ai] << 16); + if (rcGetCon(as, dirp) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dirp); + const int ay2 = ay + rcGetDirOffsetY(dirp); + const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dirp); + const rcCompactSpan& as2 = chf.spans[ai2]; + ch = rcMax(ch, (int)as2.y); + regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); + } + } + if (rcGetCon(s, dirp) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dirp); + const int ay = y + rcGetDirOffsetY(dirp); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dirp); + const rcCompactSpan& as = chf.spans[ai]; + ch = rcMax(ch, (int)as.y); + regs[3] = chf.spans[ai].reg | (chf.areas[ai] << 16); + if (rcGetCon(as, dir) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dir); + const int ay2 = ay + rcGetDirOffsetY(dir); + const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dir); + const rcCompactSpan& as2 = chf.spans[ai2]; + ch = rcMax(ch, (int)as2.y); + regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); + } + } + + // Check if the vertex is special edge vertex, these vertices will be removed later. + for (int j = 0; j < 4; ++j) + { + const int a = j; + const int b = (j+1) & 0x3; + const int c = (j+2) & 0x3; + const int d = (j+3) & 0x3; + + // The vertex is a border vertex there are two same exterior cells in a row, + // followed by two interior cells and none of the regions are out of bounds. + const bool twoSameExts = (regs[a] & regs[b] & RC_BORDER_REG) != 0 && regs[a] == regs[b]; + const bool twoInts = ((regs[c] | regs[d]) & RC_BORDER_REG) == 0; + const bool intsSameArea = (regs[c]>>16) == (regs[d]>>16); + const bool noZeros = regs[a] != 0 && regs[b] != 0 && regs[c] != 0 && regs[d] != 0; + if (twoSameExts && twoInts && intsSameArea && noZeros) + { + isBorderVertex = true; + break; + } + } + + return ch; +} + +static void walkContour(int x, int y, int i, + rcCompactHeightfield& chf, + unsigned char* flags, rcIntArray& points) +{ + // Choose the first non-connected edge + unsigned char dir = 0; + while ((flags[i] & (1 << dir)) == 0) + dir++; + + unsigned char startDir = dir; + int starti = i; + + const unsigned char area = chf.areas[i]; + + int iter = 0; + while (++iter < 40000) + { + if (flags[i] & (1 << dir)) + { + // Choose the edge corner + bool isBorderVertex = false; + bool isAreaBorder = false; + int px = x; + int py = getCornerHeight(x, y, i, dir, chf, isBorderVertex); + int pz = y; + switch(dir) + { + case 0: pz++; break; + case 1: px++; pz++; break; + case 2: px++; break; + } + int r = 0; + const rcCompactSpan& s = chf.spans[i]; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); + r = (int)chf.spans[ai].reg; + if (area != chf.areas[ai]) + isAreaBorder = true; + } + if (isBorderVertex) + r |= RC_BORDER_VERTEX; + if (isAreaBorder) + r |= RC_AREA_BORDER; + points.push(px); + points.push(py); + points.push(pz); + points.push(r); + + flags[i] &= ~(1 << dir); // Remove visited edges + dir = (dir+1) & 0x3; // Rotate CW + } + else + { + int ni = -1; + const int nx = x + rcGetDirOffsetX(dir); + const int ny = y + rcGetDirOffsetY(dir); + const rcCompactSpan& s = chf.spans[i]; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const rcCompactCell& nc = chf.cells[nx+ny*chf.width]; + ni = (int)nc.index + rcGetCon(s, dir); + } + if (ni == -1) + { + // Should not happen. + return; + } + x = nx; + y = ny; + i = ni; + dir = (dir+3) & 0x3; // Rotate CCW + } + + if (starti == i && startDir == dir) + { + break; + } + } +} + +static float distancePtSeg(const int x, const int z, + const int px, const int pz, + const int qx, const int qz) +{ +/* float pqx = (float)(qx - px); + float pqy = (float)(qy - py); + float pqz = (float)(qz - pz); + float dx = (float)(x - px); + float dy = (float)(y - py); + float dz = (float)(z - pz); + float d = pqx*pqx + pqy*pqy + pqz*pqz; + float t = pqx*dx + pqy*dy + pqz*dz; + if (d > 0) + t /= d; + if (t < 0) + t = 0; + else if (t > 1) + t = 1; + + dx = px + t*pqx - x; + dy = py + t*pqy - y; + dz = pz + t*pqz - z; + + return dx*dx + dy*dy + dz*dz;*/ + + float pqx = (float)(qx - px); + float pqz = (float)(qz - pz); + float dx = (float)(x - px); + float dz = (float)(z - pz); + float d = pqx*pqx + pqz*pqz; + float t = pqx*dx + pqz*dz; + if (d > 0) + t /= d; + if (t < 0) + t = 0; + else if (t > 1) + t = 1; + + dx = px + t*pqx - x; + dz = pz + t*pqz - z; + + return dx*dx + dz*dz; +} + +static void simplifyContour(rcIntArray& points, rcIntArray& simplified, + const float maxError, const int maxEdgeLen, const int buildFlags) +{ + // Add initial points. + bool hasConnections = false; + for (int i = 0; i < points.size(); i += 4) + { + if ((points[i+3] & RC_CONTOUR_REG_MASK) != 0) + { + hasConnections = true; + break; + } + } + + if (hasConnections) + { + // The contour has some portals to other regions. + // Add a new point to every location where the region changes. + for (int i = 0, ni = points.size()/4; i < ni; ++i) + { + int ii = (i+1) % ni; + const bool differentRegs = (points[i*4+3] & RC_CONTOUR_REG_MASK) != (points[ii*4+3] & RC_CONTOUR_REG_MASK); + const bool areaBorders = (points[i*4+3] & RC_AREA_BORDER) != (points[ii*4+3] & RC_AREA_BORDER); + if (differentRegs || areaBorders) + { + simplified.push(points[i*4+0]); + simplified.push(points[i*4+1]); + simplified.push(points[i*4+2]); + simplified.push(i); + } + } + } + + if (simplified.size() == 0) + { + // If there is no connections at all, + // create some initial points for the simplification process. + // Find lower-left and upper-right vertices of the contour. + int llx = points[0]; + int lly = points[1]; + int llz = points[2]; + int lli = 0; + int urx = points[0]; + int ury = points[1]; + int urz = points[2]; + int uri = 0; + for (int i = 0; i < points.size(); i += 4) + { + int x = points[i+0]; + int y = points[i+1]; + int z = points[i+2]; + if (x < llx || (x == llx && z < llz)) + { + llx = x; + lly = y; + llz = z; + lli = i/4; + } + if (x > urx || (x == urx && z > urz)) + { + urx = x; + ury = y; + urz = z; + uri = i/4; + } + } + simplified.push(llx); + simplified.push(lly); + simplified.push(llz); + simplified.push(lli); + + simplified.push(urx); + simplified.push(ury); + simplified.push(urz); + simplified.push(uri); + } + + // Add points until all raw points are within + // error tolerance to the simplified shape. + const int pn = points.size()/4; + for (int i = 0; i < simplified.size()/4; ) + { + int ii = (i+1) % (simplified.size()/4); + + const int ax = simplified[i*4+0]; + const int az = simplified[i*4+2]; + const int ai = simplified[i*4+3]; + + const int bx = simplified[ii*4+0]; + const int bz = simplified[ii*4+2]; + const int bi = simplified[ii*4+3]; + + // Find maximum deviation from the segment. + float maxd = 0; + int maxi = -1; + int ci, cinc, endi; + + // Traverse the segment in lexilogical order so that the + // max deviation is calculated similarly when traversing + // opposite segments. + if (bx > ax || (bx == ax && bz > az)) + { + cinc = 1; + ci = (ai+cinc) % pn; + endi = bi; + } + else + { + cinc = pn-1; + ci = (bi+cinc) % pn; + endi = ai; + } + + // Tessellate only outer edges or edges between areas. + if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 || + (points[ci*4+3] & RC_AREA_BORDER)) + { + while (ci != endi) + { + float d = distancePtSeg(points[ci*4+0], points[ci*4+2], ax, az, bx, bz); + if (d > maxd) + { + maxd = d; + maxi = ci; + } + ci = (ci+cinc) % pn; + } + } + + + // If the max deviation is larger than accepted error, + // add new point, else continue to next segment. + if (maxi != -1 && maxd > (maxError*maxError)) + { + // Add space for the new point. + simplified.resize(simplified.size()+4); + const int n = simplified.size()/4; + for (int j = n-1; j > i; --j) + { + simplified[j*4+0] = simplified[(j-1)*4+0]; + simplified[j*4+1] = simplified[(j-1)*4+1]; + simplified[j*4+2] = simplified[(j-1)*4+2]; + simplified[j*4+3] = simplified[(j-1)*4+3]; + } + // Add the point. + simplified[(i+1)*4+0] = points[maxi*4+0]; + simplified[(i+1)*4+1] = points[maxi*4+1]; + simplified[(i+1)*4+2] = points[maxi*4+2]; + simplified[(i+1)*4+3] = maxi; + } + else + { + ++i; + } + } + + // Split too long edges. + if (maxEdgeLen > 0 && (buildFlags & (RC_CONTOUR_TESS_WALL_EDGES|RC_CONTOUR_TESS_AREA_EDGES)) != 0) + { + for (int i = 0; i < simplified.size()/4; ) + { + const int ii = (i+1) % (simplified.size()/4); + + const int ax = simplified[i*4+0]; + const int az = simplified[i*4+2]; + const int ai = simplified[i*4+3]; + + const int bx = simplified[ii*4+0]; + const int bz = simplified[ii*4+2]; + const int bi = simplified[ii*4+3]; + + // Find maximum deviation from the segment. + int maxi = -1; + int ci = (ai+1) % pn; + + // Tessellate only outer edges or edges between areas. + bool tess = false; + // Wall edges. + if ((buildFlags & RC_CONTOUR_TESS_WALL_EDGES) && (points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0) + tess = true; + // Edges between areas. + if ((buildFlags & RC_CONTOUR_TESS_AREA_EDGES) && (points[ci*4+3] & RC_AREA_BORDER)) + tess = true; + + if (tess) + { + int dx = bx - ax; + int dz = bz - az; + if (dx*dx + dz*dz > maxEdgeLen*maxEdgeLen) + { + // Round based on the segments in lexilogical order so that the + // max tesselation is consistent regardles in which direction + // segments are traversed. + const int n = bi < ai ? (bi+pn - ai) : (bi - ai); + if (n > 1) + { + if (bx > ax || (bx == ax && bz > az)) + maxi = (ai + n/2) % pn; + else + maxi = (ai + (n+1)/2) % pn; + } + } + } + + // If the max deviation is larger than accepted error, + // add new point, else continue to next segment. + if (maxi != -1) + { + // Add space for the new point. + simplified.resize(simplified.size()+4); + const int n = simplified.size()/4; + for (int j = n-1; j > i; --j) + { + simplified[j*4+0] = simplified[(j-1)*4+0]; + simplified[j*4+1] = simplified[(j-1)*4+1]; + simplified[j*4+2] = simplified[(j-1)*4+2]; + simplified[j*4+3] = simplified[(j-1)*4+3]; + } + // Add the point. + simplified[(i+1)*4+0] = points[maxi*4+0]; + simplified[(i+1)*4+1] = points[maxi*4+1]; + simplified[(i+1)*4+2] = points[maxi*4+2]; + simplified[(i+1)*4+3] = maxi; + } + else + { + ++i; + } + } + } + + for (int i = 0; i < simplified.size()/4; ++i) + { + // The edge vertex flag is take from the current raw point, + // and the neighbour region is take from the next raw point. + const int ai = (simplified[i*4+3]+1) % pn; + const int bi = simplified[i*4+3]; + simplified[i*4+3] = (points[ai*4+3] & (RC_CONTOUR_REG_MASK|RC_AREA_BORDER)) | (points[bi*4+3] & RC_BORDER_VERTEX); + } + +} + +static void removeDegenerateSegments(rcIntArray& simplified) +{ + // Remove adjacent vertices which are equal on xz-plane, + // or else the triangulator will get confused. + for (int i = 0; i < simplified.size()/4; ++i) + { + int ni = i+1; + if (ni >= (simplified.size()/4)) + ni = 0; + + if (simplified[i*4+0] == simplified[ni*4+0] && + simplified[i*4+2] == simplified[ni*4+2]) + { + // Degenerate segment, remove. + for (int j = i; j < simplified.size()/4-1; ++j) + { + simplified[j*4+0] = simplified[(j+1)*4+0]; + simplified[j*4+1] = simplified[(j+1)*4+1]; + simplified[j*4+2] = simplified[(j+1)*4+2]; + simplified[j*4+3] = simplified[(j+1)*4+3]; + } + simplified.resize(simplified.size()-4); + } + } +} + +static int calcAreaOfPolygon2D(const int* verts, const int nverts) +{ + int area = 0; + for (int i = 0, j = nverts-1; i < nverts; j=i++) + { + const int* vi = &verts[i*4]; + const int* vj = &verts[j*4]; + area += vi[0] * vj[2] - vj[0] * vi[2]; + } + return (area+1) / 2; +} + +inline bool ileft(const int* a, const int* b, const int* c) +{ + return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]) <= 0; +} + +static void getClosestIndices(const int* vertsa, const int nvertsa, + const int* vertsb, const int nvertsb, + int& ia, int& ib) +{ + int closestDist = 0xfffffff; + ia = -1, ib = -1; + for (int i = 0; i < nvertsa; ++i) + { + const int in = (i+1) % nvertsa; + const int ip = (i+nvertsa-1) % nvertsa; + const int* va = &vertsa[i*4]; + const int* van = &vertsa[in*4]; + const int* vap = &vertsa[ip*4]; + + for (int j = 0; j < nvertsb; ++j) + { + const int* vb = &vertsb[j*4]; + // vb must be "infront" of va. + if (ileft(vap,va,vb) && ileft(va,van,vb)) + { + const int dx = vb[0] - va[0]; + const int dz = vb[2] - va[2]; + const int d = dx*dx + dz*dz; + if (d < closestDist) + { + ia = i; + ib = j; + closestDist = d; + } + } + } + } +} + +static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib) +{ + const int maxVerts = ca.nverts + cb.nverts + 2; + int* verts = (int*)rcAlloc(sizeof(int)*maxVerts*4, RC_ALLOC_PERM); + if (!verts) + return false; + + int nv = 0; + + // Copy contour A. + for (int i = 0; i <= ca.nverts; ++i) + { + int* dst = &verts[nv*4]; + const int* src = &ca.verts[((ia+i)%ca.nverts)*4]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + nv++; + } + + // Copy contour B + for (int i = 0; i <= cb.nverts; ++i) + { + int* dst = &verts[nv*4]; + const int* src = &cb.verts[((ib+i)%cb.nverts)*4]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + nv++; + } + + rcFree(ca.verts); + ca.verts = verts; + ca.nverts = nv; + + rcFree(cb.verts); + cb.verts = 0; + cb.nverts = 0; + + return true; +} + +/// @par +/// +/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen +/// parameters control how closely the simplified contours will match the raw contours. +/// +/// Simplified contours are generated such that the vertices for portals between areas match up. +/// (They are considered mandatory vertices.) +/// +/// Setting @p maxEdgeLength to zero will disabled the edge length feature. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig +bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, + const float maxError, const int maxEdgeLen, + rcContourSet& cset, const int buildFlags) +{ + rcAssert(ctx); + + const int w = chf.width; + const int h = chf.height; + const int borderSize = chf.borderSize; + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS); + + rcVcopy(cset.bmin, chf.bmin); + rcVcopy(cset.bmax, chf.bmax); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + const float pad = borderSize*chf.cs; + cset.bmin[0] += pad; + cset.bmin[2] += pad; + cset.bmax[0] -= pad; + cset.bmax[2] -= pad; + } + cset.cs = chf.cs; + cset.ch = chf.ch; + cset.width = chf.width - chf.borderSize*2; + cset.height = chf.height - chf.borderSize*2; + cset.borderSize = chf.borderSize; + + int maxContours = rcMax((int)chf.maxRegions, 8); + cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM); + if (!cset.conts) + return false; + cset.nconts = 0; + + rcScopedDelete flags = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!flags) + { + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount); + return false; + } + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + + // Mark boundaries. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + unsigned char res = 0; + const rcCompactSpan& s = chf.spans[i]; + if (!chf.spans[i].reg || (chf.spans[i].reg & RC_BORDER_REG)) + { + flags[i] = 0; + continue; + } + for (int dir = 0; dir < 4; ++dir) + { + unsigned short r = 0; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + r = chf.spans[ai].reg; + } + if (r == chf.spans[i].reg) + res |= (1 << dir); + } + flags[i] = res ^ 0xf; // Inverse, mark non connected edges. + } + } + } + + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + + rcIntArray verts(256); + rcIntArray simplified(64); + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (flags[i] == 0 || flags[i] == 0xf) + { + flags[i] = 0; + continue; + } + const unsigned short reg = chf.spans[i].reg; + if (!reg || (reg & RC_BORDER_REG)) + continue; + const unsigned char area = chf.areas[i]; + + verts.resize(0); + simplified.resize(0); + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + walkContour(x, y, i, chf, flags, verts); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags); + removeDegenerateSegments(simplified); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + + + // Store region->contour remap info. + // Create contour. + if (simplified.size()/4 >= 3) + { + if (cset.nconts >= maxContours) + { + // Allocate more contours. + // This can happen when there are tiny holes in the heightfield. + const int oldMax = maxContours; + maxContours *= 2; + rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM); + for (int j = 0; j < cset.nconts; ++j) + { + newConts[j] = cset.conts[j]; + // Reset source pointers to prevent data deletion. + cset.conts[j].verts = 0; + cset.conts[j].rverts = 0; + } + rcFree(cset.conts); + cset.conts = newConts; + + ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours); + } + + rcContour* cont = &cset.conts[cset.nconts++]; + + cont->nverts = simplified.size()/4; + cont->verts = (int*)rcAlloc(sizeof(int)*cont->nverts*4, RC_ALLOC_PERM); + if (!cont->verts) + { + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'verts' (%d).", cont->nverts); + return false; + } + memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + for (int j = 0; j < cont->nverts; ++j) + { + int* v = &cont->verts[j*4]; + v[0] -= borderSize; + v[2] -= borderSize; + } + } + + cont->nrverts = verts.size()/4; + cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM); + if (!cont->rverts) + { + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'rverts' (%d).", cont->nrverts); + return false; + } + memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + for (int j = 0; j < cont->nrverts; ++j) + { + int* v = &cont->rverts[j*4]; + v[0] -= borderSize; + v[2] -= borderSize; + } + } + +/* cont->cx = cont->cy = cont->cz = 0; + for (int i = 0; i < cont->nverts; ++i) + { + cont->cx += cont->verts[i*4+0]; + cont->cy += cont->verts[i*4+1]; + cont->cz += cont->verts[i*4+2]; + } + cont->cx /= cont->nverts; + cont->cy /= cont->nverts; + cont->cz /= cont->nverts;*/ + + cont->reg = reg; + cont->area = area; + } + } + } + } + + // Check and merge droppings. + // Sometimes the previous algorithms can fail and create several contours + // per area. This pass will try to merge the holes into the main region. + for (int i = 0; i < cset.nconts; ++i) + { + rcContour& cont = cset.conts[i]; + // Check if the contour is would backwards. + if (calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0) + { + // Find another contour which has the same region ID. + int mergeIdx = -1; + for (int j = 0; j < cset.nconts; ++j) + { + if (i == j) continue; + if (cset.conts[j].nverts && cset.conts[j].reg == cont.reg) + { + // Make sure the polygon is correctly oriented. + if (calcAreaOfPolygon2D(cset.conts[j].verts, cset.conts[j].nverts)) + { + mergeIdx = j; + break; + } + } + } + if (mergeIdx == -1) + { + ctx->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i); + } + else + { + rcContour& mcont = cset.conts[mergeIdx]; + // Merge by closest points. + int ia = 0, ib = 0; + getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib); + if (ia == -1 || ib == -1) + { + ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx); + continue; + } + if (!mergeContours(mcont, cont, ia, ib)) + { + ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx); + continue; + } + } + } + } + + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS); + + return true; +} diff --git a/KREngine/3rdparty/recast/source/RecastFilter.cpp b/KREngine/3rdparty/recast/source/RecastFilter.cpp new file mode 100755 index 0000000..bf985c3 --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastFilter.cpp @@ -0,0 +1,207 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#define _USE_MATH_DEFINES +#include +#include +#include "Recast.h" +#include "RecastAssert.h" + +/// @par +/// +/// Allows the formation of walkable regions that will flow over low lying +/// objects such as curbs, and up structures such as stairways. +/// +/// Two neighboring spans are walkable if: rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb +/// +/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call +/// #rcFilterLedgeSpans after calling this filter. +/// +/// @see rcHeightfield, rcConfig +void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_LOW_OBSTACLES); + + const int w = solid.width; + const int h = solid.height; + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + rcSpan* ps = 0; + bool previousWalkable = false; + unsigned char previousArea = RC_NULL_AREA; + + for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next) + { + const bool walkable = s->area != RC_NULL_AREA; + // If current span is not walkable, but there is walkable + // span just below it, mark the span above it walkable too. + if (!walkable && previousWalkable) + { + if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb) + s->area = previousArea; + } + // Copy walkable flag so that it cannot propagate + // past multiple non-walkable objects. + previousWalkable = walkable; + previousArea = s->area; + } + } + } + + ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES); +} + +/// @par +/// +/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb +/// from the current span's maximum. +/// This method removes the impact of the overestimation of conservative voxelization +/// so the resulting mesh will not have regions hanging in the air over ledges. +/// +/// A span is a ledge if: rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb +/// +/// @see rcHeightfield, rcConfig +void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& solid) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_BORDER); + + const int w = solid.width; + const int h = solid.height; + const int MAX_HEIGHT = 0xffff; + + // Mark border spans. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next) + { + // Skip non walkable spans. + if (s->area == RC_NULL_AREA) + continue; + + const int bot = (int)(s->smax); + const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT; + + // Find neighbours minimum height. + int minh = MAX_HEIGHT; + + // Min and max height of accessible neighbours. + int asmin = s->smax; + int asmax = s->smax; + + for (int dir = 0; dir < 4; ++dir) + { + int dx = x + rcGetDirOffsetX(dir); + int dy = y + rcGetDirOffsetY(dir); + // Skip neighbours which are out of bounds. + if (dx < 0 || dy < 0 || dx >= w || dy >= h) + { + minh = rcMin(minh, -walkableClimb - bot); + continue; + } + + // From minus infinity to the first span. + rcSpan* ns = solid.spans[dx + dy*w]; + int nbot = -walkableClimb; + int ntop = ns ? (int)ns->smin : MAX_HEIGHT; + // Skip neightbour if the gap between the spans is too small. + if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight) + minh = rcMin(minh, nbot - bot); + + // Rest of the spans. + for (ns = solid.spans[dx + dy*w]; ns; ns = ns->next) + { + nbot = (int)ns->smax; + ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT; + // Skip neightbour if the gap between the spans is too small. + if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight) + { + minh = rcMin(minh, nbot - bot); + + // Find min/max accessible neighbour height. + if (rcAbs(nbot - bot) <= walkableClimb) + { + if (nbot < asmin) asmin = nbot; + if (nbot > asmax) asmax = nbot; + } + + } + } + } + + // The current span is close to a ledge if the drop to any + // neighbour span is less than the walkableClimb. + if (minh < -walkableClimb) + s->area = RC_NULL_AREA; + + // If the difference between all neighbours is too large, + // we are at steep slope, mark the span as ledge. + if ((asmax - asmin) > walkableClimb) + { + s->area = RC_NULL_AREA; + } + } + } + } + + ctx->stopTimer(RC_TIMER_FILTER_BORDER); +} + +/// @par +/// +/// For this filter, the clearance above the span is the distance from the span's +/// maximum to the next higher span's minimum. (Same grid column.) +/// +/// @see rcHeightfield, rcConfig +void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_WALKABLE); + + const int w = solid.width; + const int h = solid.height; + const int MAX_HEIGHT = 0xffff; + + // Remove walkable flag from spans which do not have enough + // space above them for the agent to stand there. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next) + { + const int bot = (int)(s->smax); + const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT; + if ((top - bot) <= walkableHeight) + s->area = RC_NULL_AREA; + } + } + } + + ctx->stopTimer(RC_TIMER_FILTER_WALKABLE); +} diff --git a/KREngine/3rdparty/recast/source/RecastLayers.cpp b/KREngine/3rdparty/recast/source/RecastLayers.cpp new file mode 100755 index 0000000..204f72e --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastLayers.cpp @@ -0,0 +1,620 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + + +static const int RC_MAX_LAYERS = RC_NOT_CONNECTED; +static const int RC_MAX_NEIS = 16; + +struct rcLayerRegion +{ + unsigned char layers[RC_MAX_LAYERS]; + unsigned char neis[RC_MAX_NEIS]; + unsigned short ymin, ymax; + unsigned char layerId; // Layer ID + unsigned char nlayers; // Layer count + unsigned char nneis; // Neighbour count + unsigned char base; // Flag indicating if the region is hte base of merged regions. +}; + + +static void addUnique(unsigned char* a, unsigned char& an, unsigned char v) +{ + const int n = (int)an; + for (int i = 0; i < n; ++i) + if (a[i] == v) + return; + a[an] = v; + an++; +} + +static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v) +{ + const int n = (int)an; + for (int i = 0; i < n; ++i) + if (a[i] == v) + return true; + return false; +} + +inline bool overlapRange(const unsigned short amin, const unsigned short amax, + const unsigned short bmin, const unsigned short bmax) +{ + return (amin > bmax || amax < bmin) ? false : true; +} + + + +struct rcLayerSweepSpan +{ + unsigned short ns; // number samples + unsigned char id; // region id + unsigned char nei; // neighbour id +}; + +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig +bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int walkableHeight, + rcHeightfieldLayerSet& lset) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_LAYERS); + + const int w = chf.width; + const int h = chf.height; + + rcScopedDelete srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!srcReg) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount); + return false; + } + memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount); + + const int nsweeps = chf.width; + rcScopedDelete sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP); + if (!sweeps) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps); + return false; + } + + + // Partition walkable area into monotone regions. + int prevCount[256]; + unsigned char regId = 0; + + for (int y = borderSize; y < h-borderSize; ++y) + { + memset(prevCount,0,sizeof(int)*regId); + unsigned char sweepId = 0; + + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) continue; + + unsigned char sid = 0xff; + + // -x + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + if (chf.areas[ai] != RC_NULL_AREA && srcReg[ai] != 0xff) + sid = srcReg[ai]; + } + + if (sid == 0xff) + { + sid = sweepId++; + sweeps[sid].nei = 0xff; + sweeps[sid].ns = 0; + } + + // -y + if (rcGetCon(s,3) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + const unsigned char nr = srcReg[ai]; + if (nr != 0xff) + { + // Set neighbour when first valid neighbour is encoutered. + if (sweeps[sid].ns == 0) + sweeps[sid].nei = nr; + + if (sweeps[sid].nei == nr) + { + // Update existing neighbour + sweeps[sid].ns++; + prevCount[nr]++; + } + else + { + // This is hit if there is nore than one neighbour. + // Invalidate the neighbour. + sweeps[sid].nei = 0xff; + } + } + } + + srcReg[i] = sid; + } + } + + // Create unique ID. + for (int i = 0; i < sweepId; ++i) + { + // If the neighbour is set and there is only one continuous connection to it, + // the sweep will be merged with the previous one, else new region is created. + if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == (int)sweeps[i].ns) + { + sweeps[i].id = sweeps[i].nei; + } + else + { + if (regId == 255) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Region ID overflow."); + return false; + } + sweeps[i].id = regId++; + } + } + + // Remap local sweep ids to region ids. + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (srcReg[i] != 0xff) + srcReg[i] = sweeps[srcReg[i]].id; + } + } + } + + // Allocate and init layer regions. + const int nregs = (int)regId; + rcScopedDelete regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP); + if (!regs) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs); + return false; + } + memset(regs, 0, sizeof(rcLayerRegion)*nregs); + for (int i = 0; i < nregs; ++i) + { + regs[i].layerId = 0xff; + regs[i].ymin = 0xffff; + regs[i].ymax = 0; + } + + // Find region neighbours and overlapping regions. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + unsigned char lregs[RC_MAX_LAYERS]; + int nlregs = 0; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + const unsigned char ri = srcReg[i]; + if (ri == 0xff) continue; + + regs[ri].ymin = rcMin(regs[ri].ymin, s.y); + regs[ri].ymax = rcMax(regs[ri].ymax, s.y); + + // Collect all region layers. + if (nlregs < RC_MAX_LAYERS) + lregs[nlregs++] = ri; + + // Update neighbours + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + const unsigned char rai = srcReg[ai]; + if (rai != 0xff && rai != ri) + addUnique(regs[ri].neis, regs[ri].nneis, rai); + } + } + + } + + // Update overlapping regions. + for (int i = 0; i < nlregs-1; ++i) + { + for (int j = i+1; j < nlregs; ++j) + { + if (lregs[i] != lregs[j]) + { + rcLayerRegion& ri = regs[lregs[i]]; + rcLayerRegion& rj = regs[lregs[j]]; + addUnique(ri.layers, ri.nlayers, lregs[j]); + addUnique(rj.layers, rj.nlayers, lregs[i]); + } + } + } + + } + } + + // Create 2D layers from regions. + unsigned char layerId = 0; + + static const int MAX_STACK = 64; + unsigned char stack[MAX_STACK]; + int nstack = 0; + + for (int i = 0; i < nregs; ++i) + { + rcLayerRegion& root = regs[i]; + // Skip alreadu visited. + if (root.layerId != 0xff) + continue; + + // Start search. + root.layerId = layerId; + root.base = 1; + + nstack = 0; + stack[nstack++] = (unsigned char)i; + + while (nstack) + { + // Pop front + rcLayerRegion& reg = regs[stack[0]]; + nstack--; + for (int j = 0; j < nstack; ++j) + stack[j] = stack[j+1]; + + const int nneis = (int)reg.nneis; + for (int j = 0; j < nneis; ++j) + { + const unsigned char nei = reg.neis[j]; + rcLayerRegion& regn = regs[nei]; + // Skip already visited. + if (regn.layerId != 0xff) + continue; + // Skip if the neighbour is overlapping root region. + if (contains(root.layers, root.nlayers, nei)) + continue; + // Skip if the height range would become too large. + const int ymin = rcMin(root.ymin, regn.ymin); + const int ymax = rcMax(root.ymax, regn.ymax); + if ((ymax - ymin) >= 255) + continue; + + if (nstack < MAX_STACK) + { + // Deepen + stack[nstack++] = (unsigned char)nei; + + // Mark layer id + regn.layerId = layerId; + // Merge current layers to root. + for (int k = 0; k < regn.nlayers; ++k) + addUnique(root.layers, root.nlayers, regn.layers[k]); + root.ymin = rcMin(root.ymin, regn.ymin); + root.ymax = rcMax(root.ymax, regn.ymax); + } + } + } + + layerId++; + } + + // Merge non-overlapping regions that are close in height. + const unsigned short mergeHeight = (unsigned short)walkableHeight * 4; + + for (int i = 0; i < nregs; ++i) + { + rcLayerRegion& ri = regs[i]; + if (!ri.base) continue; + + unsigned char newId = ri.layerId; + + for (;;) + { + unsigned char oldId = 0xff; + + for (int j = 0; j < nregs; ++j) + { + if (i == j) continue; + rcLayerRegion& rj = regs[j]; + if (!rj.base) continue; + + // Skip if teh regions are not close to each other. + if (!overlapRange(ri.ymin,ri.ymax+mergeHeight, rj.ymin,rj.ymax+mergeHeight)) + continue; + // Skip if the height range would become too large. + const int ymin = rcMin(ri.ymin, rj.ymin); + const int ymax = rcMax(ri.ymax, rj.ymax); + if ((ymax - ymin) >= 255) + continue; + + // Make sure that there is no overlap when mergin 'ri' and 'rj'. + bool overlap = false; + // Iterate over all regions which have the same layerId as 'rj' + for (int k = 0; k < nregs; ++k) + { + if (regs[k].layerId != rj.layerId) + continue; + // Check if region 'k' is overlapping region 'ri' + // Index to 'regs' is the same as region id. + if (contains(ri.layers,ri.nlayers, (unsigned char)k)) + { + overlap = true; + break; + } + } + // Cannot merge of regions overlap. + if (overlap) + continue; + + // Can merge i and j. + oldId = rj.layerId; + break; + } + + // Could not find anything to merge with, stop. + if (oldId == 0xff) + break; + + // Merge + for (int j = 0; j < nregs; ++j) + { + rcLayerRegion& rj = regs[j]; + if (rj.layerId == oldId) + { + rj.base = 0; + // Remap layerIds. + rj.layerId = newId; + // Add overlaid layers from 'rj' to 'ri'. + for (int k = 0; k < rj.nlayers; ++k) + addUnique(ri.layers, ri.nlayers, rj.layers[k]); + // Update heigh bounds. + ri.ymin = rcMin(ri.ymin, rj.ymin); + ri.ymax = rcMax(ri.ymax, rj.ymax); + } + } + } + } + + // Compact layerIds + unsigned char remap[256]; + memset(remap, 0, 256); + + // Find number of unique layers. + layerId = 0; + for (int i = 0; i < nregs; ++i) + remap[regs[i].layerId] = 1; + for (int i = 0; i < 256; ++i) + { + if (remap[i]) + remap[i] = layerId++; + else + remap[i] = 0xff; + } + // Remap ids. + for (int i = 0; i < nregs; ++i) + regs[i].layerId = remap[regs[i].layerId]; + + // No layers, return empty. + if (layerId == 0) + { + ctx->stopTimer(RC_TIMER_BUILD_LAYERS); + return true; + } + + // Create layers. + rcAssert(lset.layers == 0); + + const int lw = w - borderSize*2; + const int lh = h - borderSize*2; + + // Build contracted bbox for layers. + float bmin[3], bmax[3]; + rcVcopy(bmin, chf.bmin); + rcVcopy(bmax, chf.bmax); + bmin[0] += borderSize*chf.cs; + bmin[2] += borderSize*chf.cs; + bmax[0] -= borderSize*chf.cs; + bmax[2] -= borderSize*chf.cs; + + lset.nlayers = (int)layerId; + + lset.layers = (rcHeightfieldLayer*)rcAlloc(sizeof(rcHeightfieldLayer)*lset.nlayers, RC_ALLOC_PERM); + if (!lset.layers) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'layers' (%d).", lset.nlayers); + return false; + } + memset(lset.layers, 0, sizeof(rcHeightfieldLayer)*lset.nlayers); + + + // Store layers. + for (int i = 0; i < lset.nlayers; ++i) + { + unsigned char curId = (unsigned char)i; + + // Allocate memory for the current layer. + rcHeightfieldLayer* layer = &lset.layers[i]; + memset(layer, 0, sizeof(rcHeightfieldLayer)); + + const int gridSize = sizeof(unsigned char)*lw*lh; + + layer->heights = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->heights) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'heights' (%d).", gridSize); + return false; + } + memset(layer->heights, 0xff, gridSize); + + layer->areas = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'areas' (%d).", gridSize); + return false; + } + memset(layer->areas, 0, gridSize); + + layer->cons = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->cons) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'cons' (%d).", gridSize); + return false; + } + memset(layer->cons, 0, gridSize); + + // Find layer height bounds. + int hmin = 0, hmax = 0; + for (int j = 0; j < nregs; ++j) + { + if (regs[j].base && regs[j].layerId == curId) + { + hmin = (int)regs[j].ymin; + hmax = (int)regs[j].ymax; + } + } + + layer->width = lw; + layer->height = lh; + layer->cs = chf.cs; + layer->ch = chf.ch; + + // Adjust the bbox to fit the heighfield. + rcVcopy(layer->bmin, bmin); + rcVcopy(layer->bmax, bmax); + layer->bmin[1] = bmin[1] + hmin*chf.ch; + layer->bmax[1] = bmin[1] + hmax*chf.ch; + layer->hmin = hmin; + layer->hmax = hmax; + + // Update usable data region. + layer->minx = layer->width; + layer->maxx = 0; + layer->miny = layer->height; + layer->maxy = 0; + + // Copy height and area from compact heighfield. + for (int y = 0; y < lh; ++y) + { + for (int x = 0; x < lw; ++x) + { + const int cx = borderSize+x; + const int cy = borderSize+y; + const rcCompactCell& c = chf.cells[cx+cy*w]; + for (int j = (int)c.index, nj = (int)(c.index+c.count); j < nj; ++j) + { + const rcCompactSpan& s = chf.spans[j]; + // Skip unassigned regions. + if (srcReg[j] == 0xff) + continue; + // Skip of does nto belong to current layer. + unsigned char lid = regs[srcReg[j]].layerId; + if (lid != curId) + continue; + + // Update data bounds. + layer->minx = rcMin(layer->minx, x); + layer->maxx = rcMax(layer->maxx, x); + layer->miny = rcMin(layer->miny, y); + layer->maxy = rcMax(layer->maxy, y); + + // Store height and area type. + const int idx = x+y*lw; + layer->heights[idx] = (unsigned char)(s.y - hmin); + layer->areas[idx] = chf.areas[j]; + + // Check connection. + unsigned char portal = 0; + unsigned char con = 0; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + unsigned char alid = srcReg[ai] != 0xff ? regs[srcReg[ai]].layerId : 0xff; + // Portal mask + if (chf.areas[ai] != RC_NULL_AREA && lid != alid) + { + portal |= (unsigned char)(1< hmin) + layer->heights[idx] = rcMax(layer->heights[idx], (unsigned char)(as.y - hmin)); + } + // Valid connection mask + if (chf.areas[ai] != RC_NULL_AREA && lid == alid) + { + const int nx = ax - borderSize; + const int ny = ay - borderSize; + if (nx >= 0 && ny >= 0 && nx < lw && ny < lh) + con |= (unsigned char)(1<cons[idx] = (portal << 4) | con; + } + } + } + + if (layer->minx > layer->maxx) + layer->minx = layer->maxx = 0; + if (layer->miny > layer->maxy) + layer->miny = layer->maxy = 0; + } + + ctx->stopTimer(RC_TIMER_BUILD_LAYERS); + + return true; +} diff --git a/KREngine/3rdparty/recast/source/RecastMesh.cpp b/KREngine/3rdparty/recast/source/RecastMesh.cpp new file mode 100755 index 0000000..534a72e --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastMesh.cpp @@ -0,0 +1,1433 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#define _USE_MATH_DEFINES +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + +struct rcEdge +{ + unsigned short vert[2]; + unsigned short polyEdge[2]; + unsigned short poly[2]; +}; + +static bool buildMeshAdjacency(unsigned short* polys, const int npolys, + const int nverts, const int vertsPerPoly) +{ + // Based on code by Eric Lengyel from: + // http://www.terathon.com/code/edges.php + + int maxEdgeCount = npolys*vertsPerPoly; + unsigned short* firstEdge = (unsigned short*)rcAlloc(sizeof(unsigned short)*(nverts + maxEdgeCount), RC_ALLOC_TEMP); + if (!firstEdge) + return false; + unsigned short* nextEdge = firstEdge + nverts; + int edgeCount = 0; + + rcEdge* edges = (rcEdge*)rcAlloc(sizeof(rcEdge)*maxEdgeCount, RC_ALLOC_TEMP); + if (!edges) + { + rcFree(firstEdge); + return false; + } + + for (int i = 0; i < nverts; i++) + firstEdge[i] = RC_MESH_NULL_IDX; + + for (int i = 0; i < npolys; ++i) + { + unsigned short* t = &polys[i*vertsPerPoly*2]; + for (int j = 0; j < vertsPerPoly; ++j) + { + if (t[j] == RC_MESH_NULL_IDX) break; + unsigned short v0 = t[j]; + unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; + if (v0 < v1) + { + rcEdge& edge = edges[edgeCount]; + edge.vert[0] = v0; + edge.vert[1] = v1; + edge.poly[0] = (unsigned short)i; + edge.polyEdge[0] = (unsigned short)j; + edge.poly[1] = (unsigned short)i; + edge.polyEdge[1] = 0; + // Insert edge + nextEdge[edgeCount] = firstEdge[v0]; + firstEdge[v0] = (unsigned short)edgeCount; + edgeCount++; + } + } + } + + for (int i = 0; i < npolys; ++i) + { + unsigned short* t = &polys[i*vertsPerPoly*2]; + for (int j = 0; j < vertsPerPoly; ++j) + { + if (t[j] == RC_MESH_NULL_IDX) break; + unsigned short v0 = t[j]; + unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; + if (v0 > v1) + { + for (unsigned short e = firstEdge[v1]; e != RC_MESH_NULL_IDX; e = nextEdge[e]) + { + rcEdge& edge = edges[e]; + if (edge.vert[1] == v0 && edge.poly[0] == edge.poly[1]) + { + edge.poly[1] = (unsigned short)i; + edge.polyEdge[1] = (unsigned short)j; + break; + } + } + } + } + } + + // Store adjacency + for (int i = 0; i < edgeCount; ++i) + { + const rcEdge& e = edges[i]; + if (e.poly[0] != e.poly[1]) + { + unsigned short* p0 = &polys[e.poly[0]*vertsPerPoly*2]; + unsigned short* p1 = &polys[e.poly[1]*vertsPerPoly*2]; + p0[vertsPerPoly + e.polyEdge[0]] = e.poly[1]; + p1[vertsPerPoly + e.polyEdge[1]] = e.poly[0]; + } + } + + rcFree(firstEdge); + rcFree(edges); + + return true; +} + + +static const int VERTEX_BUCKET_COUNT = (1<<12); + +inline int computeVertexHash(int x, int y, int z) +{ + const unsigned int h1 = 0x8da6b343; // Large multiplicative constants; + const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes + const unsigned int h3 = 0xcb1ab31f; + unsigned int n = h1 * x + h2 * y + h3 * z; + return (int)(n & (VERTEX_BUCKET_COUNT-1)); +} + +static unsigned short addVertex(unsigned short x, unsigned short y, unsigned short z, + unsigned short* verts, int* firstVert, int* nextVert, int& nv) +{ + int bucket = computeVertexHash(x, 0, z); + int i = firstVert[bucket]; + + while (i != -1) + { + const unsigned short* v = &verts[i*3]; + if (v[0] == x && (rcAbs(v[1] - y) <= 2) && v[2] == z) + return (unsigned short)i; + i = nextVert[i]; // next + } + + // Could not find, create new. + i = nv; nv++; + unsigned short* v = &verts[i*3]; + v[0] = x; + v[1] = y; + v[2] = z; + nextVert[i] = firstVert[bucket]; + firstVert[bucket] = i; + + return (unsigned short)i; +} + +inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; } +inline int next(int i, int n) { return i+1 < n ? i+1 : 0; } + +inline int area2(const int* a, const int* b, const int* c) +{ + return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]); +} + +// Exclusive or: true iff exactly one argument is true. +// The arguments are negated to ensure that they are 0/1 +// values. Then the bitwise Xor operator may apply. +// (This idea is due to Michael Baldwin.) +inline bool xorb(bool x, bool y) +{ + return !x ^ !y; +} + +// Returns true iff c is strictly to the left of the directed +// line through a to b. +inline bool left(const int* a, const int* b, const int* c) +{ + return area2(a, b, c) < 0; +} + +inline bool leftOn(const int* a, const int* b, const int* c) +{ + return area2(a, b, c) <= 0; +} + +inline bool collinear(const int* a, const int* b, const int* c) +{ + return area2(a, b, c) == 0; +} + +// Returns true iff ab properly intersects cd: they share +// a point interior to both segments. The properness of the +// intersection is ensured by using strict leftness. +static bool intersectProp(const int* a, const int* b, const int* c, const int* d) +{ + // Eliminate improper cases. + if (collinear(a,b,c) || collinear(a,b,d) || + collinear(c,d,a) || collinear(c,d,b)) + return false; + + return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b)); +} + +// Returns T iff (a,b,c) are collinear and point c lies +// on the closed segement ab. +static bool between(const int* a, const int* b, const int* c) +{ + if (!collinear(a, b, c)) + return false; + // If ab not vertical, check betweenness on x; else on y. + if (a[0] != b[0]) + return ((a[0] <= c[0]) && (c[0] <= b[0])) || ((a[0] >= c[0]) && (c[0] >= b[0])); + else + return ((a[2] <= c[2]) && (c[2] <= b[2])) || ((a[2] >= c[2]) && (c[2] >= b[2])); +} + +// Returns true iff segments ab and cd intersect, properly or improperly. +static bool intersect(const int* a, const int* b, const int* c, const int* d) +{ + if (intersectProp(a, b, c, d)) + return true; + else if (between(a, b, c) || between(a, b, d) || + between(c, d, a) || between(c, d, b)) + return true; + else + return false; +} + +static bool vequal(const int* a, const int* b) +{ + return a[0] == b[0] && a[2] == b[2]; +} + +// Returns T iff (v_i, v_j) is a proper internal *or* external +// diagonal of P, *ignoring edges incident to v_i and v_j*. +static bool diagonalie(int i, int j, int n, const int* verts, int* indices) +{ + const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4]; + const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4]; + + // For each edge (k,k+1) of P + for (int k = 0; k < n; k++) + { + int k1 = next(k, n); + // Skip edges incident to i or j + if (!((k == i) || (k1 == i) || (k == j) || (k1 == j))) + { + const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4]; + const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4]; + + if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1)) + continue; + + if (intersect(d0, d1, p0, p1)) + return false; + } + } + return true; +} + +// Returns true iff the diagonal (i,j) is strictly internal to the +// polygon P in the neighborhood of the i endpoint. +static bool inCone(int i, int j, int n, const int* verts, int* indices) +{ + const int* pi = &verts[(indices[i] & 0x0fffffff) * 4]; + const int* pj = &verts[(indices[j] & 0x0fffffff) * 4]; + const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4]; + const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4]; + + // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. + if (leftOn(pin1, pi, pi1)) + return left(pi, pj, pin1) && left(pj, pi, pi1); + // Assume (i-1,i,i+1) not collinear. + // else P[i] is reflex. + return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1)); +} + +// Returns T iff (v_i, v_j) is a proper internal +// diagonal of P. +static bool diagonal(int i, int j, int n, const int* verts, int* indices) +{ + return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); +} + +static int triangulate(int n, const int* verts, int* indices, int* tris) +{ + int ntris = 0; + int* dst = tris; + + // The last bit of the index is used to indicate if the vertex can be removed. + for (int i = 0; i < n; i++) + { + int i1 = next(i, n); + int i2 = next(i1, n); + if (diagonal(i, i2, n, verts, indices)) + indices[i1] |= 0x80000000; + } + + while (n > 3) + { + int minLen = -1; + int mini = -1; + for (int i = 0; i < n; i++) + { + int i1 = next(i, n); + if (indices[i1] & 0x80000000) + { + const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4]; + const int* p2 = &verts[(indices[next(i1, n)] & 0x0fffffff) * 4]; + + int dx = p2[0] - p0[0]; + int dy = p2[2] - p0[2]; + int len = dx*dx + dy*dy; + + if (minLen < 0 || len < minLen) + { + minLen = len; + mini = i; + } + } + } + + if (mini == -1) + { + // Should not happen. +/* printf("mini == -1 ntris=%d n=%d\n", ntris, n); + for (int i = 0; i < n; i++) + { + printf("%d ", indices[i] & 0x0fffffff); + } + printf("\n");*/ + return -ntris; + } + + int i = mini; + int i1 = next(i, n); + int i2 = next(i1, n); + + *dst++ = indices[i] & 0x0fffffff; + *dst++ = indices[i1] & 0x0fffffff; + *dst++ = indices[i2] & 0x0fffffff; + ntris++; + + // Removes P[i1] by copying P[i+1]...P[n-1] left one index. + n--; + for (int k = i1; k < n; k++) + indices[k] = indices[k+1]; + + if (i1 >= n) i1 = 0; + i = prev(i1,n); + // Update diagonal flags. + if (diagonal(prev(i, n), i1, n, verts, indices)) + indices[i] |= 0x80000000; + else + indices[i] &= 0x0fffffff; + + if (diagonal(i, next(i1, n), n, verts, indices)) + indices[i1] |= 0x80000000; + else + indices[i1] &= 0x0fffffff; + } + + // Append the remaining triangle. + *dst++ = indices[0] & 0x0fffffff; + *dst++ = indices[1] & 0x0fffffff; + *dst++ = indices[2] & 0x0fffffff; + ntris++; + + return ntris; +} + +static int countPolyVerts(const unsigned short* p, const int nvp) +{ + for (int i = 0; i < nvp; ++i) + if (p[i] == RC_MESH_NULL_IDX) + return i; + return nvp; +} + +inline bool uleft(const unsigned short* a, const unsigned short* b, const unsigned short* c) +{ + return ((int)b[0] - (int)a[0]) * ((int)c[2] - (int)a[2]) - + ((int)c[0] - (int)a[0]) * ((int)b[2] - (int)a[2]) < 0; +} + +static int getPolyMergeValue(unsigned short* pa, unsigned short* pb, + const unsigned short* verts, int& ea, int& eb, + const int nvp) +{ + const int na = countPolyVerts(pa, nvp); + const int nb = countPolyVerts(pb, nvp); + + // If the merged polygon would be too big, do not merge. + if (na+nb-2 > nvp) + return -1; + + // Check if the polygons share an edge. + ea = -1; + eb = -1; + + for (int i = 0; i < na; ++i) + { + unsigned short va0 = pa[i]; + unsigned short va1 = pa[(i+1) % na]; + if (va0 > va1) + rcSwap(va0, va1); + for (int j = 0; j < nb; ++j) + { + unsigned short vb0 = pb[j]; + unsigned short vb1 = pb[(j+1) % nb]; + if (vb0 > vb1) + rcSwap(vb0, vb1); + if (va0 == vb0 && va1 == vb1) + { + ea = i; + eb = j; + break; + } + } + } + + // No common edge, cannot merge. + if (ea == -1 || eb == -1) + return -1; + + // Check to see if the merged polygon would be convex. + unsigned short va, vb, vc; + + va = pa[(ea+na-1) % na]; + vb = pa[ea]; + vc = pb[(eb+2) % nb]; + if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3])) + return -1; + + va = pb[(eb+nb-1) % nb]; + vb = pb[eb]; + vc = pa[(ea+2) % na]; + if (!uleft(&verts[va*3], &verts[vb*3], &verts[vc*3])) + return -1; + + va = pa[ea]; + vb = pa[(ea+1)%na]; + + int dx = (int)verts[va*3+0] - (int)verts[vb*3+0]; + int dy = (int)verts[va*3+2] - (int)verts[vb*3+2]; + + return dx*dx + dy*dy; +} + +static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb, + unsigned short* tmp, const int nvp) +{ + const int na = countPolyVerts(pa, nvp); + const int nb = countPolyVerts(pb, nvp); + + // Merge polygons. + memset(tmp, 0xff, sizeof(unsigned short)*nvp); + int n = 0; + // Add pa + for (int i = 0; i < na-1; ++i) + tmp[n++] = pa[(ea+1+i) % na]; + // Add pb + for (int i = 0; i < nb-1; ++i) + tmp[n++] = pb[(eb+1+i) % nb]; + + memcpy(pa, tmp, sizeof(unsigned short)*nvp); +} + + +static void pushFront(int v, int* arr, int& an) +{ + an++; + for (int i = an-1; i > 0; --i) arr[i] = arr[i-1]; + arr[0] = v; +} + +static void pushBack(int v, int* arr, int& an) +{ + arr[an] = v; + an++; +} + +static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short rem) +{ + const int nvp = mesh.nvp; + + // Count number of polygons to remove. + int numRemovedVerts = 0; + int numTouchedVerts = 0; + int numRemainingEdges = 0; + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + int numRemoved = 0; + int numVerts = 0; + for (int j = 0; j < nv; ++j) + { + if (p[j] == rem) + { + numTouchedVerts++; + numRemoved++; + } + numVerts++; + } + if (numRemoved) + { + numRemovedVerts += numRemoved; + numRemainingEdges += numVerts-(numRemoved+1); + } + } + + // There would be too few edges remaining to create a polygon. + // This can happen for example when a tip of a triangle is marked + // as deletion, but there are no other polys that share the vertex. + // In this case, the vertex should not be removed. + if (numRemainingEdges <= 2) + return false; + + // Find edges which share the removed vertex. + const int maxEdges = numTouchedVerts*2; + int nedges = 0; + rcScopedDelete edges = (int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP); + if (!edges) + { + ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3); + return false; + } + + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + + // Collect edges which touches the removed vertex. + for (int j = 0, k = nv-1; j < nv; k = j++) + { + if (p[j] == rem || p[k] == rem) + { + // Arrange edge so that a=rem. + int a = p[j], b = p[k]; + if (b == rem) + rcSwap(a,b); + + // Check if the edge exists + bool exists = false; + for (int m = 0; m < nedges; ++m) + { + int* e = &edges[m*3]; + if (e[1] == b) + { + // Exists, increment vertex share count. + e[2]++; + exists = true; + } + } + // Add new edge. + if (!exists) + { + int* e = &edges[nedges*3]; + e[0] = a; + e[1] = b; + e[2] = 1; + nedges++; + } + } + } + } + + // There should be no more than 2 open edges. + // This catches the case that two non-adjacent polygons + // share the removed vertex. In that case, do not remove the vertex. + int numOpenEdges = 0; + for (int i = 0; i < nedges; ++i) + { + if (edges[i*3+2] < 2) + numOpenEdges++; + } + if (numOpenEdges > 2) + return false; + + return true; +} + +static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short rem, const int maxTris) +{ + const int nvp = mesh.nvp; + + // Count number of polygons to remove. + int numRemovedVerts = 0; + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + for (int j = 0; j < nv; ++j) + { + if (p[j] == rem) + numRemovedVerts++; + } + } + + int nedges = 0; + rcScopedDelete edges = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP); + if (!edges) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4); + return false; + } + + int nhole = 0; + rcScopedDelete hole = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); + if (!hole) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp); + return false; + } + + int nhreg = 0; + rcScopedDelete hreg = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); + if (!hreg) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp); + return false; + } + + int nharea = 0; + rcScopedDelete harea = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); + if (!harea) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp); + return false; + } + + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + bool hasRem = false; + for (int j = 0; j < nv; ++j) + if (p[j] == rem) hasRem = true; + if (hasRem) + { + // Collect edges which does not touch the removed vertex. + for (int j = 0, k = nv-1; j < nv; k = j++) + { + if (p[j] != rem && p[k] != rem) + { + int* e = &edges[nedges*4]; + e[0] = p[k]; + e[1] = p[j]; + e[2] = mesh.regs[i]; + e[3] = mesh.areas[i]; + nedges++; + } + } + // Remove the polygon. + unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2]; + if (p != p2) + memcpy(p,p2,sizeof(unsigned short)*nvp); + memset(p+nvp,0xff,sizeof(unsigned short)*nvp); + mesh.regs[i] = mesh.regs[mesh.npolys-1]; + mesh.areas[i] = mesh.areas[mesh.npolys-1]; + mesh.npolys--; + --i; + } + } + + // Remove vertex. + for (int i = (int)rem; i < mesh.nverts; ++i) + { + mesh.verts[i*3+0] = mesh.verts[(i+1)*3+0]; + mesh.verts[i*3+1] = mesh.verts[(i+1)*3+1]; + mesh.verts[i*3+2] = mesh.verts[(i+1)*3+2]; + } + mesh.nverts--; + + // Adjust indices to match the removed vertex layout. + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + for (int j = 0; j < nv; ++j) + if (p[j] > rem) p[j]--; + } + for (int i = 0; i < nedges; ++i) + { + if (edges[i*4+0] > rem) edges[i*4+0]--; + if (edges[i*4+1] > rem) edges[i*4+1]--; + } + + if (nedges == 0) + return true; + + // Start with one vertex, keep appending connected + // segments to the start and end of the hole. + pushBack(edges[0], hole, nhole); + pushBack(edges[2], hreg, nhreg); + pushBack(edges[3], harea, nharea); + + while (nedges) + { + bool match = false; + + for (int i = 0; i < nedges; ++i) + { + const int ea = edges[i*4+0]; + const int eb = edges[i*4+1]; + const int r = edges[i*4+2]; + const int a = edges[i*4+3]; + bool add = false; + if (hole[0] == eb) + { + // The segment matches the beginning of the hole boundary. + pushFront(ea, hole, nhole); + pushFront(r, hreg, nhreg); + pushFront(a, harea, nharea); + add = true; + } + else if (hole[nhole-1] == ea) + { + // The segment matches the end of the hole boundary. + pushBack(eb, hole, nhole); + pushBack(r, hreg, nhreg); + pushBack(a, harea, nharea); + add = true; + } + if (add) + { + // The edge segment was added, remove it. + edges[i*4+0] = edges[(nedges-1)*4+0]; + edges[i*4+1] = edges[(nedges-1)*4+1]; + edges[i*4+2] = edges[(nedges-1)*4+2]; + edges[i*4+3] = edges[(nedges-1)*4+3]; + --nedges; + match = true; + --i; + } + } + + if (!match) + break; + } + + rcScopedDelete tris = (int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP); + if (!tris) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3); + return false; + } + + rcScopedDelete tverts = (int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP); + if (!tverts) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4); + return false; + } + + rcScopedDelete thole = (int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP); + if (!tverts) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole); + return false; + } + + // Generate temp vertex array for triangulation. + for (int i = 0; i < nhole; ++i) + { + const int pi = hole[i]; + tverts[i*4+0] = mesh.verts[pi*3+0]; + tverts[i*4+1] = mesh.verts[pi*3+1]; + tverts[i*4+2] = mesh.verts[pi*3+2]; + tverts[i*4+3] = 0; + thole[i] = i; + } + + // Triangulate the hole. + int ntris = triangulate(nhole, &tverts[0], &thole[0], tris); + if (ntris < 0) + { + ntris = -ntris; + ctx->log(RC_LOG_WARNING, "removeVertex: triangulate() returned bad results."); + } + + // Merge the hole triangles back to polygons. + rcScopedDelete polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP); + if (!polys) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp); + return false; + } + rcScopedDelete pregs = (unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP); + if (!pregs) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris); + return false; + } + rcScopedDelete pareas = (unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP); + if (!pregs) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris); + return false; + } + + unsigned short* tmpPoly = &polys[ntris*nvp]; + + // Build initial polygons. + int npolys = 0; + memset(polys, 0xff, ntris*nvp*sizeof(unsigned short)); + for (int j = 0; j < ntris; ++j) + { + int* t = &tris[j*3]; + if (t[0] != t[1] && t[0] != t[2] && t[1] != t[2]) + { + polys[npolys*nvp+0] = (unsigned short)hole[t[0]]; + polys[npolys*nvp+1] = (unsigned short)hole[t[1]]; + polys[npolys*nvp+2] = (unsigned short)hole[t[2]]; + pregs[npolys] = (unsigned short)hreg[t[0]]; + pareas[npolys] = (unsigned char)harea[t[0]]; + npolys++; + } + } + if (!npolys) + return true; + + // Merge polygons. + if (nvp > 3) + { + for (;;) + { + // Find best polygons to merge. + int bestMergeVal = 0; + int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0; + + for (int j = 0; j < npolys-1; ++j) + { + unsigned short* pj = &polys[j*nvp]; + for (int k = j+1; k < npolys; ++k) + { + unsigned short* pk = &polys[k*nvp]; + int ea, eb; + int v = getPolyMergeValue(pj, pk, mesh.verts, ea, eb, nvp); + if (v > bestMergeVal) + { + bestMergeVal = v; + bestPa = j; + bestPb = k; + bestEa = ea; + bestEb = eb; + } + } + } + + if (bestMergeVal > 0) + { + // Found best, merge. + unsigned short* pa = &polys[bestPa*nvp]; + unsigned short* pb = &polys[bestPb*nvp]; + mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp); + unsigned short* last = &polys[(npolys-1)*nvp]; + if (pb != last) + memcpy(pb, last, sizeof(unsigned short)*nvp); + pregs[bestPb] = pregs[npolys-1]; + pareas[bestPb] = pareas[npolys-1]; + npolys--; + } + else + { + // Could not merge any polygons, stop. + break; + } + } + } + + // Store polygons. + for (int i = 0; i < npolys; ++i) + { + if (mesh.npolys >= maxTris) break; + unsigned short* p = &mesh.polys[mesh.npolys*nvp*2]; + memset(p,0xff,sizeof(unsigned short)*nvp*2); + for (int j = 0; j < nvp; ++j) + p[j] = polys[i*nvp+j]; + mesh.regs[mesh.npolys] = pregs[i]; + mesh.areas[mesh.npolys] = pareas[i]; + mesh.npolys++; + if (mesh.npolys > maxTris) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris); + return false; + } + } + + return true; +} + +/// @par +/// +/// @note If the mesh data is to be used to construct a Detour navigation mesh, then the upper +/// limit must be retricted to <= #DT_VERTS_PER_POLYGON. +/// +/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig +bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_POLYMESH); + + rcVcopy(mesh.bmin, cset.bmin); + rcVcopy(mesh.bmax, cset.bmax); + mesh.cs = cset.cs; + mesh.ch = cset.ch; + mesh.borderSize = cset.borderSize; + + int maxVertices = 0; + int maxTris = 0; + int maxVertsPerCont = 0; + for (int i = 0; i < cset.nconts; ++i) + { + // Skip null contours. + if (cset.conts[i].nverts < 3) continue; + maxVertices += cset.conts[i].nverts; + maxTris += cset.conts[i].nverts - 2; + maxVertsPerCont = rcMax(maxVertsPerCont, cset.conts[i].nverts); + } + + if (maxVertices >= 0xfffe) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices); + return false; + } + + rcScopedDelete vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP); + if (!vflags) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices); + return false; + } + memset(vflags, 0, maxVertices); + + mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertices*3, RC_ALLOC_PERM); + if (!mesh.verts) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); + return false; + } + mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM); + if (!mesh.polys) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2); + return false; + } + mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris, RC_ALLOC_PERM); + if (!mesh.regs) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris); + return false; + } + mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris, RC_ALLOC_PERM); + if (!mesh.areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris); + return false; + } + + mesh.nverts = 0; + mesh.npolys = 0; + mesh.nvp = nvp; + mesh.maxpolys = maxTris; + + memset(mesh.verts, 0, sizeof(unsigned short)*maxVertices*3); + memset(mesh.polys, 0xff, sizeof(unsigned short)*maxTris*nvp*2); + memset(mesh.regs, 0, sizeof(unsigned short)*maxTris); + memset(mesh.areas, 0, sizeof(unsigned char)*maxTris); + + rcScopedDelete nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP); + if (!nextVert) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices); + return false; + } + memset(nextVert, 0, sizeof(int)*maxVertices); + + rcScopedDelete firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP); + if (!firstVert) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); + return false; + } + for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) + firstVert[i] = -1; + + rcScopedDelete indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP); + if (!indices) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont); + return false; + } + rcScopedDelete tris = (int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP); + if (!tris) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3); + return false; + } + rcScopedDelete polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP); + if (!polys) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp); + return false; + } + unsigned short* tmpPoly = &polys[maxVertsPerCont*nvp]; + + for (int i = 0; i < cset.nconts; ++i) + { + rcContour& cont = cset.conts[i]; + + // Skip null contours. + if (cont.nverts < 3) + continue; + + // Triangulate contour + for (int j = 0; j < cont.nverts; ++j) + indices[j] = j; + + int ntris = triangulate(cont.nverts, cont.verts, &indices[0], &tris[0]); + if (ntris <= 0) + { + // Bad triangulation, should not happen. +/* printf("\tconst float bmin[3] = {%ff,%ff,%ff};\n", cset.bmin[0], cset.bmin[1], cset.bmin[2]); + printf("\tconst float cs = %ff;\n", cset.cs); + printf("\tconst float ch = %ff;\n", cset.ch); + printf("\tconst int verts[] = {\n"); + for (int k = 0; k < cont.nverts; ++k) + { + const int* v = &cont.verts[k*4]; + printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]); + } + printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/ + ctx->log(RC_LOG_WARNING, "rcBuildPolyMesh: Bad triangulation Contour %d.", i); + ntris = -ntris; + } + + // Add and merge vertices. + for (int j = 0; j < cont.nverts; ++j) + { + const int* v = &cont.verts[j*4]; + indices[j] = addVertex((unsigned short)v[0], (unsigned short)v[1], (unsigned short)v[2], + mesh.verts, firstVert, nextVert, mesh.nverts); + if (v[3] & RC_BORDER_VERTEX) + { + // This vertex should be removed. + vflags[indices[j]] = 1; + } + } + + // Build initial polygons. + int npolys = 0; + memset(polys, 0xff, maxVertsPerCont*nvp*sizeof(unsigned short)); + for (int j = 0; j < ntris; ++j) + { + int* t = &tris[j*3]; + if (t[0] != t[1] && t[0] != t[2] && t[1] != t[2]) + { + polys[npolys*nvp+0] = (unsigned short)indices[t[0]]; + polys[npolys*nvp+1] = (unsigned short)indices[t[1]]; + polys[npolys*nvp+2] = (unsigned short)indices[t[2]]; + npolys++; + } + } + if (!npolys) + continue; + + // Merge polygons. + if (nvp > 3) + { + for(;;) + { + // Find best polygons to merge. + int bestMergeVal = 0; + int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0; + + for (int j = 0; j < npolys-1; ++j) + { + unsigned short* pj = &polys[j*nvp]; + for (int k = j+1; k < npolys; ++k) + { + unsigned short* pk = &polys[k*nvp]; + int ea, eb; + int v = getPolyMergeValue(pj, pk, mesh.verts, ea, eb, nvp); + if (v > bestMergeVal) + { + bestMergeVal = v; + bestPa = j; + bestPb = k; + bestEa = ea; + bestEb = eb; + } + } + } + + if (bestMergeVal > 0) + { + // Found best, merge. + unsigned short* pa = &polys[bestPa*nvp]; + unsigned short* pb = &polys[bestPb*nvp]; + mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp); + unsigned short* lastPoly = &polys[(npolys-1)*nvp]; + if (pb != lastPoly) + memcpy(pb, lastPoly, sizeof(unsigned short)*nvp); + npolys--; + } + else + { + // Could not merge any polygons, stop. + break; + } + } + } + + // Store polygons. + for (int j = 0; j < npolys; ++j) + { + unsigned short* p = &mesh.polys[mesh.npolys*nvp*2]; + unsigned short* q = &polys[j*nvp]; + for (int k = 0; k < nvp; ++k) + p[k] = q[k]; + mesh.regs[mesh.npolys] = cont.reg; + mesh.areas[mesh.npolys] = cont.area; + mesh.npolys++; + if (mesh.npolys > maxTris) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many polygons %d (max:%d).", mesh.npolys, maxTris); + return false; + } + } + } + + + // Remove edge vertices. + for (int i = 0; i < mesh.nverts; ++i) + { + if (vflags[i]) + { + if (!canRemoveVertex(ctx, mesh, (unsigned short)i)) + continue; + if (!removeVertex(ctx, mesh, (unsigned short)i, maxTris)) + { + // Failed to remove vertex + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i); + return false; + } + // Remove vertex + // Note: mesh.nverts is already decremented inside removeVertex()! + // Fixup vertex flags + for (int j = i; j < mesh.nverts; ++j) + vflags[j] = vflags[j+1]; + --i; + } + } + + // Calculate adjacency. + if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp)) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed."); + return false; + } + + // Find portal edges + if (mesh.borderSize > 0) + { + const int w = cset.width; + const int h = cset.height; + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*2*nvp]; + for (int j = 0; j < nvp; ++j) + { + if (p[j] == RC_MESH_NULL_IDX) break; + // Skip connected edges. + if (p[nvp+j] != RC_MESH_NULL_IDX) + continue; + int nj = j+1; + if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0; + const unsigned short* va = &mesh.verts[p[j]*3]; + const unsigned short* vb = &mesh.verts[p[nj]*3]; + + if ((int)va[0] == 0 && (int)vb[0] == 0) + p[nvp+j] = 0x8000 | 0; + else if ((int)va[2] == h && (int)vb[2] == h) + p[nvp+j] = 0x8000 | 1; + else if ((int)va[0] == w && (int)vb[0] == w) + p[nvp+j] = 0x8000 | 2; + else if ((int)va[2] == 0 && (int)vb[2] == 0) + p[nvp+j] = 0x8000 | 3; + } + } + } + + // Just allocate the mesh flags array. The user is resposible to fill it. + mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM); + if (!mesh.flags) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.flags' (%d).", mesh.npolys); + return false; + } + memset(mesh.flags, 0, sizeof(unsigned short) * mesh.npolys); + + if (mesh.nverts > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); + } + if (mesh.npolys > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); + } + + ctx->stopTimer(RC_TIMER_BUILD_POLYMESH); + + return true; +} + +/// @see rcAllocPolyMesh, rcPolyMesh +bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) +{ + rcAssert(ctx); + + if (!nmeshes || !meshes) + return true; + + ctx->startTimer(RC_TIMER_MERGE_POLYMESH); + + mesh.nvp = meshes[0]->nvp; + mesh.cs = meshes[0]->cs; + mesh.ch = meshes[0]->ch; + rcVcopy(mesh.bmin, meshes[0]->bmin); + rcVcopy(mesh.bmax, meshes[0]->bmax); + + int maxVerts = 0; + int maxPolys = 0; + int maxVertsPerMesh = 0; + for (int i = 0; i < nmeshes; ++i) + { + rcVmin(mesh.bmin, meshes[i]->bmin); + rcVmax(mesh.bmax, meshes[i]->bmax); + maxVertsPerMesh = rcMax(maxVertsPerMesh, meshes[i]->nverts); + maxVerts += meshes[i]->nverts; + maxPolys += meshes[i]->npolys; + } + + mesh.nverts = 0; + mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVerts*3, RC_ALLOC_PERM); + if (!mesh.verts) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3); + return false; + } + + mesh.npolys = 0; + mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys*2*mesh.nvp, RC_ALLOC_PERM); + if (!mesh.polys) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp); + return false; + } + memset(mesh.polys, 0xff, sizeof(unsigned short)*maxPolys*2*mesh.nvp); + + mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); + if (!mesh.regs) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys); + return false; + } + memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys); + + mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxPolys, RC_ALLOC_PERM); + if (!mesh.areas) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys); + return false; + } + memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys); + + mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); + if (!mesh.flags) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.flags' (%d).", maxPolys); + return false; + } + memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys); + + rcScopedDelete nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP); + if (!nextVert) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts); + return false; + } + memset(nextVert, 0, sizeof(int)*maxVerts); + + rcScopedDelete firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP); + if (!firstVert) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); + return false; + } + for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) + firstVert[i] = -1; + + rcScopedDelete vremap = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM); + if (!vremap) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh); + return false; + } + memset(vremap, 0, sizeof(unsigned short)*maxVertsPerMesh); + + for (int i = 0; i < nmeshes; ++i) + { + const rcPolyMesh* pmesh = meshes[i]; + + const unsigned short ox = (unsigned short)floorf((pmesh->bmin[0]-mesh.bmin[0])/mesh.cs+0.5f); + const unsigned short oz = (unsigned short)floorf((pmesh->bmin[2]-mesh.bmin[2])/mesh.cs+0.5f); + + for (int j = 0; j < pmesh->nverts; ++j) + { + unsigned short* v = &pmesh->verts[j*3]; + vremap[j] = addVertex(v[0]+ox, v[1], v[2]+oz, + mesh.verts, firstVert, nextVert, mesh.nverts); + } + + for (int j = 0; j < pmesh->npolys; ++j) + { + unsigned short* tgt = &mesh.polys[mesh.npolys*2*mesh.nvp]; + unsigned short* src = &pmesh->polys[j*2*mesh.nvp]; + mesh.regs[mesh.npolys] = pmesh->regs[j]; + mesh.areas[mesh.npolys] = pmesh->areas[j]; + mesh.flags[mesh.npolys] = pmesh->flags[j]; + mesh.npolys++; + for (int k = 0; k < mesh.nvp; ++k) + { + if (src[k] == RC_MESH_NULL_IDX) break; + tgt[k] = vremap[src[k]]; + } + } + } + + // Calculate adjacency. + if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp)) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed."); + return false; + } + + if (mesh.nverts > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); + } + if (mesh.npolys > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); + } + + ctx->stopTimer(RC_TIMER_MERGE_POLYMESH); + + return true; +} + +bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst) +{ + rcAssert(ctx); + + // Destination must be empty. + rcAssert(dst.verts == 0); + rcAssert(dst.polys == 0); + rcAssert(dst.regs == 0); + rcAssert(dst.areas == 0); + rcAssert(dst.flags == 0); + + dst.nverts = src.nverts; + dst.npolys = src.npolys; + dst.maxpolys = src.npolys; + dst.nvp = src.nvp; + rcVcopy(dst.bmin, src.bmin); + rcVcopy(dst.bmax, src.bmax); + dst.cs = src.cs; + dst.ch = src.ch; + dst.borderSize = src.borderSize; + + dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM); + if (!dst.verts) + { + ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.verts' (%d).", src.nverts*3); + return false; + } + memcpy(dst.verts, src.verts, sizeof(unsigned short)*src.nverts*3); + + dst.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys*2*src.nvp, RC_ALLOC_PERM); + if (!dst.polys) + { + ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.polys' (%d).", src.npolys*2*src.nvp); + return false; + } + memcpy(dst.polys, src.polys, sizeof(unsigned short)*src.npolys*2*src.nvp); + + dst.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM); + if (!dst.regs) + { + ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.regs' (%d).", src.npolys); + return false; + } + memcpy(dst.regs, src.regs, sizeof(unsigned short)*src.npolys); + + dst.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*src.npolys, RC_ALLOC_PERM); + if (!dst.areas) + { + ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.areas' (%d).", src.npolys); + return false; + } + memcpy(dst.areas, src.areas, sizeof(unsigned char)*src.npolys); + + dst.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM); + if (!dst.flags) + { + ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys); + return false; + } + memcpy(dst.flags, src.flags, sizeof(unsigned char)*src.npolys); + + return true; +} diff --git a/KREngine/3rdparty/recast/source/RecastMeshDetail.cpp b/KREngine/3rdparty/recast/source/RecastMeshDetail.cpp new file mode 100755 index 0000000..77438fd --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastMeshDetail.cpp @@ -0,0 +1,1245 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + + +static const unsigned RC_UNSET_HEIGHT = 0xffff; + +struct rcHeightPatch +{ + inline rcHeightPatch() : data(0), xmin(0), ymin(0), width(0), height(0) {} + inline ~rcHeightPatch() { rcFree(data); } + unsigned short* data; + int xmin, ymin, width, height; +}; + + +inline float vdot2(const float* a, const float* b) +{ + return a[0]*b[0] + a[2]*b[2]; +} + +inline float vdistSq2(const float* p, const float* q) +{ + const float dx = q[0] - p[0]; + const float dy = q[2] - p[2]; + return dx*dx + dy*dy; +} + +inline float vdist2(const float* p, const float* q) +{ + return sqrtf(vdistSq2(p,q)); +} + +inline float vcross2(const float* p1, const float* p2, const float* p3) +{ + const float u1 = p2[0] - p1[0]; + const float v1 = p2[2] - p1[2]; + const float u2 = p3[0] - p1[0]; + const float v2 = p3[2] - p1[2]; + return u1 * v2 - v1 * u2; +} + +static bool circumCircle(const float* p1, const float* p2, const float* p3, + float* c, float& r) +{ + static const float EPS = 1e-6f; + + const float cp = vcross2(p1, p2, p3); + if (fabsf(cp) > EPS) + { + const float p1Sq = vdot2(p1,p1); + const float p2Sq = vdot2(p2,p2); + const float p3Sq = vdot2(p3,p3); + c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp); + c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp); + r = vdist2(c, p1); + return true; + } + + c[0] = p1[0]; + c[2] = p1[2]; + r = 0; + return false; +} + +static float distPtTri(const float* p, const float* a, const float* b, const float* c) +{ + float v0[3], v1[3], v2[3]; + rcVsub(v0, c,a); + rcVsub(v1, b,a); + rcVsub(v2, p,a); + + const float dot00 = vdot2(v0, v0); + const float dot01 = vdot2(v0, v1); + const float dot02 = vdot2(v0, v2); + const float dot11 = vdot2(v1, v1); + const float dot12 = vdot2(v1, v2); + + // Compute barycentric coordinates + const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); + const float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // If point lies inside the triangle, return interpolated y-coord. + static const float EPS = 1e-4f; + if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS) + { + const float y = a[1] + v0[1]*u + v1[1]*v; + return fabsf(y-p[1]); + } + return FLT_MAX; +} + +static float distancePtSeg(const float* pt, const float* p, const float* q) +{ + float pqx = q[0] - p[0]; + float pqy = q[1] - p[1]; + float pqz = q[2] - p[2]; + float dx = pt[0] - p[0]; + float dy = pt[1] - p[1]; + float dz = pt[2] - p[2]; + float d = pqx*pqx + pqy*pqy + pqz*pqz; + float t = pqx*dx + pqy*dy + pqz*dz; + if (d > 0) + t /= d; + if (t < 0) + t = 0; + else if (t > 1) + t = 1; + + dx = p[0] + t*pqx - pt[0]; + dy = p[1] + t*pqy - pt[1]; + dz = p[2] + t*pqz - pt[2]; + + return dx*dx + dy*dy + dz*dz; +} + +static float distancePtSeg2d(const float* pt, const float* p, const float* q) +{ + float pqx = q[0] - p[0]; + float pqz = q[2] - p[2]; + float dx = pt[0] - p[0]; + float dz = pt[2] - p[2]; + float d = pqx*pqx + pqz*pqz; + float t = pqx*dx + pqz*dz; + if (d > 0) + t /= d; + if (t < 0) + t = 0; + else if (t > 1) + t = 1; + + dx = p[0] + t*pqx - pt[0]; + dz = p[2] + t*pqz - pt[2]; + + return dx*dx + dz*dz; +} + +static float distToTriMesh(const float* p, const float* verts, const int /*nverts*/, const int* tris, const int ntris) +{ + float dmin = FLT_MAX; + for (int i = 0; i < ntris; ++i) + { + const float* va = &verts[tris[i*4+0]*3]; + const float* vb = &verts[tris[i*4+1]*3]; + const float* vc = &verts[tris[i*4+2]*3]; + float d = distPtTri(p, va,vb,vc); + if (d < dmin) + dmin = d; + } + if (dmin == FLT_MAX) return -1; + return dmin; +} + +static float distToPoly(int nvert, const float* verts, const float* p) +{ + + float dmin = FLT_MAX; + int i, j, c = 0; + for (i = 0, j = nvert-1; i < nvert; j = i++) + { + const float* vi = &verts[i*3]; + const float* vj = &verts[j*3]; + if (((vi[2] > p[2]) != (vj[2] > p[2])) && + (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) ) + c = !c; + dmin = rcMin(dmin, distancePtSeg2d(p, vj, vi)); + } + return c ? -dmin : dmin; +} + + +static unsigned short getHeight(const float fx, const float fy, const float fz, + const float /*cs*/, const float ics, const float ch, + const rcHeightPatch& hp) +{ + int ix = (int)floorf(fx*ics + 0.01f); + int iz = (int)floorf(fz*ics + 0.01f); + ix = rcClamp(ix-hp.xmin, 0, hp.width - 1); + iz = rcClamp(iz-hp.ymin, 0, hp.height - 1); + unsigned short h = hp.data[ix+iz*hp.width]; + if (h == RC_UNSET_HEIGHT) + { + // Special case when data might be bad. + // Find nearest neighbour pixel which has valid height. + const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1}; + float dmin = FLT_MAX; + for (int i = 0; i < 8; ++i) + { + const int nx = ix+off[i*2+0]; + const int nz = iz+off[i*2+1]; + if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue; + const unsigned short nh = hp.data[nx+nz*hp.width]; + if (nh == RC_UNSET_HEIGHT) continue; + + const float d = fabsf(nh*ch - fy); + if (d < dmin) + { + h = nh; + dmin = d; + } + +/* const float dx = (nx+0.5f)*cs - fx; + const float dz = (nz+0.5f)*cs - fz; + const float d = dx*dx+dz*dz; + if (d < dmin) + { + h = nh; + dmin = d; + } */ + } + } + return h; +} + + +enum EdgeValues +{ + UNDEF = -1, + HULL = -2, +}; + +static int findEdge(const int* edges, int nedges, int s, int t) +{ + for (int i = 0; i < nedges; i++) + { + const int* e = &edges[i*4]; + if ((e[0] == s && e[1] == t) || (e[0] == t && e[1] == s)) + return i; + } + return UNDEF; +} + +static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r) +{ + if (nedges >= maxEdges) + { + ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges); + return UNDEF; + } + + // Add edge if not already in the triangulation. + int e = findEdge(edges, nedges, s, t); + if (e == UNDEF) + { + int* edge = &edges[nedges*4]; + edge[0] = s; + edge[1] = t; + edge[2] = l; + edge[3] = r; + return nedges++; + } + else + { + return UNDEF; + } +} + +static void updateLeftFace(int* e, int s, int t, int f) +{ + if (e[0] == s && e[1] == t && e[2] == UNDEF) + e[2] = f; + else if (e[1] == s && e[0] == t && e[3] == UNDEF) + e[3] = f; +} + +static int overlapSegSeg2d(const float* a, const float* b, const float* c, const float* d) +{ + const float a1 = vcross2(a, b, d); + const float a2 = vcross2(a, b, c); + if (a1*a2 < 0.0f) + { + float a3 = vcross2(c, d, a); + float a4 = a3 + a2 - a1; + if (a3 * a4 < 0.0f) + return 1; + } + return 0; +} + +static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1, int t1) +{ + for (int i = 0; i < nedges; ++i) + { + const int s0 = edges[i*4+0]; + const int t0 = edges[i*4+1]; + // Same or connected edges do not overlap. + if (s0 == s1 || s0 == t1 || t0 == s1 || t0 == t1) + continue; + if (overlapSegSeg2d(&pts[s0*3],&pts[t0*3], &pts[s1*3],&pts[t1*3])) + return true; + } + return false; +} + +static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e) +{ + static const float EPS = 1e-5f; + + int* edge = &edges[e*4]; + + // Cache s and t. + int s,t; + if (edge[2] == UNDEF) + { + s = edge[0]; + t = edge[1]; + } + else if (edge[3] == UNDEF) + { + s = edge[1]; + t = edge[0]; + } + else + { + // Edge already completed. + return; + } + + // Find best point on left of edge. + int pt = npts; + float c[3] = {0,0,0}; + float r = -1; + for (int u = 0; u < npts; ++u) + { + if (u == s || u == t) continue; + if (vcross2(&pts[s*3], &pts[t*3], &pts[u*3]) > EPS) + { + if (r < 0) + { + // The circle is not updated yet, do it now. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + continue; + } + const float d = vdist2(c, &pts[u*3]); + const float tol = 0.001f; + if (d > r*(1+tol)) + { + // Outside current circumcircle, skip. + continue; + } + else if (d < r*(1-tol)) + { + // Inside safe circumcircle, update circle. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + } + else + { + // Inside epsilon circum circle, do extra tests to make sure the edge is valid. + // s-u and t-u cannot overlap with s-pt nor t-pt if they exists. + if (overlapEdges(pts, edges, nedges, s,u)) + continue; + if (overlapEdges(pts, edges, nedges, t,u)) + continue; + // Edge is valid. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + } + } + } + + // Add new triangle or update edge info if s-t is on hull. + if (pt < npts) + { + // Update face information of edge being completed. + updateLeftFace(&edges[e*4], s, t, nfaces); + + // Add new edge or update face info of old edge. + e = findEdge(edges, nedges, pt, s); + if (e == UNDEF) + addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF); + else + updateLeftFace(&edges[e*4], pt, s, nfaces); + + // Add new edge or update face info of old edge. + e = findEdge(edges, nedges, t, pt); + if (e == UNDEF) + addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF); + else + updateLeftFace(&edges[e*4], t, pt, nfaces); + + nfaces++; + } + else + { + updateLeftFace(&edges[e*4], s, t, HULL); + } +} + +static void delaunayHull(rcContext* ctx, const int npts, const float* pts, + const int nhull, const int* hull, + rcIntArray& tris, rcIntArray& edges) +{ + int nfaces = 0; + int nedges = 0; + const int maxEdges = npts*10; + edges.resize(maxEdges*4); + + for (int i = 0, j = nhull-1; i < nhull; j=i++) + addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF); + + int currentEdge = 0; + while (currentEdge < nedges) + { + if (edges[currentEdge*4+2] == UNDEF) + completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); + if (edges[currentEdge*4+3] == UNDEF) + completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); + currentEdge++; + } + + // Create tris + tris.resize(nfaces*4); + for (int i = 0; i < nfaces*4; ++i) + tris[i] = -1; + + for (int i = 0; i < nedges; ++i) + { + const int* e = &edges[i*4]; + if (e[3] >= 0) + { + // Left face + int* t = &tris[e[3]*4]; + if (t[0] == -1) + { + t[0] = e[0]; + t[1] = e[1]; + } + else if (t[0] == e[1]) + t[2] = e[0]; + else if (t[1] == e[0]) + t[2] = e[1]; + } + if (e[2] >= 0) + { + // Right + int* t = &tris[e[2]*4]; + if (t[0] == -1) + { + t[0] = e[1]; + t[1] = e[0]; + } + else if (t[0] == e[0]) + t[2] = e[1]; + else if (t[1] == e[1]) + t[2] = e[0]; + } + } + + for (int i = 0; i < tris.size()/4; ++i) + { + int* t = &tris[i*4]; + if (t[0] == -1 || t[1] == -1 || t[2] == -1) + { + ctx->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]); + t[0] = tris[tris.size()-4]; + t[1] = tris[tris.size()-3]; + t[2] = tris[tris.size()-2]; + t[3] = tris[tris.size()-1]; + tris.resize(tris.size()-4); + --i; + } + } +} + + +inline float getJitterX(const int i) +{ + return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f; +} + +inline float getJitterY(const int i) +{ + return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f; +} + +static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin, + const float sampleDist, const float sampleMaxError, + const rcCompactHeightfield& chf, const rcHeightPatch& hp, + float* verts, int& nverts, rcIntArray& tris, + rcIntArray& edges, rcIntArray& samples) +{ + static const int MAX_VERTS = 127; + static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts). + static const int MAX_VERTS_PER_EDGE = 32; + float edge[(MAX_VERTS_PER_EDGE+1)*3]; + int hull[MAX_VERTS]; + int nhull = 0; + + nverts = 0; + + for (int i = 0; i < nin; ++i) + rcVcopy(&verts[i*3], &in[i*3]); + nverts = nin; + + const float cs = chf.cs; + const float ics = 1.0f/cs; + + // Tessellate outlines. + // This is done in separate pass in order to ensure + // seamless height values across the ply boundaries. + if (sampleDist > 0) + { + for (int i = 0, j = nin-1; i < nin; j=i++) + { + const float* vj = &in[j*3]; + const float* vi = &in[i*3]; + bool swapped = false; + // Make sure the segments are always handled in same order + // using lexological sort or else there will be seams. + if (fabsf(vj[0]-vi[0]) < 1e-6f) + { + if (vj[2] > vi[2]) + { + rcSwap(vj,vi); + swapped = true; + } + } + else + { + if (vj[0] > vi[0]) + { + rcSwap(vj,vi); + swapped = true; + } + } + // Create samples along the edge. + float dx = vi[0] - vj[0]; + float dy = vi[1] - vj[1]; + float dz = vi[2] - vj[2]; + float d = sqrtf(dx*dx + dz*dz); + int nn = 1 + (int)floorf(d/sampleDist); + if (nn >= MAX_VERTS_PER_EDGE) nn = MAX_VERTS_PER_EDGE-1; + if (nverts+nn >= MAX_VERTS) + nn = MAX_VERTS-1-nverts; + + for (int k = 0; k <= nn; ++k) + { + float u = (float)k/(float)nn; + float* pos = &edge[k*3]; + pos[0] = vj[0] + dx*u; + pos[1] = vj[1] + dy*u; + pos[2] = vj[2] + dz*u; + pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch; + } + // Simplify samples. + int idx[MAX_VERTS_PER_EDGE] = {0,nn}; + int nidx = 2; + for (int k = 0; k < nidx-1; ) + { + const int a = idx[k]; + const int b = idx[k+1]; + const float* va = &edge[a*3]; + const float* vb = &edge[b*3]; + // Find maximum deviation along the segment. + float maxd = 0; + int maxi = -1; + for (int m = a+1; m < b; ++m) + { + float dev = distancePtSeg(&edge[m*3],va,vb); + if (dev > maxd) + { + maxd = dev; + maxi = m; + } + } + // If the max deviation is larger than accepted error, + // add new point, else continue to next segment. + if (maxi != -1 && maxd > rcSqr(sampleMaxError)) + { + for (int m = nidx; m > k; --m) + idx[m] = idx[m-1]; + idx[k+1] = maxi; + nidx++; + } + else + { + ++k; + } + } + + hull[nhull++] = j; + // Add new vertices. + if (swapped) + { + for (int k = nidx-2; k > 0; --k) + { + rcVcopy(&verts[nverts*3], &edge[idx[k]*3]); + hull[nhull++] = nverts; + nverts++; + } + } + else + { + for (int k = 1; k < nidx-1; ++k) + { + rcVcopy(&verts[nverts*3], &edge[idx[k]*3]); + hull[nhull++] = nverts; + nverts++; + } + } + } + } + + + // Tessellate the base mesh. + edges.resize(0); + tris.resize(0); + + delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges); + + if (tris.size() == 0) + { + // Could not triangulate the poly, make sure there is some valid data there. + ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data."); + for (int i = 2; i < nverts; ++i) + { + tris.push(0); + tris.push(i-1); + tris.push(i); + tris.push(0); + } + return true; + } + + if (sampleDist > 0) + { + // Create sample locations in a grid. + float bmin[3], bmax[3]; + rcVcopy(bmin, in); + rcVcopy(bmax, in); + for (int i = 1; i < nin; ++i) + { + rcVmin(bmin, &in[i*3]); + rcVmax(bmax, &in[i*3]); + } + int x0 = (int)floorf(bmin[0]/sampleDist); + int x1 = (int)ceilf(bmax[0]/sampleDist); + int z0 = (int)floorf(bmin[2]/sampleDist); + int z1 = (int)ceilf(bmax[2]/sampleDist); + samples.resize(0); + for (int z = z0; z < z1; ++z) + { + for (int x = x0; x < x1; ++x) + { + float pt[3]; + pt[0] = x*sampleDist; + pt[1] = (bmax[1]+bmin[1])*0.5f; + pt[2] = z*sampleDist; + // Make sure the samples are not too close to the edges. + if (distToPoly(nin,in,pt) > -sampleDist/2) continue; + samples.push(x); + samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp)); + samples.push(z); + samples.push(0); // Not added + } + } + + // Add the samples starting from the one that has the most + // error. The procedure stops when all samples are added + // or when the max error is within treshold. + const int nsamples = samples.size()/4; + for (int iter = 0; iter < nsamples; ++iter) + { + if (nverts >= MAX_VERTS) + break; + + // Find sample with most error. + float bestpt[3] = {0,0,0}; + float bestd = 0; + int besti = -1; + for (int i = 0; i < nsamples; ++i) + { + const int* s = &samples[i*4]; + if (s[3]) continue; // skip added. + float pt[3]; + // The sample location is jittered to get rid of some bad triangulations + // which are cause by symmetrical data from the grid structure. + pt[0] = s[0]*sampleDist + getJitterX(i)*cs*0.1f; + pt[1] = s[1]*chf.ch; + pt[2] = s[2]*sampleDist + getJitterY(i)*cs*0.1f; + float d = distToTriMesh(pt, verts, nverts, &tris[0], tris.size()/4); + if (d < 0) continue; // did not hit the mesh. + if (d > bestd) + { + bestd = d; + besti = i; + rcVcopy(bestpt,pt); + } + } + // If the max error is within accepted threshold, stop tesselating. + if (bestd <= sampleMaxError || besti == -1) + break; + // Mark sample as added. + samples[besti*4+3] = 1; + // Add the new sample point. + rcVcopy(&verts[nverts*3],bestpt); + nverts++; + + // Create new triangulation. + // TODO: Incremental add instead of full rebuild. + edges.resize(0); + tris.resize(0); + delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges); + } + } + + const int ntris = tris.size()/4; + if (ntris > MAX_TRIS) + { + tris.resize(MAX_TRIS*4); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS); + } + + return true; +} + +static void getHeightData(const rcCompactHeightfield& chf, + const unsigned short* poly, const int npoly, + const unsigned short* verts, const int bs, + rcHeightPatch& hp, rcIntArray& stack) +{ + // Floodfill the heightfield to get 2D height data, + // starting at vertex locations as seeds. + + // Note: Reads to the compact heightfield are offset by border size (bs) + // since border size offset is already removed from the polymesh vertices. + + memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height); + + stack.resize(0); + + static const int offset[9*2] = + { + 0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0, + }; + + // Use poly vertices as seed points for the flood fill. + for (int j = 0; j < npoly; ++j) + { + int cx = 0, cz = 0, ci =-1; + int dmin = RC_UNSET_HEIGHT; + for (int k = 0; k < 9; ++k) + { + const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0]; + const int ay = (int)verts[poly[j]*3+1]; + const int az = (int)verts[poly[j]*3+2] + offset[k*2+1]; + if (ax < hp.xmin || ax >= hp.xmin+hp.width || + az < hp.ymin || az >= hp.ymin+hp.height) + continue; + + const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + int d = rcAbs(ay - (int)s.y); + if (d < dmin) + { + cx = ax; + cz = az; + ci = i; + dmin = d; + } + } + } + if (ci != -1) + { + stack.push(cx); + stack.push(cz); + stack.push(ci); + } + } + + // Find center of the polygon using flood fill. + int pcx = 0, pcz = 0; + for (int j = 0; j < npoly; ++j) + { + pcx += (int)verts[poly[j]*3+0]; + pcz += (int)verts[poly[j]*3+2]; + } + pcx /= npoly; + pcz /= npoly; + + for (int i = 0; i < stack.size(); i += 3) + { + int cx = stack[i+0]; + int cy = stack[i+1]; + int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width; + hp.data[idx] = 1; + } + + while (stack.size() > 0) + { + int ci = stack.pop(); + int cy = stack.pop(); + int cx = stack.pop(); + + // Check if close to center of the polygon. + if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1) + { + stack.resize(0); + stack.push(cx); + stack.push(cy); + stack.push(ci); + break; + } + + const rcCompactSpan& cs = chf.spans[ci]; + + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue; + + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + + if (ax < hp.xmin || ax >= (hp.xmin+hp.width) || + ay < hp.ymin || ay >= (hp.ymin+hp.height)) + continue; + + if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0) + continue; + + const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); + + int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; + hp.data[idx] = 1; + + stack.push(ax); + stack.push(ay); + stack.push(ai); + } + } + + memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height); + + // Mark start locations. + for (int i = 0; i < stack.size(); i += 3) + { + int cx = stack[i+0]; + int cy = stack[i+1]; + int ci = stack[i+2]; + int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width; + const rcCompactSpan& cs = chf.spans[ci]; + hp.data[idx] = cs.y; + } + + static const int RETRACT_SIZE = 256; + int head = 0; + + while (head*3 < stack.size()) + { + int cx = stack[head*3+0]; + int cy = stack[head*3+1]; + int ci = stack[head*3+2]; + head++; + if (head >= RETRACT_SIZE) + { + head = 0; + if (stack.size() > RETRACT_SIZE*3) + memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3)); + stack.resize(stack.size()-RETRACT_SIZE*3); + } + + const rcCompactSpan& cs = chf.spans[ci]; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue; + + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + + if (ax < hp.xmin || ax >= (hp.xmin+hp.width) || + ay < hp.ymin || ay >= (hp.ymin+hp.height)) + continue; + + if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT) + continue; + + const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); + + const rcCompactSpan& as = chf.spans[ai]; + int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; + hp.data[idx] = as.y; + + stack.push(ax); + stack.push(ay); + stack.push(ai); + } + } + +} + +static unsigned char getEdgeFlags(const float* va, const float* vb, + const float* vpoly, const int npoly) +{ + // Return true if edge (va,vb) is part of the polygon. + static const float thrSqr = rcSqr(0.001f); + for (int i = 0, j = npoly-1; i < npoly; j=i++) + { + if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr && + distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr) + return 1; + } + return 0; +} + +static unsigned char getTriFlags(const float* va, const float* vb, const float* vc, + const float* vpoly, const int npoly) +{ + unsigned char flags = 0; + flags |= getEdgeFlags(va,vb,vpoly,npoly) << 0; + flags |= getEdgeFlags(vb,vc,vpoly,npoly) << 2; + flags |= getEdgeFlags(vc,va,vpoly,npoly) << 4; + return flags; +} + +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig +bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, + const float sampleDist, const float sampleMaxError, + rcPolyMeshDetail& dmesh) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL); + + if (mesh.nverts == 0 || mesh.npolys == 0) + return true; + + const int nvp = mesh.nvp; + const float cs = mesh.cs; + const float ch = mesh.ch; + const float* orig = mesh.bmin; + const int borderSize = mesh.borderSize; + + rcIntArray edges(64); + rcIntArray tris(512); + rcIntArray stack(512); + rcIntArray samples(512); + float verts[256*3]; + rcHeightPatch hp; + int nPolyVerts = 0; + int maxhw = 0, maxhh = 0; + + rcScopedDelete bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP); + if (!bounds) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4); + return false; + } + rcScopedDelete poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP); + if (!poly) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3); + return false; + } + + // Find max size for a polygon area. + for (int i = 0; i < mesh.npolys; ++i) + { + const unsigned short* p = &mesh.polys[i*nvp*2]; + int& xmin = bounds[i*4+0]; + int& xmax = bounds[i*4+1]; + int& ymin = bounds[i*4+2]; + int& ymax = bounds[i*4+3]; + xmin = chf.width; + xmax = 0; + ymin = chf.height; + ymax = 0; + for (int j = 0; j < nvp; ++j) + { + if(p[j] == RC_MESH_NULL_IDX) break; + const unsigned short* v = &mesh.verts[p[j]*3]; + xmin = rcMin(xmin, (int)v[0]); + xmax = rcMax(xmax, (int)v[0]); + ymin = rcMin(ymin, (int)v[2]); + ymax = rcMax(ymax, (int)v[2]); + nPolyVerts++; + } + xmin = rcMax(0,xmin-1); + xmax = rcMin(chf.width,xmax+1); + ymin = rcMax(0,ymin-1); + ymax = rcMin(chf.height,ymax+1); + if (xmin >= xmax || ymin >= ymax) continue; + maxhw = rcMax(maxhw, xmax-xmin); + maxhh = rcMax(maxhh, ymax-ymin); + } + + hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP); + if (!hp.data) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh); + return false; + } + + dmesh.nmeshes = mesh.npolys; + dmesh.nverts = 0; + dmesh.ntris = 0; + dmesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*dmesh.nmeshes*4, RC_ALLOC_PERM); + if (!dmesh.meshes) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4); + return false; + } + + int vcap = nPolyVerts+nPolyVerts/2; + int tcap = vcap*2; + + dmesh.nverts = 0; + dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); + if (!dmesh.verts) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3); + return false; + } + dmesh.ntris = 0; + dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM); + if (!dmesh.tris) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4); + return false; + } + + for (int i = 0; i < mesh.npolys; ++i) + { + const unsigned short* p = &mesh.polys[i*nvp*2]; + + // Store polygon vertices for processing. + int npoly = 0; + for (int j = 0; j < nvp; ++j) + { + if(p[j] == RC_MESH_NULL_IDX) break; + const unsigned short* v = &mesh.verts[p[j]*3]; + poly[j*3+0] = v[0]*cs; + poly[j*3+1] = v[1]*ch; + poly[j*3+2] = v[2]*cs; + npoly++; + } + + // Get the height data from the area of the polygon. + hp.xmin = bounds[i*4+0]; + hp.ymin = bounds[i*4+2]; + hp.width = bounds[i*4+1]-bounds[i*4+0]; + hp.height = bounds[i*4+3]-bounds[i*4+2]; + getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack); + + // Build detail mesh. + int nverts = 0; + if (!buildPolyDetail(ctx, poly, npoly, + sampleDist, sampleMaxError, + chf, hp, verts, nverts, tris, + edges, samples)) + { + return false; + } + + // Move detail verts to world space. + for (int j = 0; j < nverts; ++j) + { + verts[j*3+0] += orig[0]; + verts[j*3+1] += orig[1] + chf.ch; // Is this offset necessary? + verts[j*3+2] += orig[2]; + } + // Offset poly too, will be used to flag checking. + for (int j = 0; j < npoly; ++j) + { + poly[j*3+0] += orig[0]; + poly[j*3+1] += orig[1]; + poly[j*3+2] += orig[2]; + } + + // Store detail submesh. + const int ntris = tris.size()/4; + + dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts; + dmesh.meshes[i*4+1] = (unsigned int)nverts; + dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris; + dmesh.meshes[i*4+3] = (unsigned int)ntris; + + // Store vertices, allocate more memory if necessary. + if (dmesh.nverts+nverts > vcap) + { + while (dmesh.nverts+nverts > vcap) + vcap += 256; + + float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); + if (!newv) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3); + return false; + } + if (dmesh.nverts) + memcpy(newv, dmesh.verts, sizeof(float)*3*dmesh.nverts); + rcFree(dmesh.verts); + dmesh.verts = newv; + } + for (int j = 0; j < nverts; ++j) + { + dmesh.verts[dmesh.nverts*3+0] = verts[j*3+0]; + dmesh.verts[dmesh.nverts*3+1] = verts[j*3+1]; + dmesh.verts[dmesh.nverts*3+2] = verts[j*3+2]; + dmesh.nverts++; + } + + // Store triangles, allocate more memory if necessary. + if (dmesh.ntris+ntris > tcap) + { + while (dmesh.ntris+ntris > tcap) + tcap += 256; + unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM); + if (!newt) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4); + return false; + } + if (dmesh.ntris) + memcpy(newt, dmesh.tris, sizeof(unsigned char)*4*dmesh.ntris); + rcFree(dmesh.tris); + dmesh.tris = newt; + } + for (int j = 0; j < ntris; ++j) + { + const int* t = &tris[j*4]; + dmesh.tris[dmesh.ntris*4+0] = (unsigned char)t[0]; + dmesh.tris[dmesh.ntris*4+1] = (unsigned char)t[1]; + dmesh.tris[dmesh.ntris*4+2] = (unsigned char)t[2]; + dmesh.tris[dmesh.ntris*4+3] = getTriFlags(&verts[t[0]*3], &verts[t[1]*3], &verts[t[2]*3], poly, npoly); + dmesh.ntris++; + } + } + + ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL); + + return true; +} + +/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail +bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL); + + int maxVerts = 0; + int maxTris = 0; + int maxMeshes = 0; + + for (int i = 0; i < nmeshes; ++i) + { + if (!meshes[i]) continue; + maxVerts += meshes[i]->nverts; + maxTris += meshes[i]->ntris; + maxMeshes += meshes[i]->nmeshes; + } + + mesh.nmeshes = 0; + mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM); + if (!mesh.meshes) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4); + return false; + } + + mesh.ntris = 0; + mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM); + if (!mesh.tris) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4); + return false; + } + + mesh.nverts = 0; + mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM); + if (!mesh.verts) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3); + return false; + } + + // Merge datas. + for (int i = 0; i < nmeshes; ++i) + { + rcPolyMeshDetail* dm = meshes[i]; + if (!dm) continue; + for (int j = 0; j < dm->nmeshes; ++j) + { + unsigned int* dst = &mesh.meshes[mesh.nmeshes*4]; + unsigned int* src = &dm->meshes[j*4]; + dst[0] = (unsigned int)mesh.nverts+src[0]; + dst[1] = src[1]; + dst[2] = (unsigned int)mesh.ntris+src[2]; + dst[3] = src[3]; + mesh.nmeshes++; + } + + for (int k = 0; k < dm->nverts; ++k) + { + rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]); + mesh.nverts++; + } + for (int k = 0; k < dm->ntris; ++k) + { + mesh.tris[mesh.ntris*4+0] = dm->tris[k*4+0]; + mesh.tris[mesh.ntris*4+1] = dm->tris[k*4+1]; + mesh.tris[mesh.ntris*4+2] = dm->tris[k*4+2]; + mesh.tris[mesh.ntris*4+3] = dm->tris[k*4+3]; + mesh.ntris++; + } + } + + ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL); + + return true; +} + diff --git a/KREngine/3rdparty/recast/source/RecastRasterization.cpp b/KREngine/3rdparty/recast/source/RecastRasterization.cpp new file mode 100755 index 0000000..d2bb7c9 --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastRasterization.cpp @@ -0,0 +1,387 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#define _USE_MATH_DEFINES +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + +inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax) +{ + bool overlap = true; + overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; + overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap; + overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap; + return overlap; +} + +inline bool overlapInterval(unsigned short amin, unsigned short amax, + unsigned short bmin, unsigned short bmax) +{ + if (amax < bmin) return false; + if (amin > bmax) return false; + return true; +} + + +static rcSpan* allocSpan(rcHeightfield& hf) +{ + // If running out of memory, allocate new page and update the freelist. + if (!hf.freelist || !hf.freelist->next) + { + // Create new page. + // Allocate memory for the new pool. + rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM); + if (!pool) return 0; + pool->next = 0; + // Add the pool into the list of pools. + pool->next = hf.pools; + hf.pools = pool; + // Add new items to the free list. + rcSpan* freelist = hf.freelist; + rcSpan* head = &pool->items[0]; + rcSpan* it = &pool->items[RC_SPANS_PER_POOL]; + do + { + --it; + it->next = freelist; + freelist = it; + } + while (it != head); + hf.freelist = it; + } + + // Pop item from in front of the free list. + rcSpan* it = hf.freelist; + hf.freelist = hf.freelist->next; + return it; +} + +static void freeSpan(rcHeightfield& hf, rcSpan* ptr) +{ + if (!ptr) return; + // Add the node in front of the free list. + ptr->next = hf.freelist; + hf.freelist = ptr; +} + +static void addSpan(rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr) +{ + + int idx = x + y*hf.width; + + rcSpan* s = allocSpan(hf); + s->smin = smin; + s->smax = smax; + s->area = area; + s->next = 0; + + // Empty cell, add he first span. + if (!hf.spans[idx]) + { + hf.spans[idx] = s; + return; + } + rcSpan* prev = 0; + rcSpan* cur = hf.spans[idx]; + + // Insert and merge spans. + while (cur) + { + if (cur->smin > s->smax) + { + // Current span is further than the new span, break. + break; + } + else if (cur->smax < s->smin) + { + // Current span is before the new span advance. + prev = cur; + cur = cur->next; + } + else + { + // Merge spans. + if (cur->smin < s->smin) + s->smin = cur->smin; + if (cur->smax > s->smax) + s->smax = cur->smax; + + // Merge flags. + if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr) + s->area = rcMax(s->area, cur->area); + + // Remove current span. + rcSpan* next = cur->next; + freeSpan(hf, cur); + if (prev) + prev->next = next; + else + hf.spans[idx] = next; + cur = next; + } + } + + // Insert new span. + if (prev) + { + s->next = prev->next; + prev->next = s; + } + else + { + s->next = hf.spans[idx]; + hf.spans[idx] = s; + } +} + +/// @par +/// +/// The span addition can be set to favor flags. If the span is merged to +/// another span and the new @p smax is within @p flagMergeThr units +/// from the existing span, the span flags are merged. +/// +/// @see rcHeightfield, rcSpan. +void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr) +{ +// rcAssert(ctx); + addSpan(hf, x,y, smin, smax, area, flagMergeThr); +} + +static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd) +{ + float d[12]; + for (int i = 0; i < n; ++i) + d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd; + + int m = 0; + for (int i = 0, j = n-1; i < n; j=i, ++i) + { + bool ina = d[j] >= 0; + bool inb = d[i] >= 0; + if (ina != inb) + { + float s = d[j] / (d[j] - d[i]); + out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s; + out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s; + out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s; + m++; + } + if (inb) + { + out[m*3+0] = in[i*3+0]; + out[m*3+1] = in[i*3+1]; + out[m*3+2] = in[i*3+2]; + m++; + } + } + return m; +} + +static void rasterizeTri(const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& hf, + const float* bmin, const float* bmax, + const float cs, const float ics, const float ich, + const int flagMergeThr) +{ + const int w = hf.width; + const int h = hf.height; + float tmin[3], tmax[3]; + const float by = bmax[1] - bmin[1]; + + // Calculate the bounding box of the triangle. + rcVcopy(tmin, v0); + rcVcopy(tmax, v0); + rcVmin(tmin, v1); + rcVmin(tmin, v2); + rcVmax(tmax, v1); + rcVmax(tmax, v2); + + // If the triangle does not touch the bbox of the heightfield, skip the triagle. + if (!overlapBounds(bmin, bmax, tmin, tmax)) + return; + + // Calculate the footpring of the triangle on the grid. + int x0 = (int)((tmin[0] - bmin[0])*ics); + int y0 = (int)((tmin[2] - bmin[2])*ics); + int x1 = (int)((tmax[0] - bmin[0])*ics); + int y1 = (int)((tmax[2] - bmin[2])*ics); + x0 = rcClamp(x0, 0, w-1); + y0 = rcClamp(y0, 0, h-1); + x1 = rcClamp(x1, 0, w-1); + y1 = rcClamp(y1, 0, h-1); + + // Clip the triangle into all grid cells it touches. + float in[7*3], out[7*3], inrow[7*3]; + + for (int y = y0; y <= y1; ++y) + { + // Clip polygon to row. + rcVcopy(&in[0], v0); + rcVcopy(&in[1*3], v1); + rcVcopy(&in[2*3], v2); + int nvrow = 3; + const float cz = bmin[2] + y*cs; + nvrow = clipPoly(in, nvrow, out, 0, 1, -cz); + if (nvrow < 3) continue; + nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs); + if (nvrow < 3) continue; + + for (int x = x0; x <= x1; ++x) + { + // Clip polygon to column. + int nv = nvrow; + const float cx = bmin[0] + x*cs; + nv = clipPoly(inrow, nv, out, 1, 0, -cx); + if (nv < 3) continue; + nv = clipPoly(out, nv, in, -1, 0, cx+cs); + if (nv < 3) continue; + + // Calculate min and max of the span. + float smin = in[1], smax = in[1]; + for (int i = 1; i < nv; ++i) + { + smin = rcMin(smin, in[i*3+1]); + smax = rcMax(smax, in[i*3+1]); + } + smin -= bmin[1]; + smax -= bmin[1]; + // Skip the span if it is outside the heightfield bbox + if (smax < 0.0f) continue; + if (smin > by) continue; + // Clamp the span to the heightfield bbox. + if (smin < 0.0f) smin = 0; + if (smax > by) smax = by; + + // Snap the span to the heightfield height grid. + unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT); + unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT); + + addSpan(hf, x, y, ismin, ismax, area, flagMergeThr); + } + } +} + +/// @par +/// +/// No spans will be added if the triangle does not overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& solid, + const int flagMergeThr) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} + +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, + const int* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + // Rasterize triangles. + for (int i = 0; i < nt; ++i) + { + const float* v0 = &verts[tris[i*3+0]*3]; + const float* v1 = &verts[tris[i*3+1]*3]; + const float* v2 = &verts[tris[i*3+2]*3]; + // Rasterize. + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + } + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} + +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, + const unsigned short* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + // Rasterize triangles. + for (int i = 0; i < nt; ++i) + { + const float* v0 = &verts[tris[i*3+0]*3]; + const float* v1 = &verts[tris[i*3+1]*3]; + const float* v2 = &verts[tris[i*3+2]*3]; + // Rasterize. + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + } + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} + +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + // Rasterize triangles. + for (int i = 0; i < nt; ++i) + { + const float* v0 = &verts[(i*3+0)*3]; + const float* v1 = &verts[(i*3+1)*3]; + const float* v2 = &verts[(i*3+2)*3]; + // Rasterize. + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + } + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} diff --git a/KREngine/3rdparty/recast/source/RecastRegion.cpp b/KREngine/3rdparty/recast/source/RecastRegion.cpp new file mode 100755 index 0000000..76e631c --- /dev/null +++ b/KREngine/3rdparty/recast/source/RecastRegion.cpp @@ -0,0 +1,1337 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// 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. +// + +#include +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" +#include + + +static void calculateDistanceField(rcCompactHeightfield& chf, unsigned short* src, unsigned short& maxDist) +{ + const int w = chf.width; + const int h = chf.height; + + // Init distance and points. + for (int i = 0; i < chf.spanCount; ++i) + src[i] = 0xffff; + + // Mark boundary cells. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + const unsigned char area = chf.areas[i]; + + int nc = 0; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + if (area == chf.areas[ai]) + nc++; + } + } + if (nc != 4) + src[i] = 0; + } + } + } + + + // Pass 1 + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + // (-1,0) + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + const rcCompactSpan& as = chf.spans[ai]; + if (src[ai]+2 < src[i]) + src[i] = src[ai]+2; + + // (-1,-1) + if (rcGetCon(as, 3) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(3); + const int aay = ay + rcGetDirOffsetY(3); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3); + if (src[aai]+3 < src[i]) + src[i] = src[aai]+3; + } + } + if (rcGetCon(s, 3) != RC_NOT_CONNECTED) + { + // (0,-1) + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + const rcCompactSpan& as = chf.spans[ai]; + if (src[ai]+2 < src[i]) + src[i] = src[ai]+2; + + // (1,-1) + if (rcGetCon(as, 2) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(2); + const int aay = ay + rcGetDirOffsetY(2); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2); + if (src[aai]+3 < src[i]) + src[i] = src[aai]+3; + } + } + } + } + } + + // Pass 2 + for (int y = h-1; y >= 0; --y) + { + for (int x = w-1; x >= 0; --x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 2) != RC_NOT_CONNECTED) + { + // (1,0) + const int ax = x + rcGetDirOffsetX(2); + const int ay = y + rcGetDirOffsetY(2); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2); + const rcCompactSpan& as = chf.spans[ai]; + if (src[ai]+2 < src[i]) + src[i] = src[ai]+2; + + // (1,1) + if (rcGetCon(as, 1) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(1); + const int aay = ay + rcGetDirOffsetY(1); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1); + if (src[aai]+3 < src[i]) + src[i] = src[aai]+3; + } + } + if (rcGetCon(s, 1) != RC_NOT_CONNECTED) + { + // (0,1) + const int ax = x + rcGetDirOffsetX(1); + const int ay = y + rcGetDirOffsetY(1); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1); + const rcCompactSpan& as = chf.spans[ai]; + if (src[ai]+2 < src[i]) + src[i] = src[ai]+2; + + // (-1,1) + if (rcGetCon(as, 0) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(0); + const int aay = ay + rcGetDirOffsetY(0); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0); + if (src[aai]+3 < src[i]) + src[i] = src[aai]+3; + } + } + } + } + } + + maxDist = 0; + for (int i = 0; i < chf.spanCount; ++i) + maxDist = rcMax(src[i], maxDist); + +} + +static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr, + unsigned short* src, unsigned short* dst) +{ + const int w = chf.width; + const int h = chf.height; + + thr *= 2; + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + const unsigned short cd = src[i]; + if (cd <= thr) + { + dst[i] = cd; + continue; + } + + int d = (int)cd; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + d += (int)src[ai]; + + const rcCompactSpan& as = chf.spans[ai]; + const int dir2 = (dir+1) & 0x3; + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dir2); + const int ay2 = ay + rcGetDirOffsetY(dir2); + const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); + d += (int)src[ai2]; + } + else + { + d += cd; + } + } + else + { + d += cd*2; + } + } + dst[i] = (unsigned short)((d+5)/9); + } + } + } + return dst; +} + + +static bool floodRegion(int x, int y, int i, + unsigned short level, unsigned short r, + rcCompactHeightfield& chf, + unsigned short* srcReg, unsigned short* srcDist, + rcIntArray& stack) +{ + const int w = chf.width; + + const unsigned char area = chf.areas[i]; + + // Flood fill mark region. + stack.resize(0); + stack.push((int)x); + stack.push((int)y); + stack.push((int)i); + srcReg[i] = r; + srcDist[i] = 0; + + unsigned short lev = level >= 2 ? level-2 : 0; + int count = 0; + + while (stack.size() > 0) + { + int ci = stack.pop(); + int cy = stack.pop(); + int cx = stack.pop(); + + const rcCompactSpan& cs = chf.spans[ci]; + + // Check if any of the neighbours already have a valid region set. + unsigned short ar = 0; + for (int dir = 0; dir < 4; ++dir) + { + // 8 connected + if (rcGetCon(cs, dir) != RC_NOT_CONNECTED) + { + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir); + if (chf.areas[ai] != area) + continue; + unsigned short nr = srcReg[ai]; + if (nr & RC_BORDER_REG) // Do not take borders into account. + continue; + if (nr != 0 && nr != r) + ar = nr; + + const rcCompactSpan& as = chf.spans[ai]; + + const int dir2 = (dir+1) & 0x3; + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dir2); + const int ay2 = ay + rcGetDirOffsetY(dir2); + const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); + if (chf.areas[ai2] != area) + continue; + unsigned short nr2 = srcReg[ai2]; + if (nr2 != 0 && nr2 != r) + ar = nr2; + } + } + } + if (ar != 0) + { + srcReg[ci] = 0; + continue; + } + count++; + + // Expand neighbours. + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(cs, dir) != RC_NOT_CONNECTED) + { + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir); + if (chf.areas[ai] != area) + continue; + if (chf.dist[ai] >= lev && srcReg[ai] == 0) + { + srcReg[ai] = r; + srcDist[ai] = 0; + stack.push(ax); + stack.push(ay); + stack.push(ai); + } + } + } + } + + return count > 0; +} + +static unsigned short* expandRegions(int maxIter, unsigned short level, + rcCompactHeightfield& chf, + unsigned short* srcReg, unsigned short* srcDist, + unsigned short* dstReg, unsigned short* dstDist, + rcIntArray& stack) +{ + const int w = chf.width; + const int h = chf.height; + + // Find cells revealed by the raised level. + stack.resize(0); + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA) + { + stack.push(x); + stack.push(y); + stack.push(i); + } + } + } + } + + int iter = 0; + while (stack.size() > 0) + { + int failed = 0; + + memcpy(dstReg, srcReg, sizeof(unsigned short)*chf.spanCount); + memcpy(dstDist, srcDist, sizeof(unsigned short)*chf.spanCount); + + for (int j = 0; j < stack.size(); j += 3) + { + int x = stack[j+0]; + int y = stack[j+1]; + int i = stack[j+2]; + if (i < 0) + { + failed++; + continue; + } + + unsigned short r = srcReg[i]; + unsigned short d2 = 0xffff; + const unsigned char area = chf.areas[i]; + const rcCompactSpan& s = chf.spans[i]; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) == RC_NOT_CONNECTED) continue; + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + if (chf.areas[ai] != area) continue; + if (srcReg[ai] > 0 && (srcReg[ai] & RC_BORDER_REG) == 0) + { + if ((int)srcDist[ai]+2 < (int)d2) + { + r = srcReg[ai]; + d2 = srcDist[ai]+2; + } + } + } + if (r) + { + stack[j+2] = -1; // mark as used + dstReg[i] = r; + dstDist[i] = d2; + } + else + { + failed++; + } + } + + // rcSwap source and dest. + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); + + if (failed*3 == stack.size()) + break; + + if (level > 0) + { + ++iter; + if (iter >= maxIter) + break; + } + } + + return srcReg; +} + + +struct rcRegion +{ + inline rcRegion(unsigned short i) : + spanCount(0), + id(i), + areaType(0), + remap(false), + visited(false) + {} + + int spanCount; // Number of spans belonging to this region + unsigned short id; // ID of the region + unsigned char areaType; // Are type. + bool remap; + bool visited; + rcIntArray connections; + rcIntArray floors; +}; + +static void removeAdjacentNeighbours(rcRegion& reg) +{ + // Remove adjacent duplicates. + for (int i = 0; i < reg.connections.size() && reg.connections.size() > 1; ) + { + int ni = (i+1) % reg.connections.size(); + if (reg.connections[i] == reg.connections[ni]) + { + // Remove duplicate + for (int j = i; j < reg.connections.size()-1; ++j) + reg.connections[j] = reg.connections[j+1]; + reg.connections.pop(); + } + else + ++i; + } +} + +static void replaceNeighbour(rcRegion& reg, unsigned short oldId, unsigned short newId) +{ + bool neiChanged = false; + for (int i = 0; i < reg.connections.size(); ++i) + { + if (reg.connections[i] == oldId) + { + reg.connections[i] = newId; + neiChanged = true; + } + } + for (int i = 0; i < reg.floors.size(); ++i) + { + if (reg.floors[i] == oldId) + reg.floors[i] = newId; + } + if (neiChanged) + removeAdjacentNeighbours(reg); +} + +static bool canMergeWithRegion(const rcRegion& rega, const rcRegion& regb) +{ + if (rega.areaType != regb.areaType) + return false; + int n = 0; + for (int i = 0; i < rega.connections.size(); ++i) + { + if (rega.connections[i] == regb.id) + n++; + } + if (n > 1) + return false; + for (int i = 0; i < rega.floors.size(); ++i) + { + if (rega.floors[i] == regb.id) + return false; + } + return true; +} + +static void addUniqueFloorRegion(rcRegion& reg, int n) +{ + for (int i = 0; i < reg.floors.size(); ++i) + if (reg.floors[i] == n) + return; + reg.floors.push(n); +} + +static bool mergeRegions(rcRegion& rega, rcRegion& regb) +{ + unsigned short aid = rega.id; + unsigned short bid = regb.id; + + // Duplicate current neighbourhood. + rcIntArray acon; + acon.resize(rega.connections.size()); + for (int i = 0; i < rega.connections.size(); ++i) + acon[i] = rega.connections[i]; + rcIntArray& bcon = regb.connections; + + // Find insertion point on A. + int insa = -1; + for (int i = 0; i < acon.size(); ++i) + { + if (acon[i] == bid) + { + insa = i; + break; + } + } + if (insa == -1) + return false; + + // Find insertion point on B. + int insb = -1; + for (int i = 0; i < bcon.size(); ++i) + { + if (bcon[i] == aid) + { + insb = i; + break; + } + } + if (insb == -1) + return false; + + // Merge neighbours. + rega.connections.resize(0); + for (int i = 0, ni = acon.size(); i < ni-1; ++i) + rega.connections.push(acon[(insa+1+i) % ni]); + + for (int i = 0, ni = bcon.size(); i < ni-1; ++i) + rega.connections.push(bcon[(insb+1+i) % ni]); + + removeAdjacentNeighbours(rega); + + for (int j = 0; j < regb.floors.size(); ++j) + addUniqueFloorRegion(rega, regb.floors[j]); + rega.spanCount += regb.spanCount; + regb.spanCount = 0; + regb.connections.resize(0); + + return true; +} + +static bool isRegionConnectedToBorder(const rcRegion& reg) +{ + // Region is connected to border if + // one of the neighbours is null id. + for (int i = 0; i < reg.connections.size(); ++i) + { + if (reg.connections[i] == 0) + return true; + } + return false; +} + +static bool isSolidEdge(rcCompactHeightfield& chf, unsigned short* srcReg, + int x, int y, int i, int dir) +{ + const rcCompactSpan& s = chf.spans[i]; + unsigned short r = 0; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); + r = srcReg[ai]; + } + if (r == srcReg[i]) + return false; + return true; +} + +static void walkContour(int x, int y, int i, int dir, + rcCompactHeightfield& chf, + unsigned short* srcReg, + rcIntArray& cont) +{ + int startDir = dir; + int starti = i; + + const rcCompactSpan& ss = chf.spans[i]; + unsigned short curReg = 0; + if (rcGetCon(ss, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(ss, dir); + curReg = srcReg[ai]; + } + cont.push(curReg); + + int iter = 0; + while (++iter < 40000) + { + const rcCompactSpan& s = chf.spans[i]; + + if (isSolidEdge(chf, srcReg, x, y, i, dir)) + { + // Choose the edge corner + unsigned short r = 0; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); + r = srcReg[ai]; + } + if (r != curReg) + { + curReg = r; + cont.push(curReg); + } + + dir = (dir+1) & 0x3; // Rotate CW + } + else + { + int ni = -1; + const int nx = x + rcGetDirOffsetX(dir); + const int ny = y + rcGetDirOffsetY(dir); + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const rcCompactCell& nc = chf.cells[nx+ny*chf.width]; + ni = (int)nc.index + rcGetCon(s, dir); + } + if (ni == -1) + { + // Should not happen. + return; + } + x = nx; + y = ny; + i = ni; + dir = (dir+3) & 0x3; // Rotate CCW + } + + if (starti == i && startDir == dir) + { + break; + } + } + + // Remove adjacent duplicates. + if (cont.size() > 1) + { + for (int j = 0; j < cont.size(); ) + { + int nj = (j+1) % cont.size(); + if (cont[j] == cont[nj]) + { + for (int k = j; k < cont.size()-1; ++k) + cont[k] = cont[k+1]; + cont.pop(); + } + else + ++j; + } + } +} + +static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize, + unsigned short& maxRegionId, + rcCompactHeightfield& chf, + unsigned short* srcReg) +{ + const int w = chf.width; + const int h = chf.height; + + const int nreg = maxRegionId+1; + rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP); + if (!regions) + { + ctx->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg); + return false; + } + + // Construct regions + for (int i = 0; i < nreg; ++i) + new(®ions[i]) rcRegion((unsigned short)i); + + // Find edge of a region and find connections around the contour. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + unsigned short r = srcReg[i]; + if (r == 0 || r >= nreg) + continue; + + rcRegion& reg = regions[r]; + reg.spanCount++; + + + // Update floors. + for (int j = (int)c.index; j < ni; ++j) + { + if (i == j) continue; + unsigned short floorId = srcReg[j]; + if (floorId == 0 || floorId >= nreg) + continue; + addUniqueFloorRegion(reg, floorId); + } + + // Have found contour + if (reg.connections.size() > 0) + continue; + + reg.areaType = chf.areas[i]; + + // Check if this cell is next to a border. + int ndir = -1; + for (int dir = 0; dir < 4; ++dir) + { + if (isSolidEdge(chf, srcReg, x, y, i, dir)) + { + ndir = dir; + break; + } + } + + if (ndir != -1) + { + // The cell is at border. + // Walk around the contour to find all the neighbours. + walkContour(x, y, i, ndir, chf, srcReg, reg.connections); + } + } + } + } + + // Remove too small regions. + rcIntArray stack(32); + rcIntArray trace(32); + for (int i = 0; i < nreg; ++i) + { + rcRegion& reg = regions[i]; + if (reg.id == 0 || (reg.id & RC_BORDER_REG)) + continue; + if (reg.spanCount == 0) + continue; + if (reg.visited) + continue; + + // Count the total size of all the connected regions. + // Also keep track of the regions connects to a tile border. + bool connectsToBorder = false; + int spanCount = 0; + stack.resize(0); + trace.resize(0); + + reg.visited = true; + stack.push(i); + + while (stack.size()) + { + // Pop + int ri = stack.pop(); + + rcRegion& creg = regions[ri]; + + spanCount += creg.spanCount; + trace.push(ri); + + for (int j = 0; j < creg.connections.size(); ++j) + { + if (creg.connections[j] & RC_BORDER_REG) + { + connectsToBorder = true; + continue; + } + rcRegion& neireg = regions[creg.connections[j]]; + if (neireg.visited) + continue; + if (neireg.id == 0 || (neireg.id & RC_BORDER_REG)) + continue; + // Visit + stack.push(neireg.id); + neireg.visited = true; + } + } + + // If the accumulated regions size is too small, remove it. + // Do not remove areas which connect to tile borders + // as their size cannot be estimated correctly and removing them + // can potentially remove necessary areas. + if (spanCount < minRegionArea && !connectsToBorder) + { + // Kill all visited regions. + for (int j = 0; j < trace.size(); ++j) + { + regions[trace[j]].spanCount = 0; + regions[trace[j]].id = 0; + } + } + } + + // Merge too small regions to neighbour regions. + int mergeCount = 0 ; + do + { + mergeCount = 0; + for (int i = 0; i < nreg; ++i) + { + rcRegion& reg = regions[i]; + if (reg.id == 0 || (reg.id & RC_BORDER_REG)) + continue; + if (reg.spanCount == 0) + continue; + + // Check to see if the region should be merged. + if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg)) + continue; + + // Small region with more than 1 connection. + // Or region which is not connected to a border at all. + // Find smallest neighbour region that connects to this one. + int smallest = 0xfffffff; + unsigned short mergeId = reg.id; + for (int j = 0; j < reg.connections.size(); ++j) + { + if (reg.connections[j] & RC_BORDER_REG) continue; + rcRegion& mreg = regions[reg.connections[j]]; + if (mreg.id == 0 || (mreg.id & RC_BORDER_REG)) continue; + if (mreg.spanCount < smallest && + canMergeWithRegion(reg, mreg) && + canMergeWithRegion(mreg, reg)) + { + smallest = mreg.spanCount; + mergeId = mreg.id; + } + } + // Found new id. + if (mergeId != reg.id) + { + unsigned short oldId = reg.id; + rcRegion& target = regions[mergeId]; + + // Merge neighbours. + if (mergeRegions(target, reg)) + { + // Fixup regions pointing to current region. + for (int j = 0; j < nreg; ++j) + { + if (regions[j].id == 0 || (regions[j].id & RC_BORDER_REG)) continue; + // If another region was already merged into current region + // change the nid of the previous region too. + if (regions[j].id == oldId) + regions[j].id = mergeId; + // Replace the current region with the new one if the + // current regions is neighbour. + replaceNeighbour(regions[j], oldId, mergeId); + } + mergeCount++; + } + } + } + } + while (mergeCount > 0); + + // Compress region Ids. + for (int i = 0; i < nreg; ++i) + { + regions[i].remap = false; + if (regions[i].id == 0) continue; // Skip nil regions. + if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions. + regions[i].remap = true; + } + + unsigned short regIdGen = 0; + for (int i = 0; i < nreg; ++i) + { + if (!regions[i].remap) + continue; + unsigned short oldId = regions[i].id; + unsigned short newId = ++regIdGen; + for (int j = i; j < nreg; ++j) + { + if (regions[j].id == oldId) + { + regions[j].id = newId; + regions[j].remap = false; + } + } + } + maxRegionId = regIdGen; + + // Remap regions. + for (int i = 0; i < chf.spanCount; ++i) + { + if ((srcReg[i] & RC_BORDER_REG) == 0) + srcReg[i] = regions[srcReg[i]].id; + } + + for (int i = 0; i < nreg; ++i) + regions[i].~rcRegion(); + rcFree(regions); + + return true; +} + +/// @par +/// +/// This is usually the second to the last step in creating a fully built +/// compact heightfield. This step is required before regions are built +/// using #rcBuildRegions or #rcBuildRegionsMonotone. +/// +/// After this step, the distance data is available via the rcCompactHeightfield::maxDistance +/// and rcCompactHeightfield::dist fields. +/// +/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone +bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD); + + if (chf.dist) + { + rcFree(chf.dist); + chf.dist = 0; + } + + unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!src) + { + ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount); + return false; + } + unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!dst) + { + ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount); + rcFree(src); + return false; + } + + unsigned short maxDist = 0; + + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); + + calculateDistanceField(chf, src, maxDist); + chf.maxDistance = maxDist; + + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); + + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); + + // Blur + if (boxBlur(chf, 1, src, dst) != src) + rcSwap(src, dst); + + // Store distance. + chf.dist = src; + + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); + + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD); + + rcFree(dst); + + return true; +} + +static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId, + rcCompactHeightfield& chf, unsigned short* srcReg) +{ + const int w = chf.width; + for (int y = miny; y < maxy; ++y) + { + for (int x = minx; x < maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (chf.areas[i] != RC_NULL_AREA) + srcReg[i] = regId; + } + } + } +} + + +static const unsigned short RC_NULL_NEI = 0xffff; + +struct rcSweepSpan +{ + unsigned short rid; // row id + unsigned short id; // region id + unsigned short ns; // number samples + unsigned short nei; // neighbour id +}; + +/// @par +/// +/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. +/// Contours will form simple polygons. +/// +/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be +/// re-assigned to the zero (null) region. +/// +/// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps +/// reduce unecessarily small regions. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// The region data will be available via the rcCompactHeightfield::maxRegions +/// and rcCompactSpan::reg fields. +/// +/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. +/// +/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig +bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS); + + const int w = chf.width; + const int h = chf.height; + unsigned short id = 1; + + rcScopedDelete srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!srcReg) + { + ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount); + return false; + } + memset(srcReg,0,sizeof(unsigned short)*chf.spanCount); + + const int nsweeps = rcMax(chf.width,chf.height); + rcScopedDelete sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP); + if (!sweeps) + { + ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps); + return false; + } + + + // Mark border regions. + if (borderSize > 0) + { + // Make sure border will not overflow. + const int bw = rcMin(w, borderSize); + const int bh = rcMin(h, borderSize); + // Paint regions + paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++; + + chf.borderSize = borderSize; + } + + rcIntArray prev(256); + + // Sweep one line at a time. + for (int y = borderSize; y < h-borderSize; ++y) + { + // Collect spans from this row. + prev.resize(id+1); + memset(&prev[0],0,sizeof(int)*id); + unsigned short rid = 1; + + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) continue; + + // -x + unsigned short previd = 0; + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) + previd = srcReg[ai]; + } + + if (!previd) + { + previd = rid++; + sweeps[previd].rid = previd; + sweeps[previd].ns = 0; + sweeps[previd].nei = 0; + } + + // -y + if (rcGetCon(s,3) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) + { + unsigned short nr = srcReg[ai]; + if (!sweeps[previd].nei || sweeps[previd].nei == nr) + { + sweeps[previd].nei = nr; + sweeps[previd].ns++; + prev[nr]++; + } + else + { + sweeps[previd].nei = RC_NULL_NEI; + } + } + } + + srcReg[i] = previd; + } + } + + // Create unique ID. + for (int i = 1; i < rid; ++i) + { + if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 && + prev[sweeps[i].nei] == (int)sweeps[i].ns) + { + sweeps[i].id = sweeps[i].nei; + } + else + { + sweeps[i].id = id++; + } + } + + // Remap IDs + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (srcReg[i] > 0 && srcReg[i] < rid) + srcReg[i] = sweeps[srcReg[i]].id; + } + } + } + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Filter out small regions. + chf.maxRegions = id; + if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg)) + return false; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Store the result out. + for (int i = 0; i < chf.spanCount; ++i) + chf.spans[i].reg = srcReg[i]; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS); + + return true; +} + +/// @par +/// +/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. +/// Contours will form simple polygons. +/// +/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be +/// re-assigned to the zero (null) region. +/// +/// Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors. +/// @p mergeRegionArea helps reduce unecessarily small regions. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// The region data will be available via the rcCompactHeightfield::maxRegions +/// and rcCompactSpan::reg fields. +/// +/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. +/// +/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig +bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS); + + const int w = chf.width; + const int h = chf.height; + + rcScopedDelete buf = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP); + if (!buf) + { + ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4); + return false; + } + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED); + + rcIntArray stack(1024); + rcIntArray visited(1024); + + unsigned short* srcReg = buf; + unsigned short* srcDist = buf+chf.spanCount; + unsigned short* dstReg = buf+chf.spanCount*2; + unsigned short* dstDist = buf+chf.spanCount*3; + + memset(srcReg, 0, sizeof(unsigned short)*chf.spanCount); + memset(srcDist, 0, sizeof(unsigned short)*chf.spanCount); + + unsigned short regionId = 1; + unsigned short level = (chf.maxDistance+1) & ~1; + + // TODO: Figure better formula, expandIters defines how much the + // watershed "overflows" and simplifies the regions. Tying it to + // agent radius was usually good indication how greedy it could be. +// const int expandIters = 4 + walkableRadius * 2; + const int expandIters = 8; + + if (borderSize > 0) + { + // Make sure border will not overflow. + const int bw = rcMin(w, borderSize); + const int bh = rcMin(h, borderSize); + // Paint regions + paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + + chf.borderSize = borderSize; + } + + while (level > 0) + { + level = level >= 2 ? level-2 : 0; + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND); + + // Expand current regions until no empty connected cells found. + if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg) + { + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); + } + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_EXPAND); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD); + + // Mark new regions with IDs. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA) + continue; + if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack)) + regionId++; + } + } + } + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD); + } + + // Expand current regions until no empty connected cells found. + if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg) + { + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); + } + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_WATERSHED); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Filter out small regions. + chf.maxRegions = regionId; + if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg)) + return false; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Write the result out. + for (int i = 0; i < chf.spanCount; ++i) + chf.spans[i].reg = srcReg[i]; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS); + + return true; +} + + diff --git a/KREngine/kraken/tinyxml2.cpp b/KREngine/3rdparty/tinyxml2/tinyxml2.cpp similarity index 100% rename from KREngine/kraken/tinyxml2.cpp rename to KREngine/3rdparty/tinyxml2/tinyxml2.cpp diff --git a/KREngine/kraken/tinyxml2.h b/KREngine/3rdparty/tinyxml2/tinyxml2.h similarity index 100% rename from KREngine/kraken/tinyxml2.h rename to KREngine/3rdparty/tinyxml2/tinyxml2.h diff --git a/KREngine/kraken/tinyxml2_readme.txt b/KREngine/3rdparty/tinyxml2/tinyxml2_readme.txt similarity index 100% rename from KREngine/kraken/tinyxml2_readme.txt rename to KREngine/3rdparty/tinyxml2/tinyxml2_readme.txt diff --git a/KREngine/Kraken.xcodeproj/project.pbxproj b/KREngine/Kraken.xcodeproj/project.pbxproj index 18e49e4..61a5b5e 100644 --- a/KREngine/Kraken.xcodeproj/project.pbxproj +++ b/KREngine/Kraken.xcodeproj/project.pbxproj @@ -44,6 +44,32 @@ E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E416AA9816713749000F6786 /* KRAnimationCurveManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E416AA9C1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; E416AA9D1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; + E416E4881879111300FC2EEB /* Recast.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4851879111300FC2EEB /* Recast.h */; }; + E416E4891879111300FC2EEB /* Recast.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4851879111300FC2EEB /* Recast.h */; }; + E416E48A1879111300FC2EEB /* RecastAlloc.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4861879111300FC2EEB /* RecastAlloc.h */; }; + E416E48B1879111300FC2EEB /* RecastAlloc.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4861879111300FC2EEB /* RecastAlloc.h */; }; + E416E48C1879111300FC2EEB /* RecastAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4871879111300FC2EEB /* RecastAssert.h */; }; + E416E48D1879111300FC2EEB /* RecastAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = E416E4871879111300FC2EEB /* RecastAssert.h */; }; + E416E4981879112700FC2EEB /* Recast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E48E1879112700FC2EEB /* Recast.cpp */; }; + E416E4991879112700FC2EEB /* Recast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E48E1879112700FC2EEB /* Recast.cpp */; }; + E416E49A1879112700FC2EEB /* RecastAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E48F1879112700FC2EEB /* RecastAlloc.cpp */; }; + E416E49B1879112700FC2EEB /* RecastAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E48F1879112700FC2EEB /* RecastAlloc.cpp */; }; + E416E49C1879112700FC2EEB /* RecastArea.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4901879112700FC2EEB /* RecastArea.cpp */; }; + E416E49D1879112700FC2EEB /* RecastArea.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4901879112700FC2EEB /* RecastArea.cpp */; }; + E416E49E1879112700FC2EEB /* RecastContour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4911879112700FC2EEB /* RecastContour.cpp */; }; + E416E49F1879112700FC2EEB /* RecastContour.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4911879112700FC2EEB /* RecastContour.cpp */; }; + E416E4A01879112700FC2EEB /* RecastFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4921879112700FC2EEB /* RecastFilter.cpp */; }; + E416E4A11879112700FC2EEB /* RecastFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4921879112700FC2EEB /* RecastFilter.cpp */; }; + E416E4A21879112700FC2EEB /* RecastLayers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4931879112700FC2EEB /* RecastLayers.cpp */; }; + E416E4A31879112700FC2EEB /* RecastLayers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4931879112700FC2EEB /* RecastLayers.cpp */; }; + E416E4A41879112700FC2EEB /* RecastMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4941879112700FC2EEB /* RecastMesh.cpp */; }; + E416E4A51879112700FC2EEB /* RecastMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4941879112700FC2EEB /* RecastMesh.cpp */; }; + E416E4A61879112700FC2EEB /* RecastMeshDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4951879112700FC2EEB /* RecastMeshDetail.cpp */; }; + E416E4A71879112700FC2EEB /* RecastMeshDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4951879112700FC2EEB /* RecastMeshDetail.cpp */; }; + E416E4A81879112700FC2EEB /* RecastRasterization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4961879112700FC2EEB /* RecastRasterization.cpp */; }; + E416E4A91879112700FC2EEB /* RecastRasterization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4961879112700FC2EEB /* RecastRasterization.cpp */; }; + E416E4AA1879112700FC2EEB /* RecastRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4971879112700FC2EEB /* RecastRegion.cpp */; }; + E416E4AB1879112700FC2EEB /* RecastRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416E4971879112700FC2EEB /* RecastRegion.cpp */; }; E41843921678704000DBD6CF /* KRCollider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 104A335C1672D31B001C8BA6 /* KRCollider.cpp */; }; E41B6BA816BE436100B510EB /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B6BA716BE436100B510EB /* CoreAudio.framework */; }; E41B6BAA16BE437800B510EB /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B6BA916BE437800B510EB /* CoreAudio.framework */; }; @@ -112,6 +138,28 @@ E45134B91746A4A300443C21 /* KRBehavior.h in Headers */ = {isa = PBXBuildFile; fileRef = E45134B51746A4A300443C21 /* KRBehavior.h */; settings = {ATTRIBUTES = (Public, ); }; }; E459040416C30CC5002B00A0 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E459040316C30CC5002B00A0 /* AudioUnit.framework */; }; E459040616C30CD9002B00A0 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E459040516C30CD9002B00A0 /* AudioUnit.framework */; }; + E45E03B118790DD1006DA23F /* PVRTArray.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A418790DD1006DA23F /* PVRTArray.h */; }; + E45E03B218790DD1006DA23F /* PVRTDecompress.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A518790DD1006DA23F /* PVRTDecompress.h */; }; + E45E03B318790DD1006DA23F /* PVRTError.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A618790DD1006DA23F /* PVRTError.h */; }; + E45E03B418790DD1006DA23F /* PVRTexture.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A718790DD1006DA23F /* PVRTexture.h */; }; + E45E03B518790DD1006DA23F /* PVRTextureDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A818790DD1006DA23F /* PVRTextureDefines.h */; }; + E45E03B618790DD1006DA23F /* PVRTextureFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A918790DD1006DA23F /* PVRTextureFormat.h */; }; + E45E03B718790DD1006DA23F /* PVRTextureHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AA18790DD1006DA23F /* PVRTextureHeader.h */; }; + E45E03B818790DD1006DA23F /* PVRTextureUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AB18790DD1006DA23F /* PVRTextureUtilities.h */; }; + E45E03B918790DD1006DA23F /* PVRTextureVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AC18790DD1006DA23F /* PVRTextureVersion.h */; }; + E45E03BA18790DD1006DA23F /* PVRTGlobal.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AD18790DD1006DA23F /* PVRTGlobal.h */; }; + E45E03BB18790DD1006DA23F /* PVRTMap.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AE18790DD1006DA23F /* PVRTMap.h */; }; + E45E03BC18790DD1006DA23F /* PVRTString.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03AF18790DD1006DA23F /* PVRTString.h */; }; + E45E03BD18790DD1006DA23F /* PVRTTexture.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03B018790DD1006DA23F /* PVRTTexture.h */; }; + E45E03C018790DF5006DA23F /* libPVRTexLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E45E03BF18790DF5006DA23F /* libPVRTexLib.a */; }; + E45E03C718790EC0006DA23F /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45E03C418790EC0006DA23F /* tinyxml2.cpp */; }; + E45E03C818790EC0006DA23F /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45E03C418790EC0006DA23F /* tinyxml2.cpp */; }; + E45E03C918790EC0006DA23F /* tinyxml2.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03C518790EC0006DA23F /* tinyxml2.h */; }; + E45E03CA18790EC0006DA23F /* tinyxml2.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03C518790EC0006DA23F /* tinyxml2.h */; }; + E45E03CD18790EFF006DA23F /* forsyth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45E03CB18790EFF006DA23F /* forsyth.cpp */; }; + E45E03CE18790EFF006DA23F /* forsyth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45E03CB18790EFF006DA23F /* forsyth.cpp */; }; + E45E03CF18790EFF006DA23F /* forsyth.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03CC18790EFF006DA23F /* forsyth.h */; }; + E45E03D018790EFF006DA23F /* forsyth.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03CC18790EFF006DA23F /* forsyth.h */; }; E460292616681CFF00261BB9 /* KRTextureAnimated.h in Headers */ = {isa = PBXBuildFile; fileRef = E460292516681CFE00261BB9 /* KRTextureAnimated.h */; settings = {ATTRIBUTES = (); }; }; E460292816681D1000261BB9 /* KRTextureAnimated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E460292716681D1000261BB9 /* KRTextureAnimated.cpp */; }; E460292B16682BF700261BB9 /* libfbxsdk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E460292916682BD900261BB9 /* libfbxsdk.a */; }; @@ -139,10 +187,6 @@ E468448217FFDF51001F1FA1 /* KRLocator.h in Headers */ = {isa = PBXBuildFile; fileRef = E468447E17FFDF51001F1FA1 /* KRLocator.h */; settings = {ATTRIBUTES = (Public, ); }; }; E46A6B6D1559E97D000DBD37 /* KRResource+blend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46A6B6C1559E97D000DBD37 /* KRResource+blend.cpp */; }; E46A6B701559EF0A000DBD37 /* KRResource+blend.h in Headers */ = {isa = PBXBuildFile; fileRef = E46A6B6F1559EF0A000DBD37 /* KRResource+blend.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E46C214515364BC8009CABF3 /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46C214215364BC8009CABF3 /* tinyxml2.cpp */; }; - E46C214615364BC8009CABF3 /* tinyxml2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46C214215364BC8009CABF3 /* tinyxml2.cpp */; }; - E46C214715364BC8009CABF3 /* tinyxml2.h in Headers */ = {isa = PBXBuildFile; fileRef = E46C214315364BC8009CABF3 /* tinyxml2.h */; settings = {ATTRIBUTES = (); }; }; - E46C214815364BC8009CABF3 /* tinyxml2.h in Headers */ = {isa = PBXBuildFile; fileRef = E46C214315364BC8009CABF3 /* tinyxml2.h */; settings = {ATTRIBUTES = (Public, ); }; }; E46C214B15364DEC009CABF3 /* KRSceneManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46C214A15364DEC009CABF3 /* KRSceneManager.cpp */; }; E46C214C15364DEC009CABF3 /* KRSceneManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E46C214A15364DEC009CABF3 /* KRSceneManager.cpp */; }; E46DBE7F1512AF0200D59F86 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E46DBE7D1512AD4900D59F86 /* OpenGL.framework */; }; @@ -350,7 +394,6 @@ E4E6F6BE16BA5E0A00E410F8 /* volumetric_fog_downsampled_osx.vsh in Resources */ = {isa = PBXBuildFile; fileRef = E4E6F62816BA5D8300E410F8 /* volumetric_fog_downsampled_osx.vsh */; }; E4E6F6BF16BA5E0A00E410F8 /* volumetric_fog_osx.fsh in Resources */ = {isa = PBXBuildFile; fileRef = E4E6F62916BA5D8300E410F8 /* volumetric_fog_osx.fsh */; }; E4E6F6C016BA5E0A00E410F8 /* volumetric_fog_osx.vsh in Resources */ = {isa = PBXBuildFile; fileRef = E4E6F62A16BA5D8300E410F8 /* volumetric_fog_osx.vsh */; }; - E4EC73B8171F32780065299F /* forsyth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4FE6AAA16B21D7E0058B8CE /* forsyth.cpp */; }; E4EC73C11720B1FF0065299F /* KRVector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4EC73BF1720B1FF0065299F /* KRVector4.cpp */; }; E4EC73C21720B1FF0065299F /* KRVector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4EC73BF1720B1FF0065299F /* KRVector4.cpp */; }; E4EC73C31720B1FF0065299F /* KRVector4.h in Headers */ = {isa = PBXBuildFile; fileRef = E4EC73C01720B1FF0065299F /* KRVector4.h */; }; @@ -391,9 +434,6 @@ E4F97552153633EF00FD60B2 /* KRMaterialManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E491018413C99BDC0098455B /* KRMaterialManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E4F975531536340000FD60B2 /* KRTexture2D.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E491018113C99BDC0098455B /* KRTexture2D.cpp */; }; E4F975541536340400FD60B2 /* KRTexture2D.h in Headers */ = {isa = PBXBuildFile; fileRef = E491018613C99BDC0098455B /* KRTexture2D.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4FE6AA816B21D660058B8CE /* forsyth.h in Headers */ = {isa = PBXBuildFile; fileRef = E4FE6AA716B21D660058B8CE /* forsyth.h */; settings = {ATTRIBUTES = (); }; }; - E4FE6AA916B21D660058B8CE /* forsyth.h in Headers */ = {isa = PBXBuildFile; fileRef = E4FE6AA716B21D660058B8CE /* forsyth.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4FE6AAB16B21D7E0058B8CE /* forsyth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4FE6AAA16B21D7E0058B8CE /* forsyth.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ @@ -411,7 +451,6 @@ /* Begin PBXFileReference section */ 104A335C1672D31B001C8BA6 /* KRCollider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRCollider.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 104A335D1672D31C001C8BA6 /* KRCollider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRCollider.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - 10CC33A3168530A300BB9846 /* libPVRTexLib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libPVRTexLib.a; path = Utilities/PVRTexLib/MacOS/libPVRTexLib.a; sourceTree = PVRSDK; }; E4030E4B160A3CF000592648 /* KRStockGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRStockGeometry.h; sourceTree = ""; }; E404701E18695DD200F01F42 /* KRTextureKTX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRTextureKTX.cpp; sourceTree = ""; }; E404701F18695DD200F01F42 /* KRTextureKTX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRTextureKTX.h; sourceTree = ""; }; @@ -431,6 +470,19 @@ E414F9AB1694DA37000B3D58 /* KRUnknown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRUnknown.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E416AA9816713749000F6786 /* KRAnimationCurveManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRAnimationCurveManager.h; sourceTree = ""; }; E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRAnimationCurveManager.cpp; sourceTree = ""; }; + E416E4851879111300FC2EEB /* Recast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Recast.h; sourceTree = ""; }; + E416E4861879111300FC2EEB /* RecastAlloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecastAlloc.h; sourceTree = ""; }; + E416E4871879111300FC2EEB /* RecastAssert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecastAssert.h; sourceTree = ""; }; + E416E48E1879112700FC2EEB /* Recast.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Recast.cpp; sourceTree = ""; }; + E416E48F1879112700FC2EEB /* RecastAlloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastAlloc.cpp; sourceTree = ""; }; + E416E4901879112700FC2EEB /* RecastArea.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastArea.cpp; sourceTree = ""; }; + E416E4911879112700FC2EEB /* RecastContour.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastContour.cpp; sourceTree = ""; }; + E416E4921879112700FC2EEB /* RecastFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastFilter.cpp; sourceTree = ""; }; + E416E4931879112700FC2EEB /* RecastLayers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastLayers.cpp; sourceTree = ""; }; + E416E4941879112700FC2EEB /* RecastMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastMesh.cpp; sourceTree = ""; }; + E416E4951879112700FC2EEB /* RecastMeshDetail.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastMeshDetail.cpp; sourceTree = ""; }; + E416E4961879112700FC2EEB /* RecastRasterization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastRasterization.cpp; sourceTree = ""; }; + E416E4971879112700FC2EEB /* RecastRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecastRegion.cpp; sourceTree = ""; }; E41AE1DD16B124CA00980428 /* font.tga */ = {isa = PBXFileReference; lastKnownFileType = file; path = font.tga; sourceTree = ""; }; E41B6BA716BE436100B510EB /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; E41B6BA916BE437800B510EB /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; }; @@ -471,6 +523,25 @@ E45134B51746A4A300443C21 /* KRBehavior.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRBehavior.h; sourceTree = ""; }; E459040316C30CC5002B00A0 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/AudioUnit.framework; sourceTree = DEVELOPER_DIR; }; E459040516C30CD9002B00A0 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; + E45E03A418790DD1006DA23F /* PVRTArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTArray.h; sourceTree = ""; }; + E45E03A518790DD1006DA23F /* PVRTDecompress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTDecompress.h; sourceTree = ""; }; + E45E03A618790DD1006DA23F /* PVRTError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTError.h; sourceTree = ""; }; + E45E03A718790DD1006DA23F /* PVRTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTexture.h; sourceTree = ""; }; + E45E03A818790DD1006DA23F /* PVRTextureDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTextureDefines.h; sourceTree = ""; }; + E45E03A918790DD1006DA23F /* PVRTextureFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTextureFormat.h; sourceTree = ""; }; + E45E03AA18790DD1006DA23F /* PVRTextureHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTextureHeader.h; sourceTree = ""; }; + E45E03AB18790DD1006DA23F /* PVRTextureUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTextureUtilities.h; sourceTree = ""; }; + E45E03AC18790DD1006DA23F /* PVRTextureVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTextureVersion.h; sourceTree = ""; }; + E45E03AD18790DD1006DA23F /* PVRTGlobal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTGlobal.h; sourceTree = ""; }; + E45E03AE18790DD1006DA23F /* PVRTMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTMap.h; sourceTree = ""; }; + E45E03AF18790DD1006DA23F /* PVRTString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTString.h; sourceTree = ""; }; + E45E03B018790DD1006DA23F /* PVRTTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTTexture.h; sourceTree = ""; }; + E45E03BF18790DF5006DA23F /* libPVRTexLib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libPVRTexLib.a; sourceTree = ""; }; + E45E03C318790EC0006DA23F /* tinyxml2_readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tinyxml2_readme.txt; sourceTree = ""; }; + E45E03C418790EC0006DA23F /* tinyxml2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml2.cpp; sourceTree = ""; }; + E45E03C518790EC0006DA23F /* tinyxml2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml2.h; sourceTree = ""; }; + E45E03CB18790EFF006DA23F /* forsyth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = forsyth.cpp; sourceTree = ""; }; + E45E03CC18790EFF006DA23F /* forsyth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = forsyth.h; sourceTree = ""; }; E460292516681CFE00261BB9 /* KRTextureAnimated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRTextureAnimated.h; sourceTree = ""; }; E460292716681D1000261BB9 /* KRTextureAnimated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRTextureAnimated.cpp; sourceTree = ""; }; E460292916682BD900261BB9 /* libfbxsdk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfbxsdk.a; path = "../../FBX SDK/2014.2/lib/ios-i386/release/libfbxsdk.a"; sourceTree = FBXSDK; }; @@ -486,9 +557,6 @@ E468447E17FFDF51001F1FA1 /* KRLocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRLocator.h; sourceTree = ""; }; E46A6B6C1559E97D000DBD37 /* KRResource+blend.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "KRResource+blend.cpp"; sourceTree = ""; }; E46A6B6F1559EF0A000DBD37 /* KRResource+blend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KRResource+blend.h"; sourceTree = ""; }; - E46C214115364BC8009CABF3 /* tinyxml2_readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tinyxml2_readme.txt; sourceTree = ""; }; - E46C214215364BC8009CABF3 /* tinyxml2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml2.cpp; sourceTree = ""; }; - E46C214315364BC8009CABF3 /* tinyxml2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml2.h; sourceTree = ""; }; E46C214915364DDB009CABF3 /* KRSceneManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KRSceneManager.h; sourceTree = ""; }; E46C214A15364DEC009CABF3 /* KRSceneManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRSceneManager.cpp; sourceTree = ""; }; E46DBE7D1512AD4900D59F86 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = ../../../../MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; @@ -658,8 +726,6 @@ E4F027F91698116000D4427D /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; E4F975311536220900FD60B2 /* KRNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KRNode.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E4F975351536221C00FD60B2 /* KRNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = KRNode.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - E4FE6AA716B21D660058B8CE /* forsyth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = forsyth.h; sourceTree = ""; }; - E4FE6AAA16B21D7E0058B8CE /* forsyth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = forsyth.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -681,6 +747,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E45E03C018790DF5006DA23F /* libPVRTexLib.a in Frameworks */, E459040416C30CC5002B00A0 /* AudioUnit.framework in Frameworks */, E41B6BAA16BE437800B510EB /* CoreAudio.framework in Frameworks */, E4F027F71698115600D4427D /* AudioToolbox.framework in Frameworks */, @@ -736,6 +803,42 @@ name = AnimationCurve; sourceTree = ""; }; + E416E482187910DF00FC2EEB /* recast */ = { + isa = PBXGroup; + children = ( + E416E484187910FB00FC2EEB /* include */, + E416E483187910ED00FC2EEB /* source */, + ); + path = recast; + sourceTree = ""; + }; + E416E483187910ED00FC2EEB /* source */ = { + isa = PBXGroup; + children = ( + E416E48E1879112700FC2EEB /* Recast.cpp */, + E416E48F1879112700FC2EEB /* RecastAlloc.cpp */, + E416E4901879112700FC2EEB /* RecastArea.cpp */, + E416E4911879112700FC2EEB /* RecastContour.cpp */, + E416E4921879112700FC2EEB /* RecastFilter.cpp */, + E416E4931879112700FC2EEB /* RecastLayers.cpp */, + E416E4941879112700FC2EEB /* RecastMesh.cpp */, + E416E4951879112700FC2EEB /* RecastMeshDetail.cpp */, + E416E4961879112700FC2EEB /* RecastRasterization.cpp */, + E416E4971879112700FC2EEB /* RecastRegion.cpp */, + ); + path = source; + sourceTree = ""; + }; + E416E484187910FB00FC2EEB /* include */ = { + isa = PBXGroup; + children = ( + E416E4851879111300FC2EEB /* Recast.h */, + E416E4861879111300FC2EEB /* RecastAlloc.h */, + E416E4871879111300FC2EEB /* RecastAssert.h */, + ); + path = include; + sourceTree = ""; + }; E41AE1DF16B125EC00980428 /* Shaders */ = { isa = PBXGroup; children = ( @@ -809,6 +912,73 @@ path = kraken_standard_assets; sourceTree = ""; }; + E45E03A118790D92006DA23F /* 3rdparty */ = { + isa = PBXGroup; + children = ( + E416E482187910DF00FC2EEB /* recast */, + E45E03C218790E55006DA23F /* tinyxml2 */, + E45E03C118790E4F006DA23F /* forsyth */, + E45E03A218790DA3006DA23F /* pvrtexlib */, + ); + path = 3rdparty; + sourceTree = ""; + }; + E45E03A218790DA3006DA23F /* pvrtexlib */ = { + isa = PBXGroup; + children = ( + E45E03BE18790DDB006DA23F /* static_osx */, + E45E03A318790DB8006DA23F /* include */, + ); + path = pvrtexlib; + sourceTree = ""; + }; + E45E03A318790DB8006DA23F /* include */ = { + isa = PBXGroup; + children = ( + E45E03A418790DD1006DA23F /* PVRTArray.h */, + E45E03A518790DD1006DA23F /* PVRTDecompress.h */, + E45E03A618790DD1006DA23F /* PVRTError.h */, + E45E03A718790DD1006DA23F /* PVRTexture.h */, + E45E03A818790DD1006DA23F /* PVRTextureDefines.h */, + E45E03A918790DD1006DA23F /* PVRTextureFormat.h */, + E45E03AA18790DD1006DA23F /* PVRTextureHeader.h */, + E45E03AB18790DD1006DA23F /* PVRTextureUtilities.h */, + E45E03AC18790DD1006DA23F /* PVRTextureVersion.h */, + E45E03AD18790DD1006DA23F /* PVRTGlobal.h */, + E45E03AE18790DD1006DA23F /* PVRTMap.h */, + E45E03AF18790DD1006DA23F /* PVRTString.h */, + E45E03B018790DD1006DA23F /* PVRTTexture.h */, + ); + path = include; + sourceTree = ""; + }; + E45E03BE18790DDB006DA23F /* static_osx */ = { + isa = PBXGroup; + children = ( + E45E03BF18790DF5006DA23F /* libPVRTexLib.a */, + ); + path = static_osx; + sourceTree = ""; + }; + E45E03C118790E4F006DA23F /* forsyth */ = { + isa = PBXGroup; + children = ( + E45E03CB18790EFF006DA23F /* forsyth.cpp */, + E45E03CC18790EFF006DA23F /* forsyth.h */, + ); + path = forsyth; + sourceTree = ""; + }; + E45E03C218790E55006DA23F /* tinyxml2 */ = { + isa = PBXGroup; + children = ( + E45E03C318790EC0006DA23F /* tinyxml2_readme.txt */, + E45E03C418790EC0006DA23F /* tinyxml2.cpp */, + E45E03C518790EC0006DA23F /* tinyxml2.h */, + ); + path = tinyxml2; + sourceTree = ""; + }; E461A170152E598200F2044A /* Resources */ = { isa = PBXGroup; children = ( @@ -858,16 +1028,6 @@ name = Math; sourceTree = ""; }; - E46C214015364BB8009CABF3 /* tinyxml2 */ = { - isa = PBXGroup; - children = ( - E46C214115364BC8009CABF3 /* tinyxml2_readme.txt */, - E46C214215364BC8009CABF3 /* tinyxml2.cpp */, - E46C214315364BC8009CABF3 /* tinyxml2.h */, - ); - name = tinyxml2; - sourceTree = ""; - }; E488399915F92BA300BD66D5 /* Managers */ = { isa = PBXGroup; children = ( @@ -1040,6 +1200,7 @@ E491015613C99B9D0098455B = { isa = PBXGroup; children = ( + E45E03A118790D92006DA23F /* 3rdparty */, E437849616C4881A0037FD43 /* kraken_standard_assets */, E491016613C99B9E0098455B /* kraken */, E4C8E50C16B9B5ED0031DDCB /* kraken_ios */, @@ -1064,7 +1225,6 @@ E491016613C99B9E0098455B /* kraken */ = { isa = PBXGroup; children = ( - E4F9753815362A5200FD60B2 /* 3rdparty */, E488399915F92BA300BD66D5 /* Managers */, E461A173152E59DF00F2044A /* Math */, E461A170152E598200F2044A /* Resources */, @@ -1120,7 +1280,6 @@ children = ( E459040316C30CC5002B00A0 /* AudioUnit.framework */, E41B6BA916BE437800B510EB /* CoreAudio.framework */, - 10CC33A3168530A300BB9846 /* libPVRTexLib.a */, E460292916682BD900261BB9 /* libfbxsdk.a */, E4BBBB9A1512A48200F43B5B /* Foundation.framework */, E46DBE7D1512AD4900D59F86 /* OpenGL.framework */, @@ -1219,24 +1378,6 @@ name = Frameworks; sourceTree = ""; }; - E4F9753815362A5200FD60B2 /* 3rdparty */ = { - isa = PBXGroup; - children = ( - E4FE6AA516B21D330058B8CE /* forsyth */, - E46C214015364BB8009CABF3 /* tinyxml2 */, - ); - name = 3rdparty; - sourceTree = ""; - }; - E4FE6AA516B21D330058B8CE /* forsyth */ = { - isa = PBXGroup; - children = ( - E4FE6AA716B21D660058B8CE /* forsyth.h */, - E4FE6AAA16B21D7E0058B8CE /* forsyth.cpp */, - ); - name = forsyth; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -1252,6 +1393,7 @@ E491018A13C99BDC0098455B /* KREngine.h in Headers */, E491018E13C99BDC0098455B /* KRMat4.h in Headers */, E491019B13C99BDC0098455B /* KRMeshManager.h in Headers */, + E416E48C1879111300FC2EEB /* RecastAssert.h in Headers */, E491019213C99BDC0098455B /* KRMesh.h in Headers */, E491019613C99BDC0098455B /* KRVector3.h in Headers */, E47C25A213F4F65A00FF4370 /* KRShaderManager.h in Headers */, @@ -1260,6 +1402,7 @@ E414BAE7143557D200A668C4 /* KRScene.h in Headers */, E48B3CBD14393DF5000C50E2 /* KRCamera.h in Headers */, E40F982E184A7A2700CFA4D8 /* KRMeshQuad.h in Headers */, + E45E03CF18790EFF006DA23F /* forsyth.h in Headers */, E497B94A151BCEE900D3DC67 /* KRResource.h in Headers */, E461A152152E54B500F2044A /* KRLight.h in Headers */, E461A15C152E563100F2044A /* KRDirectionalLight.h in Headers */, @@ -1267,7 +1410,6 @@ E468448117FFDF51001F1FA1 /* KRLocator.h in Headers */, E43F70E71824D9AB00136169 /* KRTextureStreamer.h in Headers */, E4F975321536220900FD60B2 /* KRNode.h in Headers */, - E46C214715364BC8009CABF3 /* tinyxml2.h in Headers */, E48C696F15374F5B00232E28 /* KRContext.h in Headers */, E46F4A0B155E002100CCF8B8 /* KRDataBlock.h in Headers */, E42CB1EC158446940066E0D8 /* KRQuaternion.h in Headers */, @@ -1280,6 +1422,7 @@ E488399E15F92BE000BD66D5 /* KRBundleManager.h in Headers */, E4030E4C160A3CF000592648 /* KRStockGeometry.h in Headers */, E4B175AE161F5A1000B8FB80 /* KRTexture.h in Headers */, + E416E48A1879111300FC2EEB /* RecastAlloc.h in Headers */, E4B175B4161F5FAF00B8FB80 /* KRTextureCube.h in Headers */, E4CA10E51637BD0A005D9400 /* KRTexturePVR.h in Headers */, E4CA10EC1637BD47005D9400 /* KRTextureTGA.h in Headers */, @@ -1310,9 +1453,10 @@ E499BF2016AE755B007FCDBE /* KRPointLight.h in Headers */, E499BF2116AE75A7007FCDBE /* KREngine-common.h in Headers */, E404702218695DD200F01F42 /* KRTextureKTX.h in Headers */, + E45E03C918790EC0006DA23F /* tinyxml2.h in Headers */, E4F027D016979CE200D4427D /* KRAudioSample.h in Headers */, E450273B16E0491D00FDEC5C /* KRReverbZone.h in Headers */, - E4FE6AA816B21D660058B8CE /* forsyth.h in Headers */, + E416E4881879111300FC2EEB /* Recast.h in Headers */, E4AE635F1704FB0A00B460CD /* KRLODGroup.h in Headers */, E4EC73C31720B1FF0065299F /* KRVector4.h in Headers */, E48CF944173453990005EBBB /* KRFloat.h in Headers */, @@ -1325,11 +1469,14 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + E45E03BD18790DD1006DA23F /* PVRTTexture.h in Headers */, E497B948151BB89D00D3DC67 /* KRVector2.h in Headers */, E4D0683F1512A790005FFBEB /* KRVector3.h in Headers */, E461A177152E5C6600F2044A /* KRMat4.h in Headers */, E4F975461536327C00FD60B2 /* KRMeshManager.h in Headers */, + E45E03B618790DD1006DA23F /* PVRTextureFormat.h in Headers */, E497B94B151BCEE900D3DC67 /* KRResource.h in Headers */, + E45E03B318790DD1006DA23F /* PVRTError.h in Headers */, E43B0AD915DDCA0F00A5CB9F /* KRContextObject.h in Headers */, E4F975331536220900FD60B2 /* KRNode.h in Headers */, E4B2A4391523B027004CB0EC /* KRMaterial.h in Headers */, @@ -1341,6 +1488,7 @@ E46DBE851512B9FA00D59F86 /* KREngine-common.h in Headers */, E488399715F928CA00BD66D5 /* KRBundle.h in Headers */, E4F9754C153632F000FD60B2 /* KRCamera.h in Headers */, + E45E03BA18790DD1006DA23F /* PVRTGlobal.h in Headers */, E4F975501536333500FD60B2 /* KRMesh.h in Headers */, E488399F15F92BE000BD66D5 /* KRBundleManager.h in Headers */, E4AFC6BC15F7C95D00DDB4C8 /* KRSceneManager.h in Headers */, @@ -1354,47 +1502,59 @@ E428C3051669627900A16EDF /* KRAnimationCurve.h in Headers */, E48C697015374F5B00232E28 /* KRContext.h in Headers */, E46F4A10155E004100CCF8B8 /* KRDataBlock.cpp in Headers */, - E46C214815364BC8009CABF3 /* tinyxml2.h in Headers */, + E45E03B418790DD1006DA23F /* PVRTexture.h in Headers */, E4D13365153767FF0070068C /* KRShaderManager.h in Headers */, E40BA45715EFF79500D7C3DD /* KRAABB.h in Headers */, E428C312166971FF00A16EDF /* KRAnimationLayer.h in Headers */, E4AFC6B615F7C46800DDB4C8 /* KRAABB.cpp in Headers */, + E45E03B818790DD1006DA23F /* PVRTextureUtilities.h in Headers */, E428C3171669A24B00A16EDF /* KRAnimationAttribute.h in Headers */, E4AFC6BE15F7C9E600DDB4C8 /* KROctreeNode.h in Headers */, + E416E48D1879111300FC2EEB /* RecastAssert.h in Headers */, + E45E03B918790DD1006DA23F /* PVRTextureVersion.h in Headers */, E4AFC6BD15F7C9DA00DDB4C8 /* KROctree.h in Headers */, E46A6B701559EF0A000DBD37 /* KRResource+blend.h in Headers */, E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */, + E416E4891879111300FC2EEB /* Recast.h in Headers */, E42CB1ED158446940066E0D8 /* KRQuaternion.h in Headers */, E4030E4D160A3CF000592648 /* KRStockGeometry.h in Headers */, E4B175AF161F5A1000B8FB80 /* KRTexture.h in Headers */, E480BE691671C641004EC8AD /* KRBone.h in Headers */, E4B175B5161F5FAF00B8FB80 /* KRTextureCube.h in Headers */, + E45E03B118790DD1006DA23F /* PVRTArray.h in Headers */, + E45E03CA18790EC0006DA23F /* tinyxml2.h in Headers */, E4CA10E61637BD0A005D9400 /* KRTexturePVR.h in Headers */, E4CA10ED1637BD47005D9400 /* KRTextureTGA.h in Headers */, + E45E03D018790EFF006DA23F /* forsyth.h in Headers */, E4CA11751639CBD6005D9400 /* KRViewport.h in Headers */, E461A15D152E563100F2044A /* KRDirectionalLight.h in Headers */, E461A169152E570700F2044A /* KRSpotLight.h in Headers */, + E45E03B218790DD1006DA23F /* PVRTDecompress.h in Headers */, E4C454B9167BD236003586CD /* KRHitInfo.h in Headers */, E4324BA516444C0D0043185B /* KRParticleSystem.h in Headers */, E4324BAC16444DEF0043185B /* KRParticleSystemNewtonian.h in Headers */, + E45E03B518790DD1006DA23F /* PVRTextureDefines.h in Headers */, E4C454AD167BB8EC003586CD /* KRMeshCube.h in Headers */, E404702318695DD200F01F42 /* KRTextureKTX.h in Headers */, E414F9A91694D977000B3D58 /* KRUnknownManager.h in Headers */, E48B68181697794F00D99917 /* KRAudioSource.h in Headers */, E4F027CA16979CCD00D4427D /* KRAudioManager.h in Headers */, E4F027D116979CE200D4427D /* KRAudioSample.h in Headers */, + E45E03B718790DD1006DA23F /* PVRTextureHeader.h in Headers */, E4F027E11697BFFF00D4427D /* KRAudioBuffer.h in Headers */, E4943234169E08D200BCB891 /* KRAmbientZone.h in Headers */, E414F9AF1694DA37000B3D58 /* KRUnknown.h in Headers */, E499BF2216AE760F007FCDBE /* krengine_osx.h in Headers */, - E4FE6AA916B21D660058B8CE /* forsyth.h in Headers */, E4C454B3167BC04C003586CD /* KRMeshSphere.h in Headers */, E450273C16E0491D00FDEC5C /* KRReverbZone.h in Headers */, + E45E03BB18790DD1006DA23F /* PVRTMap.h in Headers */, E44F38251683B23000399B5D /* KRRenderSettings.h in Headers */, + E45E03BC18790DD1006DA23F /* PVRTString.h in Headers */, E499BF1D16AE74FF007FCDBE /* KRTextureAnimated.h in Headers */, E4EC73C41720B1FF0065299F /* KRVector4.h in Headers */, E468448217FFDF51001F1FA1 /* KRLocator.h in Headers */, E43F70DF181B20E400136169 /* KRLODSet.h in Headers */, + E416E48B1879111300FC2EEB /* RecastAlloc.h in Headers */, E4AE63601704FB0A00B460CD /* KRLODGroup.h in Headers */, E45134B91746A4A300443C21 /* KRBehavior.h in Headers */, E43F71021824E73100136169 /* KRMeshStreamer.h in Headers */, @@ -1608,41 +1768,52 @@ E491019113C99BDC0098455B /* KRMesh.cpp in Sources */, E491019313C99BDC0098455B /* KRMaterialManager.cpp in Sources */, E491019413C99BDC0098455B /* KRMaterial.cpp in Sources */, + E416E49E1879112700FC2EEB /* RecastContour.cpp in Sources */, E491019713C99BDC0098455B /* KRVector3.cpp in Sources */, E491019813C99BDC0098455B /* KRTextureManager.cpp in Sources */, E491019913C99BDC0098455B /* KRTexture2D.cpp in Sources */, + E416E4AA1879112700FC2EEB /* RecastRegion.cpp in Sources */, E491019A13C99BDC0098455B /* KRMeshManager.cpp in Sources */, + E45E03C718790EC0006DA23F /* tinyxml2.cpp in Sources */, + E45E03CD18790EFF006DA23F /* forsyth.cpp in Sources */, E47C25A713F4F6AB00FF4370 /* KRShaderManager.cpp in Sources */, E47C25A913F4F6DD00FF4370 /* KRShader.cpp in Sources */, + E416E4A41879112700FC2EEB /* RecastMesh.cpp in Sources */, E43F70DC181B20E400136169 /* KRLODSet.cpp in Sources */, E414BAE51435558900A668C4 /* KRModel.cpp in Sources */, E414BAE91435585A00A668C4 /* KRScene.cpp in Sources */, E48B3CC014393E30000C50E2 /* KRCamera.cpp in Sources */, + E416E4A61879112700FC2EEB /* RecastMeshDetail.cpp in Sources */, E497B946151BA99500D3DC67 /* KRVector2.cpp in Sources */, E497B94D151BCF2500D3DC67 /* KRResource.cpp in Sources */, + E416E4981879112700FC2EEB /* Recast.cpp in Sources */, E497B950151BD2CE00D3DC67 /* KRResource+obj.cpp in Sources */, E43F70FF1824E73100136169 /* KRMeshStreamer.mm in Sources */, E461A156152E54F800F2044A /* KRLight.cpp in Sources */, E461A159152E557E00F2044A /* KRPointLight.cpp in Sources */, E468447F17FFDF51001F1FA1 /* KRLocator.cpp in Sources */, E461A15F152E565700F2044A /* KRDirectionalLight.cpp in Sources */, + E416E4A21879112700FC2EEB /* RecastLayers.cpp in Sources */, E461A165152E56C000F2044A /* KRSpotLight.cpp in Sources */, E4F975361536221C00FD60B2 /* KRNode.cpp in Sources */, - E46C214515364BC8009CABF3 /* tinyxml2.cpp in Sources */, E46C214B15364DEC009CABF3 /* KRSceneManager.cpp in Sources */, E48C697215374F7E00232E28 /* KRContext.cpp in Sources */, E46F4A0E155E003000CCF8B8 /* KRDataBlock.cpp in Sources */, + E416E49A1879112700FC2EEB /* RecastAlloc.cpp in Sources */, E42CB1F0158446AB0066E0D8 /* KRQuaternion.cpp in Sources */, E43B0AD615DDCA0F00A5CB9F /* KRContextObject.cpp in Sources */, E4924C2615EE95E800B965C6 /* KROctree.cpp in Sources */, + E416E4A81879112700FC2EEB /* RecastRasterization.cpp in Sources */, E4924C2B15EE96AB00B965C6 /* KROctreeNode.cpp in Sources */, E404702018695DD200F01F42 /* KRTextureKTX.cpp in Sources */, E40BA45415EFF79500D7C3DD /* KRAABB.cpp in Sources */, + E416E49C1879112700FC2EEB /* RecastArea.cpp in Sources */, E488399415F928CA00BD66D5 /* KRBundle.cpp in Sources */, E488399C15F92BE000BD66D5 /* KRBundleManager.cpp in Sources */, E4B175AC161F5A1000B8FB80 /* KRTexture.cpp in Sources */, E4B175B2161F5FAF00B8FB80 /* KRTextureCube.cpp in Sources */, E4CA10E91637BD2B005D9400 /* KRTexturePVR.cpp in Sources */, + E416E4A01879112700FC2EEB /* RecastFilter.cpp in Sources */, E4CA10EF1637BD58005D9400 /* KRTextureTGA.cpp in Sources */, E4CA11781639CC90005D9400 /* KRViewport.cpp in Sources */, E4324BA816444C230043185B /* KRParticleSystem.cpp in Sources */, @@ -1670,7 +1841,6 @@ E4F027CE16979CE200D4427D /* KRAudioSample.cpp in Sources */, E4F027DE1697BFFF00D4427D /* KRAudioBuffer.cpp in Sources */, E4943231169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, - E4FE6AAB16B21D7E0058B8CE /* forsyth.cpp in Sources */, E450273916E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, E4AE635D1704FB0A00B460CD /* KRLODGroup.cpp in Sources */, E4EC73C11720B1FF0065299F /* KRVector4.cpp in Sources */, @@ -1683,7 +1853,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E4EC73B8171F32780065299F /* forsyth.cpp in Sources */, E499BF2516AE8C20007FCDBE /* KREngine.mm in Sources */, 10CC33A5168534F000BB9846 /* KRCamera.cpp in Sources */, E460292C166834AB00261BB9 /* KRTextureAnimated.cpp in Sources */, @@ -1691,6 +1860,7 @@ E461A175152E5C4800F2044A /* KRLight.cpp in Sources */, E4BBBBA71512A6DC00F43B5B /* KRVector3.cpp in Sources */, E4B2A43B1523B02E004CB0EC /* KRMaterial.cpp in Sources */, + E416E4A71879112700FC2EEB /* RecastMeshDetail.cpp in Sources */, E4BBBB8E1512A40300F43B5B /* krengine_osx.mm in Sources */, E468448017FFDF51001F1FA1 /* KRLocator.cpp in Sources */, E497B947151BA99500D3DC67 /* KRVector2.cpp in Sources */, @@ -1698,18 +1868,23 @@ E497B951151BD2CE00D3DC67 /* KRResource+obj.cpp in Sources */, E497B954151BEDA600D3DC67 /* KRResource+fbx.cpp in Sources */, E4F97551153633E200FD60B2 /* KRMaterialManager.cpp in Sources */, + E416E49F1879112700FC2EEB /* RecastContour.cpp in Sources */, E461A15A152E557E00F2044A /* KRPointLight.cpp in Sources */, + E45E03C818790EC0006DA23F /* tinyxml2.cpp in Sources */, E4F9754F1536333200FD60B2 /* KRMesh.cpp in Sources */, E4F9754B153632D800FD60B2 /* KRMeshManager.cpp in Sources */, + E416E4A31879112700FC2EEB /* RecastLayers.cpp in Sources */, E461A160152E565700F2044A /* KRDirectionalLight.cpp in Sources */, E4F975531536340000FD60B2 /* KRTexture2D.cpp in Sources */, E4F9754015362CD400FD60B2 /* KRScene.cpp in Sources */, E461A166152E56C000F2044A /* KRSpotLight.cpp in Sources */, E4F9754315362D0F00FD60B2 /* KRModel.cpp in Sources */, + E416E4A11879112700FC2EEB /* RecastFilter.cpp in Sources */, + E45E03CE18790EFF006DA23F /* forsyth.cpp in Sources */, + E416E4991879112700FC2EEB /* Recast.cpp in Sources */, E4F975371536221C00FD60B2 /* KRNode.cpp in Sources */, E4F9754E1536331D00FD60B2 /* KRTextureManager.cpp in Sources */, E4D13367153768610070068C /* KRShader.cpp in Sources */, - E46C214615364BC8009CABF3 /* tinyxml2.cpp in Sources */, E4D13364153767ED0070068C /* KRShaderManager.cpp in Sources */, E4AFC6B915F7C7B200DDB4C8 /* KROctree.cpp in Sources */, E46C214C15364DEC009CABF3 /* KRSceneManager.cpp in Sources */, @@ -1719,6 +1894,7 @@ E46F4A0F155E003000CCF8B8 /* KRDataBlock.cpp in Sources */, E42CB1F1158446AB0066E0D8 /* KRQuaternion.cpp in Sources */, E4AFC6BB15F7C7D600DDB4C8 /* KROctreeNode.cpp in Sources */, + E416E4A51879112700FC2EEB /* RecastMesh.cpp in Sources */, E43B0AD715DDCA0F00A5CB9F /* KRContextObject.cpp in Sources */, E40BA45515EFF79500D7C3DD /* KRAABB.cpp in Sources */, E488399515F928CA00BD66D5 /* KRBundle.cpp in Sources */, @@ -1726,6 +1902,7 @@ E43F70DD181B20E400136169 /* KRLODSet.cpp in Sources */, E43F71001824E73100136169 /* KRMeshStreamer.mm in Sources */, E4B175AD161F5A1000B8FB80 /* KRTexture.cpp in Sources */, + E416E4AB1879112700FC2EEB /* RecastRegion.cpp in Sources */, E4B175B3161F5FAF00B8FB80 /* KRTextureCube.cpp in Sources */, E40F9833184A7BAC00CFA4D8 /* KRSprite.cpp in Sources */, E4CA10EA1637BD2B005D9400 /* KRTexturePVR.cpp in Sources */, @@ -1752,11 +1929,14 @@ E4F027C816979CCD00D4427D /* KRAudioManager.cpp in Sources */, E4F027CF16979CE200D4427D /* KRAudioSample.cpp in Sources */, E4F027DF1697BFFF00D4427D /* KRAudioBuffer.cpp in Sources */, + E416E4A91879112700FC2EEB /* RecastRasterization.cpp in Sources */, E4943232169E08D200BCB891 /* KRAmbientZone.cpp in Sources */, E404702118695DD200F01F42 /* KRTextureKTX.cpp in Sources */, E450273A16E0491D00FDEC5C /* KRReverbZone.cpp in Sources */, + E416E49B1879112700FC2EEB /* RecastAlloc.cpp in Sources */, E4AE635E1704FB0A00B460CD /* KRLODGroup.cpp in Sources */, E4EC73C21720B1FF0065299F /* KRVector4.cpp in Sources */, + E416E49D1879112700FC2EEB /* RecastArea.cpp in Sources */, E48CF943173453990005EBBB /* KRFloat.cpp in Sources */, E45134B71746A4A300443C21 /* KRBehavior.cpp in Sources */, );