diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/meshimport/src | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/general/meshimport/src')
27 files changed, 17914 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.cpp new file mode 100644 index 00000000..b47b6a65 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.cpp @@ -0,0 +1,664 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include "ExportAPX.h" +#include "MeshImport.h" +#include "MiFloatMath.h" +#include "MiMemoryBuffer.h" +#include "MiIOStream.h" +#include "MiFileInterface.h" + + +#pragma warning(disable:4100 4996) + +namespace mimp +{ + +static const char * getFloatString(MiF32 v) +{ + static char data[64*16]; + static MiI32 index=0; + + char *ret = &data[index*64]; + index++; + if (index == 16 ) index = 0; + +// This is not cross-platform, removing for now +#if 0 + if ( !_finite(v) ) + { + assert(0); + strcpy(ret,"0"); // not a valid number! + } + else +#endif + if ( v == 1 ) + { + strcpy(ret,"1"); + } + else if ( v == 0 ) + { + strcpy(ret,"0"); + } + else if ( v == - 1 ) + { + strcpy(ret,"-1"); + } + else + { + sprintf(ret,"%.9f", v ); + const char *dot = strstr(ret,"."); + if ( dot ) + { + MiI32 len = (MiI32)strlen(ret); + char *foo = &ret[len-1]; + while ( *foo == '0' ) foo--; + if ( *foo == '.' ) + *foo = 0; + else + foo[1] = 0; + } + } + + return ret; +} + + + +// Support for ridiculous completely hard coded data format enum +struct RenderDataFormat +{ + /** \brief the enum type */ + enum Enum + { + UNSPECIFIED = 0, //!< No format (semantic not used) + + //!< Integer formats + UBYTE1 = 1, //!< One unsigned 8-bit integer (uint8_t[1]) + UBYTE2 = 2, //!< Two unsigned 8-bit integers (uint8_t[2]) + UBYTE3 = 3, //!< Three unsigned 8-bit integers (uint8_t[3]) + UBYTE4 = 4, //!< Four unsigned 8-bit integers (uint8_t[4]) + + USHORT1 = 5, //!< One unsigned 16-bit integer (uint16_t[1]) + USHORT2 = 6, //!< Two unsigned 16-bit integers (uint16_t[2]) + USHORT3 = 7, //!< Three unsigned 16-bit integers (uint16_t[3]) + USHORT4 = 8, //!< Four unsigned 16-bit integers (uint16_t[4]) + + SHORT1 = 9, //!< One signed 16-bit integer (int16_t[1]) + SHORT2 = 10, //!< Two signed 16-bit integers (int16_t[2]) + SHORT3 = 11, //!< Three signed 16-bit integers (int16_t[3]) + SHORT4 = 12, //!< Four signed 16-bit integers (int16_t[4]) + + UINT1 = 13, //!< One unsigned integer (uint32_t[1]) + UINT2 = 14, //!< Two unsigned integers (uint32_t[2]) + UINT3 = 15, //!< Three unsigned integers (uint32_t[3]) + UINT4 = 16, //!< Four unsigned integers (uint32_t[4]) + + //!< Color formats + R8G8B8A8 = 17, //!< Four unsigned bytes (uint8_t[4]) representing red, green, blue, alpha + B8G8R8A8 = 18, //!< Four unsigned bytes (uint8_t[4]) representing blue, green, red, alpha + R32G32B32A32_FLOAT = 19, //!< Four floats (float[4]) representing red, green, blue, alpha + B32G32R32A32_FLOAT = 20, //!< Four floats (float[4]) representing blue, green, red, alpha + + //!< Normalized formats + BYTE_UNORM1 = 21, //!< One unsigned normalized value in the range [0,1], packed into 8 bits (uint8_t[1]) + BYTE_UNORM2 = 22, //!< Two unsigned normalized value in the range [0,1], each packed into 8 bits (uint8_t[2]) + BYTE_UNORM3 = 23, //!< Three unsigned normalized value in the range [0,1], each packed into bits (uint8_t[3]) + BYTE_UNORM4 = 24, //!< Four unsigned normalized value in the range [0,1], each packed into 8 bits (uint8_t[4]) + + SHORT_UNORM1 = 25, //!< One unsigned normalized value in the range [0,1], packed into 16 bits (uint16_t[1]) + SHORT_UNORM2 = 26, //!< Two unsigned normalized value in the range [0,1], each packed into 16 bits (uint16_t[2]) + SHORT_UNORM3 = 27, //!< Three unsigned normalized value in the range [0,1], each packed into 16 bits (uint16_t[3]) + SHORT_UNORM4 = 28, //!< Four unsigned normalized value in the range [0,1], each packed into 16 bits (uint16_t[4]) + + BYTE_SNORM1 = 29, //!< One signed normalized value in the range [-1,1], packed into 8 bits (uint8_t[1]) + BYTE_SNORM2 = 30, //!< Two signed normalized value in the range [-1,1], each packed into 8 bits (uint8_t[2]) + BYTE_SNORM3 = 31, //!< Three signed normalized value in the range [-1,1], each packed into bits (uint8_t[3]) + BYTE_SNORM4 = 32, //!< Four signed normalized value in the range [-1,1], each packed into 8 bits (uint8_t[4]) + + SHORT_SNORM1 = 33, //!< One signed normalized value in the range [-1,1], packed into 16 bits (uint16_t[1]) + SHORT_SNORM2 = 34, //!< Two signed normalized value in the range [-1,1], each packed into 16 bits (uint16_t[2]) + SHORT_SNORM3 = 35, //!< Three signed normalized value in the range [-1,1], each packed into 16 bits (uint16_t[3]) + SHORT_SNORM4 = 36, //!< Four signed normalized value in the range [-1,1], each packed into 16 bits (uint16_t[4]) + + //!< Float formats + HALF1 = 37, //!< One 16-bit floating point value + HALF2 = 38, //!< Two 16-bit floating point values + HALF3 = 39, //!< Three 16-bit floating point values + HALF4 = 40, //!< Four 16-bit floating point values + + FLOAT1 = 41, //!< One 32-bit floating point value + FLOAT2 = 42, //!< Two 32-bit floating point values + FLOAT3 = 43, //!< Three 32-bit floating point values + FLOAT4 = 44, //!< Four 32-bit floating point values + + FLOAT4x4 = 45, //!< A 4x4 matrix (see physx::PxMat34) + FLOAT3x3 = 46, //!< A 3x3 matrix (see physx::PxMat33) + + FLOAT4_QUAT = 47, //!< A quaternion (see physx::PxQuat) + BYTE_SNORM4_QUATXYZW = 48, //!< A normalized quaternion with signed byte elements, X,Y,Z,W format (uint8_t[4]) + SHORT_SNORM4_QUATXYZW = 49, //!< A normalized quaternion with signed short elements, X,Y,Z,W format (uint16_t[4]) + + NUM_FORMATS + }; +}; + + +struct TempSubMesh +{ + + TempSubMesh(Mesh *m,SubMesh *sm) + { + mVertexCount = 0; + mIndexRemap = new MiU32[m->mVertexCount]; + mVertices = new MeshVertex[m->mVertexCount]; + memset(mIndexRemap,0xFF,sizeof(MiU32)*m->mVertexCount); + + for (MiU32 i=0; i<sm->mTriCount*3; i++) + { + MiU32 index = sm->mIndices[i]; + if ( mIndexRemap[index] == 0xFFFFFFFF ) + { + mIndexRemap[index] = mVertexCount; + mVertices[mVertexCount] = m->mVertices[index]; + mVertexCount++; + } + } + mIndices = new MiU32[sm->mTriCount*3]; + for (MiU32 i=0; i<sm->mTriCount*3; i++) + { + mIndices[i] = mIndexRemap[ sm->mIndices[i] ]; + } + } + + ~TempSubMesh(void) + { + delete []mVertices; + delete []mIndices; + delete []mIndexRemap; + } + + + MiU32 mVertexCount; + MeshVertex *mVertices; + MiU32 *mIndices; + MiU32 *mIndexRemap; +}; + +struct RenderVertexSemantic +{ + /** + \brief Enum of vertex buffer semantics types + */ + enum Enum + { + CUSTOM = -1, //!< User-defined + + POSITION = 0, //!< Position of vertex + NORMAL, //!< Normal at vertex + TANGENT, //!< Tangent at vertex + BINORMAL, //!< Binormal at vertex + COLOR, //!< Color at vertex + TEXCOORD0, //!< Texture coord 0 of vertex + TEXCOORD1, //!< Texture coord 1 of vertex + TEXCOORD2, //!< Texture coord 2 of vertex + TEXCOORD3, //!< Texture coord 3 of vertex + BONE_INDEX, //!< Bone index of vertex + BONE_WEIGHT, //!< Bone weight of vertex + + DISPLACEMENT_TEXCOORD, //!< X Displacement map texture coord of vertex + DISPLACEMENT_FLAGS, //!< Displacement map flags of vertex + + NUM_SEMANTICS //!< Count of standard semantics, not a valid semantic + }; +}; + +MI_INLINE MiU32 hash(const char* string) +{ + // "DJB" string hash + MiU32 h = 5381; + char c; + while ((c = *string++) != '\0') + { + h = ((h << 5) + h) ^ c; + } + return h; +} + +struct SemanticNameAndID +{ + SemanticNameAndID(const char* name, MiU32 id) : m_name(name), m_id(id) + { + MI_ASSERT(m_id != 0 || strcmp(m_name, "SEMANTIC_INVALID") == 0); + } + const char* m_name; + MiU32 m_id; +}; + +#define SEMANTIC_NAME_AND_ID( name ) SemanticNameAndID( name, (MiU32)hash( name ) ) + +static const SemanticNameAndID sSemanticNamesAndIDs[] = +{ + SEMANTIC_NAME_AND_ID("SEMANTIC_POSITION"), + SEMANTIC_NAME_AND_ID("SEMANTIC_NORMAL"), + SEMANTIC_NAME_AND_ID("SEMANTIC_TANGENT"), + SEMANTIC_NAME_AND_ID("SEMANTIC_BINORMAL"), + SEMANTIC_NAME_AND_ID("SEMANTIC_COLOR"), + SEMANTIC_NAME_AND_ID("SEMANTIC_TEXCOORD0"), + SEMANTIC_NAME_AND_ID("SEMANTIC_TEXCOORD1"), + SEMANTIC_NAME_AND_ID("SEMANTIC_TEXCOORD2"), + SEMANTIC_NAME_AND_ID("SEMANTIC_TEXCOORD3"), + SEMANTIC_NAME_AND_ID("SEMANTIC_BONE_INDEX"), + SEMANTIC_NAME_AND_ID("SEMANTIC_BONE_WEIGHT"), + SEMANTIC_NAME_AND_ID("SEMANTIC_DISPLACEMENT_TEXCOORD"), + SEMANTIC_NAME_AND_ID("SEMANTIC_DISPLACEMENT_FLAGS"), + + SemanticNameAndID("SEMANTIC_INVALID", (MiU32)0) +}; + +static const char* getSemanticName(RenderVertexSemantic::Enum semantic) +{ + MI_ASSERT((MiU32)semantic < RenderVertexSemantic::NUM_SEMANTICS); + return (MiU32)semantic < RenderVertexSemantic::NUM_SEMANTICS ? sSemanticNamesAndIDs[semantic].m_name : NULL; +} + + +static MiU32 getSemanticID(RenderVertexSemantic::Enum semantic) +{ + MI_ASSERT((MiU32)semantic < RenderVertexSemantic::NUM_SEMANTICS); + return (MiU32)semantic < RenderVertexSemantic::NUM_SEMANTICS ? sSemanticNamesAndIDs[semantic].m_id : (MiU32)0; +} + + + +void semanticStruct(MiU32 flags,MiU32 mask,RenderVertexSemantic::Enum semantic,RenderDataFormat::Enum format,FILE_INTERFACE *fph) +{ + if ( flags & mask ) + { + fi_fprintf(fph," <struct>\r\n"); + fi_fprintf(fph," <value name=\"name\" type=\"String\">%s</value>\r\n",getSemanticName(semantic)); + fi_fprintf(fph," <value name=\"semantic\" type=\"I32\">%d</value>\r\n", semantic); + fi_fprintf(fph," <value name=\"id\" type=\"U32\">%u</value>\r\n", getSemanticID(semantic)); + fi_fprintf(fph," <value name=\"format\" type=\"U32\">%d</value>\r\n",format); + fi_fprintf(fph," <value name=\"access\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph," <value name=\"serialize\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph," </struct>\r\n"); + } +} + +static const char * getFormatString(RenderDataFormat::Enum format) +{ + const char *ret = NULL; + switch ( format ) + { + case RenderDataFormat::FLOAT4: + ret = "BufferF32x4"; + break; + case RenderDataFormat::FLOAT3: + ret = "BufferF32x3"; + break; + case RenderDataFormat::FLOAT2: + ret = "BufferF32x2"; + break; + case RenderDataFormat::USHORT4: + ret = "BufferU16x4"; + break; + case RenderDataFormat::UINT1: + ret = "BufferU32x1"; + break; + default: + MI_ALWAYS_ASSERT(); + break; + } + return ret; +} + +static const char * typeString(RenderDataFormat::Enum format) +{ + const char *ret = NULL; + switch ( format ) + { + case RenderDataFormat::FLOAT3: + ret = "Vec3"; + break; + case RenderDataFormat::UINT1: + ret = "U32"; + break; + case RenderDataFormat::FLOAT4: + case RenderDataFormat::USHORT4: + case RenderDataFormat::FLOAT2: + ret = "Struct"; + break; + default: + MI_ALWAYS_ASSERT(); + break; + } + return ret; +} + +static void semanticBuffer(MiU32 flags,MiU32 mask,RenderDataFormat::Enum format,MiU32 bufferCount,const MiU8 *scan,MiU32 bufferStride,FILE_INTERFACE *fph) +{ + if ( !(flags & mask) ) return; + + fi_fprintf(fph," <value type=\"Ref\" included=\"1\" className=\"%s\" version=\"0.0\" >\r\n", getFormatString(format)); + fi_fprintf(fph," <struct name=\"\">\r\n"); + + switch ( format ) + { + case RenderDataFormat::USHORT4: + fi_fprintf(fph," <array name=\"data\" size=\"%d\" type=\"%s\" structElements=\"x(U16),y(U16),z(U16),w(U16)\">\r\n", bufferCount, typeString(format)); + break; + case RenderDataFormat::FLOAT4: + fi_fprintf(fph," <array name=\"data\" size=\"%d\" type=\"%s\" structElements=\"x(F32),y(F32),z(F32),w(F32)\">\r\n", bufferCount, typeString(format)); + break; + case RenderDataFormat::FLOAT2: + fi_fprintf(fph," <array name=\"data\" size=\"%d\" type=\"%s\" structElements=\"x(F32),y(F32)\">\r\n", bufferCount, typeString(format)); + break; + case RenderDataFormat::FLOAT3: + case RenderDataFormat::UINT1: + fi_fprintf(fph," <array name=\"data\" size=\"%d\" type=\"%s\">\r\n", bufferCount, typeString(format)); + break; + default: + MI_ALWAYS_ASSERT(); + break; + } + + fi_fprintf(fph," "); + + for (MiU32 i=0; i<bufferCount; i++) + { + const MiF32 *p = (const MiF32 *)scan; + switch ( format ) + { + case RenderDataFormat::FLOAT4: + fi_fprintf(fph,"%s %s %s ", getFloatString(p[0]), getFloatString(p[1]), getFloatString(p[2]), getFloatString(p[3]) ); + if ( (i&3) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + break; + + case RenderDataFormat::FLOAT3: + fi_fprintf(fph,"%s %s %s ", getFloatString(p[0]), getFloatString(p[1]), getFloatString(p[2]) ); + if ( (i&3) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + break; + case RenderDataFormat::FLOAT2: + fi_fprintf(fph,"%s %s ", getFloatString(p[0]), getFloatString(p[1]) ); + if ( (i&7) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + break; + case RenderDataFormat::USHORT4: + { + const MiU16 *us = (const MiU16 *)scan; + fi_fprintf(fph,"%d %d %d %d ", us[0], us[1], us[2], us[3] ); + if ( (i&7) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + } + break; + case RenderDataFormat::UINT1: + { + const MiU32 *us = (const MiU32 *)scan; + fi_fprintf(fph,"%d ", us[0]); + if ( (i&31) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + } + break; + default: + MI_ALWAYS_ASSERT(); + break; + } + scan+=bufferStride; + } + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph," </value>\r\n"); + +} + +static void exportSubMesh(Mesh *m,SubMesh *sm,FILE_INTERFACE *fph) +{ + TempSubMesh tms(m,sm); + + MiU32 flags = m->mVertexFlags; + MiU32 semanticCount = 0; + + if ( flags & MIVF_POSITION ) + { + semanticCount++; + } + if ( flags & MIVF_NORMAL ) + { + semanticCount++; + } + if ( flags & MIVF_TANGENT ) + { + semanticCount++; + } + if ( flags & MIVF_BINORMAL ) + { + semanticCount++; + } + if ( flags & MIVF_COLOR ) + { + semanticCount++; + } + if ( flags & MIVF_TEXEL1 ) + { + semanticCount++; + } + if ( flags & MIVF_TEXEL2 ) + { + semanticCount++; + } + if ( flags & MIVF_TEXEL3 ) + { + semanticCount++; + } + if ( flags & MIVF_TEXEL4 ) + { + semanticCount++; + } + if ( flags & MIVF_BONE_WEIGHTING ) + { + semanticCount+=2; + } + + + fi_fprintf(fph," <value type=\"Ref\" included=\"1\" className=\"SubmeshParameters\" version=\"0.0\" >\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + fi_fprintf(fph," <value name=\"vertexBuffer\" type=\"Ref\" included=\"1\" className=\"VertexBufferParameters\" version=\"0.0\" >\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + fi_fprintf(fph," <value name=\"vertexCount\" type=\"U32\">%d</value>\r\n", tms.mVertexCount); + fi_fprintf(fph," <value name=\"vertexFormat\" type=\"Ref\" included=\"1\" className=\"VertexFormatParameters\" version=\"0.0\" >\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + fi_fprintf(fph," <value name=\"winding\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph," <value name=\"hasSeparateBoneBuffer\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph," <array name=\"bufferFormats\" size=\"%d\" type=\"Struct\">\r\n", semanticCount); + + semanticStruct(flags,MIVF_POSITION,RenderVertexSemantic::POSITION,RenderDataFormat::FLOAT3,fph); + semanticStruct(flags,MIVF_NORMAL,RenderVertexSemantic::NORMAL,RenderDataFormat::FLOAT3,fph); + semanticStruct(flags,MIVF_TANGENT,RenderVertexSemantic::TANGENT,RenderDataFormat::FLOAT3,fph); + semanticStruct(flags,MIVF_BINORMAL,RenderVertexSemantic::BINORMAL,RenderDataFormat::FLOAT3,fph); + semanticStruct(flags,MIVF_COLOR,RenderVertexSemantic::COLOR,RenderDataFormat::UINT1,fph); + semanticStruct(flags,MIVF_TEXEL1,RenderVertexSemantic::TEXCOORD0,RenderDataFormat::FLOAT2,fph); + semanticStruct(flags,MIVF_TEXEL2,RenderVertexSemantic::TEXCOORD1,RenderDataFormat::FLOAT2,fph); + semanticStruct(flags,MIVF_TEXEL3,RenderVertexSemantic::TEXCOORD2,RenderDataFormat::FLOAT2,fph); + semanticStruct(flags,MIVF_TEXEL4,RenderVertexSemantic::TEXCOORD3,RenderDataFormat::FLOAT2,fph); + semanticStruct(flags,MIVF_BONE_WEIGHTING,RenderVertexSemantic::BONE_INDEX,RenderDataFormat::USHORT4,fph); + semanticStruct(flags,MIVF_BONE_WEIGHTING,RenderVertexSemantic::BONE_WEIGHT,RenderDataFormat::FLOAT4,fph); + + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph," </value>\r\n"); + + fi_fprintf(fph," <array name=\"buffers\" size=\"%d\" type=\"Ref\">\r\n", semanticCount); + + semanticBuffer(flags,MIVF_POSITION,RenderDataFormat::FLOAT3, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mPos,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_NORMAL,RenderDataFormat::FLOAT3, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mNormal,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_TANGENT,RenderDataFormat::FLOAT3, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mTangent,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_BINORMAL,RenderDataFormat::FLOAT3, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mBiNormal,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_COLOR,RenderDataFormat::UINT1, tms.mVertexCount, (const MiU8 *)(&tms.mVertices[0].mColor),sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_TEXEL1,RenderDataFormat::FLOAT2, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mTexel1,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_TEXEL2,RenderDataFormat::FLOAT2, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mTexel2,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_TEXEL3,RenderDataFormat::FLOAT2, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mTexel3,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_TEXEL4,RenderDataFormat::FLOAT2, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mTexel4,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_BONE_WEIGHTING,RenderDataFormat::USHORT4, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mBone,sizeof(MeshVertex),fph); + semanticBuffer(flags,MIVF_BONE_WEIGHTING,RenderDataFormat::FLOAT4, tms.mVertexCount, (const MiU8 *)tms.mVertices[0].mWeight,sizeof(MeshVertex),fph); + + + + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph," </value>\r\n"); + fi_fprintf(fph," <array name=\"indexBuffer\" size=\"%d\" type=\"U32\">\r\n", sm->mTriCount*3); + fi_fprintf(fph," "); + for (MiU32 i=0; i<sm->mTriCount*3; i++) + { + fi_fprintf(fph,"%d ", tms.mIndices[i]); + if ( (i&15) == 0 ) + { + fi_fprintf(fph,"\r\n "); + } + } + fi_fprintf(fph,"\r\n"); + + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," <array name=\"vertexPartition\" size=\"2\" type=\"U32\">\r\n"); + fi_fprintf(fph," 0 %d\r\n", tms.mVertexCount); + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," <array name=\"indexPartition\" size=\"2\" type=\"U32\">\r\n"); + fi_fprintf(fph," 0 %d\r\n", sm->mTriCount*3); + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph," </value>\r\n"); + + + + + + + +} + +void *serializeAPX(const MeshSystem *ms,MiU32 &len) +{ + void * ret = NULL; + len = 0; + + if ( ms ) + { + FILE_INTERFACE *fph = fi_fopen(ms->mAssetName,"wmem",NULL,0); + if ( fph ) + { + + + fi_fprintf(fph,"<!DOCTYPE NvParameters>\r\n"); + fi_fprintf(fph," <NvParameters numObjects=\"1\" version=\"1.0\" >\r\n"); + + + fi_fprintf(fph,"<value name=\"\" type=\"Ref\" className=\"RenderMeshAssetParameters\" version=\"0.0\">\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + + MiU32 subMeshCount=0; + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + Mesh *m = ms->mMeshes[i]; + subMeshCount+=m->mSubMeshCount; + } + + + fi_fprintf(fph,"<array name=\"submeshes\" size=\"%d\" type=\"Ref\">\r\n", subMeshCount ); + + + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + Mesh *m = ms->mMeshes[i]; + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + exportSubMesh(m,sm,fph); + } + } + + fi_fprintf(fph,"</array>\r\n"); + + + { + fi_fprintf(fph," <array name=\"materialNames\" size=\"%d\" type=\"String\">\r\n", subMeshCount ); + + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + Mesh *m = ms->mMeshes[i]; + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + fi_fprintf(fph," <value type=\"String\">%s</value>\r\n", sm->mMaterialName ); + } + } + fi_fprintf(fph,"</array>\r\n"); + } + + fi_fprintf(fph,"<array name=\"partBounds\" size=\"1\" type=\"Bounds3\">\r\n"); + + fi_fprintf(fph," %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f\r\n", + ms->mAABB.mMin[0], + ms->mAABB.mMin[1], + ms->mAABB.mMin[2], + ms->mAABB.mMax[0], + ms->mAABB.mMax[1], + ms->mAABB.mMax[2]); + + fi_fprintf(fph," </array>\r\n"); + fi_fprintf(fph," <value name=\"textureUVOrigin\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph," <value name=\"boneCount\" type=\"U32\">1</value>\r\n"); + fi_fprintf(fph," <value name=\"deleteStaticBuffersAfterUse\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph," <value name=\"isReferenced\" type=\"Bool\">false</value>\r\n"); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph," </value>\r\n"); + + fi_fprintf(fph," </NvParameters>\r\n"); + + size_t outLen; + void *outMem = fi_getMemBuffer(fph,&outLen); + if ( outMem ) + { + len = (MiU32)outLen; + if ( len ) + { + ret = MI_ALLOC(len); + memcpy(ret,outMem,len); + } + } + fi_fclose(fph); + } + } + return ret; +} + + +};// end of namespace + + + + diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.h new file mode 100644 index 00000000..81aff433 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef EXPORT_APX_H + +#define EXPORT_APX_H + +#include "MiFileInterface.h" +#include "MeshImport.h" + +namespace mimp +{ + +void * serializeAPX(const MeshSystem *ms,MiU32 &dlen); + +};// end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.cpp new file mode 100644 index 00000000..bfc6a181 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.cpp @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include "ExportDynamicSystem.h" +#include "MeshImport.h" +#include "MiFloatMath.h" +#include "MiMemoryBuffer.h" +#include "MiIOStream.h" +#include "MiFileInterface.h" + +#pragma warning(disable:4100) + +namespace mimp +{ + +const char * getMotionString(MiF32 v) +{ + const char *ret = "LOCKED"; + if ( v!=0 ) + { + ret = "LIMITED"; + } + return ret; +} + +const char * getMotionString(MiF32 v1,MiF32 v2) +{ + const char *ret = "LOCKED"; + if ( v1!=0 || v2 != 0) + { + ret = "LIMITED"; + } + return ret; +} + +void saveBodyPairCollision(const MeshSystem &ms,FILE_INTERFACE *fph) +{ + fi_fprintf(fph,"<array name=\"BodyPairCollisions\" size=\"%d\" type=\"Struct\">\r\n", ms.mMeshPairCollisionCount); + for (MiU32 i=0; i<ms.mMeshPairCollisionCount; i++) + { + MeshPairCollision &m = ms.mMeshPairCollisions[i]; + fi_fprintf(fph,"<struct>\r\n"); + fi_fprintf(fph,"<value name=\"ObjectA\" type=\"String\">%s</value>\r\n", m.mBody1 ); + fi_fprintf(fph,"<value name=\"ObjectB\" type=\"String\">%s</value>\r\n", m.mBody2 ); + fi_fprintf(fph,"</struct>\r\n"); + } + fi_fprintf(fph,"</array>\r\n"); +} + +const char * getJointType(const MeshSimpleJoint &msj) +{ + const char *ret; + + if ( strlen(msj.mName) == 0 ) + { + ret = "NONE"; + } + else if ( msj.mSwing1 == 0 && msj.mSwing2 == 0 ) + { + if ( msj.mTwistLow == 0 && msj.mTwistHigh == 0 ) + { + ret = "FIXED"; + } + else + { + ret = "HINGE"; + } + } + else if ( msj.mTwistLow == 0 && msj.mTwistHigh == 0 ) + { + ret = "SPHERICAL"; + } + else + { + ret = "BALLSOCKET"; + } + return ret; +} + +void saveJoint(const MeshSimpleJoint &msj,FILE_INTERFACE *fph) +{ + fi_fprintf(fph,"<value name=\"Joint\" type=\"Ref\" included=\"1\" className=\"SimpleJoint\" version=\"0.0\">\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"JointType\" type=\"Enum\">%s</value>\r\n", getJointType(msj)); + fi_fprintf(fph,"<value name=\"JointUserString\" type=\"String\"></value>\r\n"); + fi_fprintf(fph,"<value name=\"ConstraintAxis\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"Xaxis\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", msj.mXaxis[0], msj.mXaxis[1], msj.mXaxis[2]); + fi_fprintf(fph,"<value name=\"Zaxis\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", msj.mZaxis[0], msj.mZaxis[1], msj.mZaxis[2]); + fi_fprintf(fph,"<value name=\"Anchor\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", msj.mOffset[0], msj.mOffset[1], msj.mOffset[2]); + fi_fprintf(fph,"<value name=\"TwistLow\" type=\"F32\">%0.9f</value>\r\n", msj.mTwistLow*FM_RAD_TO_DEG); + fi_fprintf(fph,"<value name=\"TwistHigh\" type=\"F32\">%0.9f</value>\r\n", msj.mTwistHigh*FM_RAD_TO_DEG); + fi_fprintf(fph,"<value name=\"Swing1\" type=\"F32\">%0.9f</value>\r\n", msj.mSwing1*FM_RAD_TO_DEG); + fi_fprintf(fph,"<value name=\"Swing2\" type=\"F32\">%0.9f</value>\r\n", msj.mSwing2*FM_RAD_TO_DEG); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); +} + + +MiI32 getJointParentIndex(const MeshSystem *ms,MiU32 i) +{ + MiI32 ret = -1; + + if ( ms->mMeshJointCount ) + { + const char *rootName = ms->mMeshCollisionRepresentations[i]->mName; + for (MiU32 j=0; j<ms->mMeshJointCount; j++) + { + const MeshSimpleJoint &msj = ms->mMeshJoints[j]; + if ( strcmp(msj.mName,rootName) == 0 ) + { + ret = (MiI32)j; + break; + } + } + } + return ret; +} + +const char * getParentName(const MeshSystem *ms,MiU32 i) +{ + const char *ret = "NONE"; + + MiI32 index = getJointParentIndex(ms,i); + if ( index != -1 ) + { + ret = ms->mMeshJoints[index].mParent; + } + + return ret; +} + +MiU32 getActorParentIndex(const MeshSystem *ms,MiU32 i) +{ + MiI32 ret = -1; + const char *parentName = getParentName(ms,i); + for (MiU32 i=0; i<ms->mMeshCollisionCount; i++) + { + const MeshCollisionRepresentation &mcr = *ms->mMeshCollisionRepresentations[i]; + if ( strcmp(mcr.mName,parentName) == 0 ) + { + ret = (MiI32)i; + break; + } + } + return (MiU32)ret; +} + + +void *serializeDynamicSystemAuthoring(const MeshSystem *ms,MiU32 &len) +{ + void * ret = NULL; + len = 0; + + if ( ms ) + { + FILE_INTERFACE *fph = fi_fopen(ms->mAssetName,"wmem",NULL,0); + if ( fph ) + { + // + + + +// ** Athoring + + fi_fprintf(fph,"<!DOCTYPE NvParameters>\r\n"); + fi_fprintf(fph,"<NvParameters numObjects=\"1\" version=\"1.0\" >\r\n"); + fi_fprintf(fph,"<value name=\"\" type=\"Ref\" className=\"DynamicSystemAssetAuthoringParams\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">%s</value>\r\n", ms->mAssetName); + fi_fprintf(fph,"<value name=\"ModelUserString\" null=\"1\" type=\"String\"></value>\r\n"); + fi_fprintf(fph,"<value name=\"ModelType\" type=\"Ref\" included=\"1\" className=\"ModelCollision\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + + fi_fprintf(fph,"<value name=\"PositionSolverIterationCount\" type=\"U32\">30</value>\r\n"); + fi_fprintf(fph,"<value name=\"VelocitySolverIterationCount\" type=\"U32\">30</value>\r\n"); + + fi_fprintf(fph,"<value name=\"RootBone\" type=\"Transform\">0 0 0 1 0 0 0 </value>\r\n"); + fi_fprintf(fph,"<array name=\"Materials\" size=\"1\" type=\"Struct\">\r\n"); + fi_fprintf(fph,"<struct>\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">dummy_material</value>\r\n"); + fi_fprintf(fph,"<value name=\"IncludeTriangles\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</array>\r\n"); + fi_fprintf(fph,"<array name=\"Skeleton\" size=\"%d\" type=\"Struct\">\r\n", ms->mMeshCollisionCount); + + for (MiU32 i=0; i<ms->mMeshCollisionCount; i++) + { + MeshCollisionRepresentation &mr = *ms->mMeshCollisionRepresentations[i]; + // For each Bone + fi_fprintf(fph,"<struct>\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">%s</value>\r\n", mr.mName); + fi_fprintf(fph,"<value name=\"BoneRule\" type=\"Enum\">USER_INCLUDE</value>\r\n"); + fi_fprintf(fph,"<struct name=\"MeshStats\">\r\n"); + fi_fprintf(fph,"<value name=\"VertexCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TriangleCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + + fi_fprintf(fph,"<value name=\"Transform\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f </value>\r\n", + mr.mOrientation[0],mr.mOrientation[1],mr.mOrientation[2],mr.mOrientation[3], + mr.mPosition[0],mr.mPosition[1],mr.mPosition[2]); + + fi_fprintf(fph,"<value name=\"ParentIndex\" type=\"I32\">%d</value>\r\n", getActorParentIndex(ms,i)); + + fi_fprintf(fph,"</struct>\r\n"); + } + fi_fprintf(fph,"</array>\r\n"); + + fi_fprintf(fph,"<array name=\"DynamicSystemSkeleton\" size=\"%d\" type=\"Ref\">\r\n", ms->mMeshCollisionCount); + for (MiU32 i=0; i<ms->mMeshCollisionCount; i++) + { + // For each bone + MeshCollisionRepresentation &mr = *ms->mMeshCollisionRepresentations[i]; + fi_fprintf(fph,"<value type=\"Ref\" included=\"1\" className=\"PrunedBone\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">%s</value>\r\n", mr.mName); + fi_fprintf(fph,"<value name=\"ParentName\" type=\"String\">%s</value>\r\n", getParentName(ms,i)); + fi_fprintf(fph,"<value name=\"BoneUserString\" null=\"1\" type=\"String\"></value>\r\n"); + fi_fprintf(fph,"<value name=\"Locked\" type=\"Bool\">false</value>\r\n"); + + MeshCollision &mc = *(mr.mCollisionGeometry[0]); + + switch ( mc.getType() ) + { + case MCT_SPHERE: + { + MeshCollisionSphere &mcb = *(static_cast< MeshCollisionSphere *>(&mc)); + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"SphereStatistics\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Radius\" type=\"F32\">%0.9f</value>\r\n", mcb.mRadius); + fi_fprintf(fph,"<value name=\"Center\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", + mcb.mLocalPosition[0],mcb.mLocalPosition[1],mcb.mLocalPosition[2]); + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">%0.9f</value>\r\n", 3.141592654f*mcb.mRadius*mcb.mRadius); + fi_fprintf(fph,"<value name=\"ScaleRadius\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<struct name=\"SphereOrientation\">\r\n"); + fi_fprintf(fph,"<value name=\"RotateX\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"RotateY\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"RotateZ\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<struct name=\"SphereTranslation\">\r\n"); + fi_fprintf(fph,"<value name=\"TranslateX\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TranslateY\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TranslateZ\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + break; + case MCT_BOX: + { + MeshCollisionBox &mcb = *(static_cast< MeshCollisionBox *>(&mc)); + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"BoxStatistics\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Sides\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", + mcb.mSides[0],mcb.mSides[1],mcb.mSides[2]); + fi_fprintf(fph,"<value name=\"Transform\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f</value>\r\n", + mcb.mLocalOrientation[0],mcb.mLocalOrientation[1],mcb.mLocalOrientation[2],mcb.mLocalOrientation[3], + mcb.mLocalPosition[0],mcb.mLocalPosition[1],mcb.mLocalPosition[2]); + + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">0</value>\r\n"); + + fi_fprintf(fph,"<struct name=\"BoxScaling\">\r\n"); + fi_fprintf(fph,"<value name=\"UniformScale\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"ScaleX\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"ScaleY\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"ScaleZ\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + + fi_fprintf(fph,"<struct name=\"BoxOrientation\">\r\n"); + fi_fprintf(fph,"<value name=\"RotateX\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"RotateY\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"RotateZ\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<struct name=\"BoxTranslation\">\r\n"); + + fi_fprintf(fph,"<value name=\"TranslateX\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TranslateY\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TranslateZ\" type=\"F32\">0</value>\r\n"); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + break; + case MCT_CONVEX: + { + //MeshCollisionConvex &mcc = *(static_cast< MeshCollisionConvex *>(&mc)); + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"HullStatistics\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<struct name=\"MeshStats\">\r\n"); + fi_fprintf(fph,"<value name=\"VertexCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TriangleCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"MaxHullVertices\" type=\"U32\">64</value>\r\n"); + fi_fprintf(fph,"<value name=\"ApproximationMethod\" type=\"Enum\">SINGLE_HULL</value>\r\n"); + fi_fprintf(fph,"<value name=\"Concavity\" type=\"F32\">0.200000003</value>\r\n"); + fi_fprintf(fph,"<value name=\"MaxHACDConvexHullCount\" type=\"U32\">64</value>\r\n"); + fi_fprintf(fph,"<value name=\"MaxMergeConvexHullCount\" type=\"U32\">128</value>\r\n"); + fi_fprintf(fph,"<value name=\"SmallClusterThreshold\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"BackFaceDistanceFactor\" type=\"F32\">0.00999999978</value>\r\n"); + fi_fprintf(fph,"<value name=\"DecompositionDepth\" type=\"U32\">5</value>\r\n"); + fi_fprintf(fph,"<value name=\"ClampMin\" type=\"Vec3\">0 0 0</value>\r\n"); + fi_fprintf(fph,"<value name=\"ClampMax\" type=\"Vec3\">1 1 1</value>\r\n"); + fi_fprintf(fph,"<array name=\"ConvexShapes\" size=\"0\" type=\"Ref\"></array>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + break; + default: + assert(0); // not yet implemented! + break; + } + + fi_fprintf(fph,"<value name=\"SimulationFilterData\" type=\"String\">default</value>\r\n"); + fi_fprintf(fph,"<value name=\"QueryFilterData\" type=\"String\">default</value>\r\n"); + fi_fprintf(fph,"<value name=\"Chassis\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"Wheel\" type=\"Ref\" included=\"1\" className=\"NoWheel\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + + MiI32 jointIndex = getJointParentIndex(ms,i); + if ( jointIndex == - 1 ) + { + fi_fprintf(fph,"<value name=\"Joint\" type=\"Ref\" included=\"1\" className=\"JointNone\" version=\"0.0\">\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + else + { + saveJoint(ms->mMeshJoints[jointIndex],fph); + } + + fi_fprintf(fph,"<value name=\"CenterOfMass\" type=\"Vec3\">0 0 0</value>\r\n"); + fi_fprintf(fph,"<value name=\"Mass\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"PhysicsMaterialName\" type=\"String\">defaultMaterial</value>\r\n"); + fi_fprintf(fph,"<struct name=\"MeshStats\">\r\n"); + fi_fprintf(fph,"<value name=\"VertexCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"TriangleCount\" type=\"U32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"Volume\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<value name=\"HIDDEN\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + fi_fprintf(fph,"</array>\r\n"); + fi_fprintf(fph,"<struct name=\"CollisionSettings\">\r\n"); + fi_fprintf(fph,"<value name=\"OverallUniformPrimitiveScaling\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"NeighborDistance\" type=\"U32\">2</value>\r\n"); + fi_fprintf(fph,"<value name=\"MinimumVertices\" type=\"U32\">9</value>\r\n"); + fi_fprintf(fph,"<value name=\"MinimumPercentageVolume\" type=\"F32\">10</value>\r\n"); + fi_fprintf(fph,"<value name=\"SkinWidth\" type=\"F32\">0.00999999978</value>\r\n"); + fi_fprintf(fph,"<value name=\"BoxPercent\" type=\"F32\">90</value>\r\n"); + fi_fprintf(fph,"<value name=\"SpherePercent\" type=\"F32\">80</value>\r\n"); + fi_fprintf(fph,"<value name=\"CapsulePercent\" type=\"F32\">70</value>\r\n"); + fi_fprintf(fph,"<value name=\"FitBox\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"FitSphere\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"FitCapsule\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"FitConvex\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<struct name=\"SDK_VISUALIZATION\">\r\n"); + fi_fprintf(fph,"<value name=\"WORLD_AXES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"BODY_AXES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"BODY_MASS_AXES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"BODY_LIN_VELOCITY\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"BODY_ANG_VELOCITY\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"BODY_JOINT_GROUPS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"CONTACT_POINT\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"CONTACT_ERROR\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"CONTACT_FORCE\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ACTOR_AXES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_AABBS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_SHAPES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_AXES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_COMPOUNDS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_FNORMALS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_EDGES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_STATIC\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_DYNAMIC\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"COLLISION_PAIRS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"JOINT_LOCAL_FRAMES\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"JOINT_LIMITS\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<struct name=\"Visualization\">\r\n"); + fi_fprintf(fph,"<value name=\"RenderScale\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"GameScale\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"ZAxisUp\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"Gravity\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"Collision\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowCenterOfMass\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowWheels\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowWheelLocation\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowApplyTirePoint\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowSuspensionPoint\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowSkeleton\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowSkeletonNames\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowSourceMesh\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowCollisionVolumes\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"SourceMeshWireframe\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"CollisionVolumeWireframe\" type=\"Bool\">true</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowOnlySelectedMesh\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowOnlySelectedCollision\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowConstraintAxis\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"PhysXConstraintScale\" type=\"F32\">0.100000001</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowPhysXContacts\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"ShowVehicleMomentOfInertia\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"WheelGraphChannel\" type=\"Enum\">NONE</value>\r\n"); + fi_fprintf(fph,"<value name=\"EngineGraphChannel\" type=\"Enum\">NONE</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"<struct name=\"AnimationControls\">\r\n"); + fi_fprintf(fph,"<value name=\"PlayAnimation\" type=\"Enum\">STOP</value>\r\n"); + fi_fprintf(fph,"<value name=\"ScrollAnimation\" type=\"F32\">0</value>\r\n"); + fi_fprintf(fph,"<value name=\"PlaybackSpeed\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + + saveBodyPairCollision(*ms,fph); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + fi_fprintf(fph,"</NvParameters>\r\n"); + + size_t outLen; + void *outMem = fi_getMemBuffer(fph,&outLen); + if ( outMem ) + { + len = (MiU32)outLen; + ret = MI_ALLOC(len); + memcpy(ret,outMem,len); + } + fi_fclose(fph); + } + } + return ret; +} + + + +void *serializeDynamicSystem(const MeshSystem *ms,MiU32 &len) +{ + void * ret = NULL; + len = 0; + + if ( ms ) + { + FILE_INTERFACE *fph = fi_fopen(ms->mAssetName,"wmem",NULL,0); + if ( fph ) + { + // + + +// asset + fi_fprintf(fph,"<!DOCTYPE NvParameters>\r\n"); + fi_fprintf(fph,"<NvParameters numObjects=\"1\" version=\"1.0\" >\r\n"); + fi_fprintf(fph,"<value name=\"\" type=\"Ref\" className=\"DynamicSystemAssetParam\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">DynamicSystemAsset.1</value>\r\n"); + fi_fprintf(fph,"<value name=\"ModelUserString\" null=\"1\" type=\"String\"></value>\r\n"); + fi_fprintf(fph,"<value name=\"ModelType\" type=\"Ref\" included=\"1\" className=\"ModelCollision\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + fi_fprintf(fph,"<value name=\"PositionSolverIterationCount\" type=\"U32\">30</value>\r\n"); + fi_fprintf(fph,"<value name=\"VelocitySolverIterationCount\" type=\"U32\">30</value>\r\n"); + fi_fprintf(fph,"<value name=\"RootBone\" type=\"Transform\">0 0 0 1 0 0 0 </value>\r\n"); + fi_fprintf(fph,"<array name=\"DynamicSystemSkeleton\" size=\"%d\" type=\"Struct\">\r\n",ms->mMeshCollisionCount); +// For each bone + for (MiU32 i=0; i<ms->mMeshCollisionCount; i++) + { + MeshCollisionRepresentation &mr = *ms->mMeshCollisionRepresentations[i]; + MeshCollision &mc = *(mr.mCollisionGeometry[0]); + + fi_fprintf(fph,"<struct>\r\n"); + fi_fprintf(fph,"<value name=\"Name\" type=\"String\">%s</value>\r\n", mr.mName); + fi_fprintf(fph,"<value name=\"ParentBone\" type=\"String\">%s</value>\r\n", getParentName(ms,i)); + fi_fprintf(fph,"<value name=\"BoneUserString\" null=\"1\" type=\"String\"></value>\r\n"); + fi_fprintf(fph,"<value name=\"Mass\" type=\"F32\">1</value>\r\n"); + fi_fprintf(fph,"<value name=\"CenterOfMass\" type=\"Vec3\">0 0 0</value>\r\n"); + fi_fprintf(fph,"<value name=\"SimulationFilterData\" type=\"String\">default</value>\r\n"); + fi_fprintf(fph,"<value name=\"QueryFilterData\" type=\"String\">default</value>\r\n"); + fi_fprintf(fph,"<value name=\"Chassis\" type=\"Bool\">false</value>\r\n"); + fi_fprintf(fph,"<value name=\"Wheel\" type=\"Ref\" included=\"1\" className=\"NoWheel\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + fi_fprintf(fph,"<value name=\"PhysicsMaterialName\" type=\"String\">defaultMaterial</value>\r\n"); + + switch ( mc.getType() ) + { + case MCT_SPHERE: + { + MeshCollisionSphere &mcb = *(static_cast<MeshCollisionSphere *>(&mc)); + + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"DynamicSystemSphereShapeParams\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Radius\" type=\"F32\">%0.9f</value>\r\n", mcb.mRadius); + + fi_fprintf(fph,"<value name=\"LocalPose\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f</value>\r\n", + mc.mLocalOrientation[0],mc.mLocalOrientation[1],mc.mLocalOrientation[2],mc.mLocalOrientation[3], + mc.mLocalPosition[0],mc.mLocalPosition[1],mc.mLocalPosition[2]); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + + } + break; + case MCT_BOX: + { + MeshCollisionBox &mcb = *(static_cast<MeshCollisionBox *>(&mc)); + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"DynamicSystemBoxShapeParams\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<value name=\"Sides\" type=\"Vec3\">%0.9f %0.9f %0.9f</value>\r\n", + mcb.mSides[0],mcb.mSides[1],mcb.mSides[2]); + + fi_fprintf(fph,"<value name=\"LocalPose\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f</value>\r\n", + mc.mLocalOrientation[0],mc.mLocalOrientation[1],mc.mLocalOrientation[2],mc.mLocalOrientation[3], + mc.mLocalPosition[0],mc.mLocalPosition[1],mc.mLocalPosition[2]); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + } + break; + case MCT_CONVEX: + { + + MeshCollisionConvex &mcc = *(static_cast<MeshCollisionConvex *>(&mc)); + + fi_fprintf(fph,"<value name=\"CollisionShape\" type=\"Ref\" included=\"1\" className=\"DynamicSystemConvexShapeParams\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<array name=\"ConvexShapes\" size=\"1\" type=\"Ref\">\r\n"); + fi_fprintf(fph,"<value type=\"Ref\" included=\"1\" className=\"ConvexShape\" version=\"0.0\" >\r\n"); + fi_fprintf(fph,"<struct name=\"\">\r\n"); + fi_fprintf(fph,"<array name=\"Vertices\" size=\"%d\" type=\"Vec3\">\r\n", mcc.mVertexCount); + + for (MiU32 i=0; i<mcc.mVertexCount; i++) + { + const MiF32 *v = &mcc.mVertices[i*3]; + fi_fprintf(fph,"%0.9f %0.9f %0.9f,\r\n", v[0], v[1], v[2] ); + } + + fi_fprintf(fph,"</array>\r\n"); + + if ( mcc.mTriCount ) + { + fi_fprintf(fph,"<array name=\"Indices\" size=\"%d\" type=\"U32\">\r\n", mcc.mTriCount*3); + for (MiU32 i=0; i<mcc.mTriCount; i++) + { + const MiU32 *tri = &mcc.mIndices[i*3]; + fi_fprintf(fph,"%d %d %d\r\n", tri[0],tri[1],tri[2]); + } + fi_fprintf(fph,"</array>\r\n"); + } + + fi_fprintf(fph,"<value name=\"LocalPose\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f</value>\r\n", + mc.mLocalOrientation[0],mc.mLocalOrientation[1],mc.mLocalOrientation[2],mc.mLocalOrientation[3], + mc.mLocalPosition[0],mc.mLocalPosition[1],mc.mLocalPosition[2]); + + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + fi_fprintf(fph,"</array>\r\n"); + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + + + } + break; + default: + assert(0); // not yet implemented + break; + } + + + MiI32 jointIndex = getJointParentIndex(ms,i); + if ( jointIndex == -1 ) + { + fi_fprintf(fph,"<value name=\"Joint\" type=\"Ref\" included=\"1\" className=\"JointNone\" version=\"0.0\">\r\n"); + fi_fprintf(fph," <struct name=\"\">\r\n"); + fi_fprintf(fph," </struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + + } + else + { + saveJoint(ms->mMeshJoints[jointIndex],fph); + } + + fi_fprintf(fph,"<value name=\"Transform\" type=\"Transform\">%0.9f %0.9f %0.9f %0.9f %0.9f %0.9f %0.9f</value>\r\n", + mr.mOrientation[0],mr.mOrientation[1],mr.mOrientation[2],mr.mOrientation[3], + mr.mPosition[0],mr.mPosition[1],mr.mPosition[2]); + + fi_fprintf(fph,"</struct>\r\n"); + } + fi_fprintf(fph,"</array>\r\n"); + + saveBodyPairCollision(*ms,fph); + + fi_fprintf(fph,"</struct>\r\n"); + fi_fprintf(fph,"</value>\r\n"); + fi_fprintf(fph,"</NvParameters>\r\n"); + + size_t outLen; + void *outMem = fi_getMemBuffer(fph,&outLen); + if ( outMem ) + { + len = (MiU32)outLen; + ret = MI_ALLOC(len); + memcpy(ret,outMem,len); + } + fi_fclose(fph); + } + } + return ret; +} + + +};// end of namespace + + + + diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.h new file mode 100644 index 00000000..c040afd5 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef EXPORT_DYNAMIC_SYSTEM_H + +#define EXPORT_DYNAMIC_SYSTEM_H + +#include "MiFileInterface.h" +#include "MeshImport.h" + +namespace mimp +{ + +void * serializeDynamicSystem(const MeshSystem *ms,MiU32 &dlen); +void *serializeDynamicSystemAuthoring(const MeshSystem *ms,MiU32 &len); + +};// end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.cpp new file mode 100644 index 00000000..14e17096 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.cpp @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include "ExportEZB.h" +#include "MeshImport.h" +#include "MiFloatMath.h" +#include "MiMemoryBuffer.h" +#include "MiIOStream.h" + +#pragma warning(disable:4100) + +namespace mimp +{ + +static void serialize(MiIOStream &stream,const MeshAABB &aabb) +{ + stream << aabb.mMin[0]; + stream << aabb.mMin[1]; + stream << aabb.mMin[2]; + stream << aabb.mMax[0]; + stream << aabb.mMax[1]; + stream << aabb.mMax[2]; +} + +static void serialize(MiIOStream &stream,const MeshRawTexture &m) +{ + stream << m.mName; + stream << m.mWidth; + stream << m.mHeight; + stream << m.mBPP; + + MiU32 dataLen = m.mData ? m.mWidth*m.mHeight*m.mBPP : 0; + stream << dataLen; + if ( dataLen ) + { + stream.getStream().write(m.mData,dataLen); + } +} + +static void serialize(MiIOStream & /*stream*/,const MeshTetra & /*mrt*/) +{ + MI_ALWAYS_ASSERT(); // Not yet implemented +} + +static void serialize(MiIOStream &stream,const MeshBone &m) +{ + stream << m.mName; + stream << m.mParentIndex; + stream << m.mPosition[0]; + stream << m.mPosition[1]; + stream << m.mPosition[2]; + stream << m.mOrientation[0]; + stream << m.mOrientation[1]; + stream << m.mOrientation[2]; + stream << m.mOrientation[3]; + stream << m.mScale[0]; + stream << m.mScale[1]; + stream << m.mScale[2]; +} + +static void serialize(MiIOStream &stream,const MeshSkeleton &m) +{ + stream << m.mName; + stream << m.mBoneCount; + for (MiI32 i=0; i<m.mBoneCount; i++) + { + const MeshBone &b = m.mBones[i]; + serialize(stream,b); + } +} + +static void serialize(MiIOStream &stream,const MeshAnimPose &m) +{ + stream << m.mPos[0]; + stream << m.mPos[1]; + stream << m.mPos[2]; + stream << m.mQuat[0]; + stream << m.mQuat[1]; + stream << m.mQuat[2]; + stream << m.mQuat[3]; + stream << m.mScale[0]; + stream << m.mScale[1]; + stream << m.mScale[2]; +} + +static void serialize(MiIOStream &stream,const MeshAnimTrack &m) +{ + stream << m.mName; + stream << m.mFrameCount; + stream << m.mDuration; + stream << m.mDtime; + for (MiI32 i=0; i<m.mFrameCount; i++) + { + const MeshAnimPose &p = m.mPose[i]; + serialize(stream,p); + } +} + +static void serialize(MiIOStream &stream,const MeshAnimation &m) +{ + stream << m.mName; + stream << m.mTrackCount; + stream << m.mFrameCount; + stream << m.mDuration; + stream << m.mDtime; + for (MiI32 i=0; i<m.mTrackCount; i++) + { + const MeshAnimTrack &t = *m.mTracks[i]; + serialize(stream,t); + } +} + +static void serialize(MiIOStream &stream,const MeshMaterial &m) +{ + stream << m.mName; + stream << m.mMetaData; +} + +static void serialize(MiIOStream &stream,const MeshUserData &m) +{ + stream << m.mUserKey; + stream << m.mUserValue; +} + +static void serialize(MiIOStream &stream,const MeshUserBinaryData &m) +{ + stream << m.mName; + stream << m.mUserLen; + if ( m.mUserLen ) + { + stream.getStream().write(m.mUserData,m.mUserLen); + } +} + +static void serialize(MiIOStream &stream,const SubMesh &m) +{ + stream << m.mMaterialName; + serialize(stream,m.mAABB); + stream << m.mVertexFlags; + stream << m.mTriCount; + for (MiU32 i=0; i<m.mTriCount*3; i++) + { + stream << m.mIndices[i]; + } +} + +static void serialize(MiIOStream &stream,const MeshVertex &m,MiU32 vertexFlags) +{ + + if ( vertexFlags & MIVF_POSITION ) + { + stream << m.mPos[0]; + stream << m.mPos[1]; + stream << m.mPos[2]; + } + if ( vertexFlags & MIVF_NORMAL ) + { + stream << m.mNormal[0]; + stream << m.mNormal[1]; + stream << m.mNormal[2]; + } + if ( vertexFlags & MIVF_COLOR ) + { + stream << m.mColor; + } + if ( vertexFlags & MIVF_TEXEL1 ) + { + stream << m.mTexel1[0]; + stream << m.mTexel1[1]; + } + if ( vertexFlags & MIVF_TEXEL2 ) + { + stream << m.mTexel2[0]; + stream << m.mTexel2[1]; + } + if ( vertexFlags & MIVF_TEXEL3 ) + { + stream << m.mTexel3[0]; + stream << m.mTexel3[1]; + } + if ( vertexFlags & MIVF_TEXEL4 ) + { + stream << m.mTexel4[0]; + stream << m.mTexel4[1]; + } + if ( vertexFlags & MIVF_TANGENT ) + { + stream << m.mTangent[0]; + stream << m.mTangent[1]; + stream << m.mTangent[2]; + } + if ( vertexFlags & MIVF_BINORMAL ) + { + stream << m.mBiNormal[0]; + stream << m.mBiNormal[1]; + stream << m.mBiNormal[2]; + } + if ( vertexFlags & MIVF_BONE_WEIGHTING ) + { + stream << m.mBone[0]; + stream << m.mBone[1]; + stream << m.mBone[2]; + stream << m.mBone[3]; + stream << m.mWeight[0]; + stream << m.mWeight[1]; + stream << m.mWeight[2]; + stream << m.mWeight[3]; + } + if ( vertexFlags & MIVF_RADIUS ) + { + stream << m.mRadius; + } + if ( vertexFlags & MIVF_INTERP1 ) + { + stream << m.mInterp1[0]; + stream << m.mInterp1[1]; + stream << m.mInterp1[2]; + stream << m.mInterp1[3]; + } + if ( vertexFlags & MIVF_INTERP2 ) + { + stream << m.mInterp2[0]; + stream << m.mInterp2[1]; + stream << m.mInterp2[2]; + stream << m.mInterp2[3]; + } + if ( vertexFlags & MIVF_INTERP3 ) + { + stream << m.mInterp3[0]; + stream << m.mInterp3[1]; + stream << m.mInterp3[2]; + stream << m.mInterp3[3]; + } + if ( vertexFlags & MIVF_INTERP4 ) + { + stream << m.mInterp4[0]; + stream << m.mInterp4[1]; + stream << m.mInterp4[2]; + stream << m.mInterp4[3]; + } + if ( vertexFlags & MIVF_INTERP5 ) + { + stream << m.mInterp5[0]; + stream << m.mInterp5[1]; + stream << m.mInterp5[2]; + stream << m.mInterp5[3]; + } + if ( vertexFlags & MIVF_INTERP6 ) + { + stream << m.mInterp6[0]; + stream << m.mInterp6[1]; + stream << m.mInterp6[2]; + stream << m.mInterp6[3]; + } + if ( vertexFlags & MIVF_INTERP7 ) + { + stream << m.mInterp7[0]; + stream << m.mInterp7[1]; + stream << m.mInterp7[2]; + stream << m.mInterp7[3]; + } + if ( vertexFlags & MIVF_INTERP8 ) + { + stream << m.mInterp8[0]; + stream << m.mInterp8[1]; + stream << m.mInterp8[2]; + stream << m.mInterp8[3]; + } + + +} + + +static void serialize(MiIOStream &stream,const Mesh &m) +{ + stream << m.mName; + stream << m.mSkeletonName; + serialize(stream,m.mAABB); + stream << m.mSubMeshCount; + for (MiU32 i=0; i<m.mSubMeshCount; i++) + { + const SubMesh &s = *m.mSubMeshes[i]; + serialize(stream,s); + } + stream << m.mVertexFlags; + stream << m.mVertexCount; + for (MiU32 i=0; i<m.mVertexCount; i++) + { + const MeshVertex &v = m.mVertices[i]; + serialize(stream,v,m.mVertexFlags); + } +} + +static void serialize(MiIOStream &stream,const MeshInstance &m) +{ + stream << m.mMeshName; + stream << m.mPosition[0]; + stream << m.mPosition[1]; + stream << m.mPosition[2]; + stream << m.mRotation[0]; + stream << m.mRotation[1]; + stream << m.mRotation[2]; + stream << m.mRotation[3]; + stream << m.mScale[0]; + stream << m.mScale[1]; + stream << m.mScale[2]; +} + +static void serialize(MiIOStream & /*stream*/,const MeshCollisionRepresentation & /*m*/) +{ + MI_ALWAYS_ASSERT(); // need to implement +} + + +void *serializeEZB(const MeshSystem *ms,MiU32 &len) +{ + void * ret = NULL; + len = 0; + + if ( ms ) + { + MiMemoryBuffer mb; + mb.setEndianMode(MiFileBuf::ENDIAN_BIG); + MiIOStream stream(mb,0); + MiU32 version = MESH_BINARY_VERSION; + stream << version; + stream << "EZMESH"; + stream << ms->mAssetName; + stream << ms->mAssetInfo; + stream << ms->mMeshSystemVersion; + stream << ms->mAssetVersion; + serialize(stream,ms->mAABB); + stream << ms->mTextureCount; + for (MiU32 i=0; i<ms->mTextureCount; i++) + { + const MeshRawTexture &t = *ms->mTextures[i]; + serialize(stream,t); + } + stream << ms->mTetraMeshCount; + for (MiU32 i=0; i< ms->mTetraMeshCount; i++) + { + const MeshTetra &mt = *ms->mTetraMeshes[i]; + serialize(stream,mt); + } + stream << ms->mSkeletonCount; + for (MiU32 i=0; i< ms->mSkeletonCount; i++) + { + const MeshSkeleton &m = *ms->mSkeletons[i]; + serialize(stream,m); + } + stream << ms->mAnimationCount; + for (MiU32 i=0; i<ms->mAnimationCount; i++) + { + const MeshAnimation &a = *ms->mAnimations[i]; + serialize(stream,a); + } + stream << ms->mMaterialCount; + for (MiU32 i=0; i<ms->mMaterialCount; i++) + { + const MeshMaterial &m = ms->mMaterials[i]; + serialize(stream,m); + } + stream << ms->mUserDataCount; + for (MiU32 i=0; i<ms->mUserDataCount; i++) + { + const MeshUserData &m = *ms->mUserData[i]; + serialize(stream,m); + } + stream << ms->mUserBinaryDataCount; + for (MiU32 i=0; i<ms->mUserBinaryDataCount; i++) + { + const MeshUserBinaryData &m = *ms->mUserBinaryData[i]; + serialize(stream,m); + } + stream << ms->mMeshCount; + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + const Mesh &m = *ms->mMeshes[i]; + serialize(stream,m); + } + stream << ms->mMeshInstanceCount; + for (MiU32 i=0; i<ms->mMeshInstanceCount; i++) + { + const MeshInstance &m = ms->mMeshInstances[i]; + serialize(stream,m); + } + stream << ms->mMeshCollisionCount; + for (MiU32 i=0; i<ms->mMeshCollisionCount; i++) + { + const MeshCollisionRepresentation &m = *ms->mMeshCollisionRepresentations[i]; + serialize(stream,m); + } + stream << ms->mPlane[0]; + stream << ms->mPlane[1]; + stream << ms->mPlane[2]; + stream << ms->mPlane[3]; + + ret = mb.getWriteBufferOwnership(len); + } + return ret; +} + + +};// end of namespace + diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.h new file mode 100644 index 00000000..eb5d986e --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef EXPORT_EZB_H + +#define EXPORT_EZB_H + +#include "MiFileInterface.h" +#include "MeshImport.h" + +#define MESH_BINARY_VERSION 101 + +namespace mimp +{ + +void * serializeEZB(const MeshSystem *ms,MiU32 &dlen); + +};// end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.cpp new file mode 100644 index 00000000..7f040159 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.cpp @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include "ExportFBX.h" + + +#include "MeshImport.h" +#include "MiFloatMath.h" + +#pragma warning(disable:4100) + +namespace mimp +{ + +#if 0 // not curruently fully implemented +void writeVertices(FILE_INTERFACE *fph,Mesh *mesh) +{ + if ( mesh->mVertexCount ) + { + fi_fprintf(fph," Vertices: "); + MiU32 col = 0; + + for (MiU32 i=0; i<mesh->mVertexCount; i++) + { + if (col == 0 && i > 0 ) + { + fi_fprintf(fph," ,"); + } + const MeshVertex &mv = mesh->mVertices[i]; + fi_fprintf(fph,"%0.9f,%0.9f,%0.9f", mv.mPos[0], mv.mPos[1], mv.mPos[2] ); + col++; + if ( col == 4 ) + { + fi_fprintf(fph,"\r\n"); + col = 0; + } + else if ( (i+1) < mesh->mVertexCount ) + { + fi_fprintf(fph,","); + } + } + fi_fprintf(fph,"\r\n"); + } + +} + +void writePolygonVertexIndex(FILE_INTERFACE *fph,Mesh *mesh) +{ + if ( mesh->mSubMeshCount ) + { + + fi_fprintf(fph," PolygonVertexIndex: "); + MiU32 col = 0; + MiU32 index = 0; + while ( index < mesh->mSubMeshCount ) + { + SubMesh *sm = mesh->mSubMeshes[index]; + for (MiU32 i=0; i<sm->mTriCount; i++) + { + if (col == 0 && (i > 0 || index > 0 )) + { + fi_fprintf(fph," ,"); + } + MiI32 i1 = (MiI32)sm->mIndices[i*3+0]; + MiI32 i2 = (MiI32)sm->mIndices[i*3+1]; + MiI32 i3 = (MiI32)sm->mIndices[i*3+2]; + i3 = (i3+1)*-1; + fi_fprintf(fph,"%d,%d,%d", i1, i2, i3 ); + col++; + if ( col == 4 ) + { + fi_fprintf(fph,"\r\n"); + col = 0; + } + else if ( (i+1) < sm->mTriCount ) + { + fi_fprintf(fph,","); + } + } + index++; + } + fi_fprintf(fph,"\r\n"); + } +} + +void writeUV(FILE_INTERFACE *fph,Mesh *mesh) +{ + +#if 0 + fi_fprintf(fph," LayerElementUV: 0 {\r\n"); + fi_fprintf(fph," Version: 101\r\n"); + fi_fprintf(fph," Name: \"\"\r\n"); + fi_fprintf(fph," MappingInformationType: \"ByPolygonVertex\"\r\n"); + fi_fprintf(fph," ReferenceInformationType: \"IndexToDirect\"\r\n"); + fi_fprintf(fph," UV: 0.5,1,0.5,0,1,0,1,1,0,1,0,0,0.5,0,0.5,1,0.5,1,0,1,0,0,0.5,0,1,1,0.5,1,0.5,0,1,0,0.5,1,0,1,0,0,0.5,0,1,1,0.5,1\r\n"); + fi_fprintf(fph," ,0.5,0,1,0,1,1,0,1,0,0,1,0,0.5,1,0,1,0,0,0.5,0,1,1,0.5,1,0.5,0,1,0,1,1,0,1,0,0,1,0\r\n"); + fi_fprintf(fph," UVIndex: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," }\r\n"); +#endif + + fi_fprintf(fph," LayerElementUV: 0 {\r\n"); + fi_fprintf(fph," Version: 101\r\n"); + fi_fprintf(fph," Name: \"\"\r\n"); + fi_fprintf(fph," MappingInformationType: \"ByPolygonVertex\"\r\n"); + fi_fprintf(fph," ReferenceInformationType: \"IndexToDirect\"\r\n"); + fi_fprintf(fph," UV: "); + + MiU32 vcount = mesh->mVertexCount; + + MiU32 col = 0; + for (MiU32 i=0; i<vcount; i++) + { + if ( col == 0 && i > 0 ) + { + fi_fprintf(fph," ,"); + } + const MeshVertex &mv = mesh->mVertices[i]; + fi_fprintf(fph,"%0.6f,%0.6f", mv.mTexel1[0], mv.mTexel1[1] ); + col++; + if ( col == 32 ) + { + fi_fprintf(fph,"\r\n"); + col = 0; + } + else if ( (i+1) < vcount ) + { + fi_fprintf(fph,","); + } + } + fi_fprintf(fph,"\r\n"); + + fi_fprintf(fph," UVIndex: "); + col = 0; + for (MiU32 i=0; i<vcount; i++) + { + if ( col == 0 && i > 0 ) + fi_fprintf(fph," ,"); + fi_fprintf(fph,"%d",i); + col++; + if ( col == 64 ) + { + fi_fprintf(fph,"\r\n"); + col = 0; + } + else if ( (i+1) < vcount ) + { + fi_fprintf(fph,","); + } + } + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," }\r\n"); + +} + +void serializeFBX(FILE_INTERFACE *fph,MeshSystem *ms) +{ + + fi_fprintf(fph,"; FBX 6.1.0 project file\r\n"); + fi_fprintf(fph,"; Copyright (C) 1997-2008 Autodesk Inc. and/or its licensors.\r\n"); + fi_fprintf(fph,"; All rights reserved.\r\n"); + fi_fprintf(fph,"; ----------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"FBXHeaderExtension: {\r\n"); + fi_fprintf(fph," FBXHeaderVersion: 1003\r\n"); + fi_fprintf(fph," FBXVersion: 6100\r\n"); + fi_fprintf(fph," CreationTimeStamp: {\r\n"); + fi_fprintf(fph," Version: 1000\r\n"); + fi_fprintf(fph," Year: 2009\r\n"); + fi_fprintf(fph," Month: 12\r\n"); + fi_fprintf(fph," Day: 3\r\n"); + fi_fprintf(fph," Hour: 18\r\n"); + fi_fprintf(fph," Minute: 6\r\n"); + fi_fprintf(fph," Second: 18\r\n"); + fi_fprintf(fph," Millisecond: 532\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Creator: \"FBX SDK/FBX Plugins version 2010.2\"\r\n"); + fi_fprintf(fph," OtherFlags: {\r\n"); + fi_fprintf(fph," FlagPLE: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,"CreationTime: \"2009-12-03 18:06:18:532\"\r\n"); + fi_fprintf(fph,"Creator: \"FBX SDK/FBX Plugins build 20090731\"\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"; Document Description\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Document: {\r\n"); + fi_fprintf(fph," Name: \"\"\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"; Document References\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"References: {\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"; Object definitions\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Definitions: {\r\n"); + fi_fprintf(fph," Version: 100\r\n"); + fi_fprintf(fph," Count: 5\r\n"); + fi_fprintf(fph," ObjectType: \"Model\" {\r\n"); + fi_fprintf(fph," Count: 2\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," ObjectType: \"Material\" {\r\n"); + fi_fprintf(fph," Count: 1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," ObjectType: \"SceneInfo\" {\r\n"); + fi_fprintf(fph," Count: 1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," ObjectType: \"GlobalSettings\" {\r\n"); + fi_fprintf(fph," Count: 1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"; Object properties\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Objects: {\r\n"); + fi_fprintf(fph," Model: \"Model::aconcave_root\", \"Null\" {\r\n"); + fi_fprintf(fph," Version: 232\r\n"); + fi_fprintf(fph," Properties60: {\r\n"); + fi_fprintf(fph," Property: \"QuaternionInterpolate\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationOffset\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationPivot\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"ScalingOffset\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"ScalingPivot\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMin\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationMax\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationOrder\", \"enum\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationSpaceForLimitOnly\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"AxisLen\", \"double\", \"\",10\r\n"); + fi_fprintf(fph," Property: \"PreRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"PostRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMin\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationMax\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"InheritType\", \"enum\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMin\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"ScalingMax\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"ScalingMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"GeometricTranslation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"GeometricRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"GeometricScaling\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"LookAtProperty\", \"object\", \"\"\r\n"); + fi_fprintf(fph," Property: \"UpVectorProperty\", \"object\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Show\", \"bool\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"NegativePercentShapeSupport\", \"bool\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"DefaultAttributeIndex\", \"int\", \"\",-1\r\n"); + fi_fprintf(fph," Property: \"Freeze\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"LODBox\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"Lcl Translation\", \"Lcl Translation\", \"A+\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"Lcl Rotation\", \"Lcl Rotation\", \"A+\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"Lcl Scaling\", \"Lcl Scaling\", \"A+\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"Visibility\", \"Visibility\", \"A+\",1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," MultiLayer: 0\r\n"); + fi_fprintf(fph," MultiTake: 1\r\n"); + fi_fprintf(fph," Shading: Y\r\n"); + fi_fprintf(fph," Culling: \"CullingOff\"\r\n"); + fi_fprintf(fph," TypeFlags: \"Null\"\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Model: \"Model::Box01\", \"Mesh\" {\r\n"); + fi_fprintf(fph," Version: 232\r\n"); + fi_fprintf(fph," Properties60: {\r\n"); + fi_fprintf(fph," Property: \"QuaternionInterpolate\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationOffset\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationPivot\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"ScalingOffset\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"ScalingPivot\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMin\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationMax\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"TranslationMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationOrder\", \"enum\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationSpaceForLimitOnly\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationStiffnessZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"AxisLen\", \"double\", \"\",10\r\n"); + fi_fprintf(fph," Property: \"PreRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"PostRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMin\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationMax\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"RotationMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"RotationMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"InheritType\", \"enum\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingActive\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMin\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"ScalingMax\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"ScalingMinX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMinY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMinZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxX\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxY\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"ScalingMaxZ\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"GeometricTranslation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"GeometricRotation\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"GeometricScaling\", \"Vector3D\", \"\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampRangeZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampRangeZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MinDampStrengthZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"MaxDampStrengthZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleX\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleY\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"PreferedAngleZ\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"LookAtProperty\", \"object\", \"\"\r\n"); + fi_fprintf(fph," Property: \"UpVectorProperty\", \"object\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Show\", \"bool\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"NegativePercentShapeSupport\", \"bool\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"DefaultAttributeIndex\", \"int\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"Freeze\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"LODBox\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"Lcl Translation\", \"Lcl Translation\", \"A+\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"Lcl Rotation\", \"Lcl Rotation\", \"A+\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"Lcl Scaling\", \"Lcl Scaling\", \"A+\",1,1,1\r\n"); + fi_fprintf(fph," Property: \"Visibility\", \"Visibility\", \"A+\",1\r\n"); + fi_fprintf(fph," Property: \"Color\", \"ColorRGB\", \"N\",0.8,0.8,0.8\r\n"); + fi_fprintf(fph," Property: \"BBoxMin\", \"Vector3D\", \"N\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"BBoxMax\", \"Vector3D\", \"N\",0,0,0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," MultiLayer: 0\r\n"); + fi_fprintf(fph," MultiTake: 1\r\n"); + fi_fprintf(fph," Shading: Y\r\n"); + fi_fprintf(fph," Culling: \"CullingOff\"\r\n"); + + if ( ms->mMeshCount ) + { + Mesh *mesh = ms->mMeshes[0]; + writeVertices(fph,mesh); + writePolygonVertexIndex(fph,mesh); + + fi_fprintf(fph," GeometryVersion: 124\r\n"); + + writeUV(fph,mesh); + } + + + fi_fprintf(fph," LayerElementMaterial: 0 {\r\n"); + fi_fprintf(fph," Version: 101\r\n"); + fi_fprintf(fph," Name: \"\"\r\n"); + fi_fprintf(fph," MappingInformationType: \"AllSame\"\r\n"); + fi_fprintf(fph," ReferenceInformationType: \"IndexToDirect\"\r\n"); + fi_fprintf(fph," Materials: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," LayerElementTexture: 0 {\r\n"); + fi_fprintf(fph," Version: 101\r\n"); + fi_fprintf(fph," Name: \"\"\r\n"); + fi_fprintf(fph," MappingInformationType: \"NoMappingInformation\"\r\n"); + fi_fprintf(fph," ReferenceInformationType: \"IndexToDirect\"\r\n"); + fi_fprintf(fph," BlendMode: \"Translucent\"\r\n"); + fi_fprintf(fph," TextureAlpha: 1\r\n"); + fi_fprintf(fph," TextureId:\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Layer: 0 {\r\n"); + fi_fprintf(fph," Version: 100\r\n"); + fi_fprintf(fph," LayerElement: {\r\n"); + fi_fprintf(fph," Type: \"LayerElementMaterial\"\r\n"); + fi_fprintf(fph," TypedIndex: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," LayerElement: {\r\n"); + fi_fprintf(fph," Type: \"LayerElementTexture\"\r\n"); + fi_fprintf(fph," TypedIndex: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," LayerElement: {\r\n"); + fi_fprintf(fph," Type: \"LayerElementUV\"\r\n"); + fi_fprintf(fph," TypedIndex: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," NodeAttributeName: \"Geometry::Box01_ncl1_1\"\r\n"); + fi_fprintf(fph," }\r\n"); + + fi_fprintf(fph," SceneInfo: \"SceneInfo::GlobalInfo\", \"UserData\" {\r\n"); + fi_fprintf(fph," Type: \"UserData\"\r\n"); + fi_fprintf(fph," Version: 100\r\n"); + fi_fprintf(fph," MetaData: {\r\n"); + fi_fprintf(fph," Version: 100\r\n"); + fi_fprintf(fph," Title: \"\"\r\n"); + fi_fprintf(fph," Subject: \"\"\r\n"); + fi_fprintf(fph," Author: \"\"\r\n"); + fi_fprintf(fph," Keywords: \"\"\r\n"); + fi_fprintf(fph," Revision: \"\"\r\n"); + fi_fprintf(fph," Comment: \"\"\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Properties60: {\r\n"); + fi_fprintf(fph," Property: \"DocumentUrl\", \"KString\", \"\", \"aconcave.fbx\"\r\n"); + fi_fprintf(fph," Property: \"SrcDocumentUrl\", \"KString\", \"\", \"aconcave.fbx\"\r\n"); + fi_fprintf(fph," Property: \"Original\", \"Compound\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Original|ApplicationVendor\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Original|ApplicationName\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Original|ApplicationVersion\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Original|DateTime_GMT\", \"DateTime\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"Original|FileName\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"LastSaved\", \"Compound\", \"\"\r\n"); + fi_fprintf(fph," Property: \"LastSaved|ApplicationVendor\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"LastSaved|ApplicationName\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"LastSaved|ApplicationVersion\", \"KString\", \"\", \"\"\r\n"); + fi_fprintf(fph," Property: \"LastSaved|DateTime_GMT\", \"DateTime\", \"\", \"\"\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Material: \"Material::Box01Mat\", \"\" {\r\n"); + fi_fprintf(fph," Version: 102\r\n"); + fi_fprintf(fph," ShadingModel: \"phong\"\r\n"); + fi_fprintf(fph," MultiLayer: 0\r\n"); + fi_fprintf(fph," Properties60: {\r\n"); + fi_fprintf(fph," Property: \"ShadingModel\", \"KString\", \"\", \"Phong\"\r\n"); + fi_fprintf(fph," Property: \"MultiLayer\", \"bool\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"EmissiveColor\", \"ColorRGB\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"EmissiveFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"AmbientColor\", \"ColorRGB\", \"\",0.2,0.2,0.2\r\n"); + fi_fprintf(fph," Property: \"AmbientFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"DiffuseColor\", \"ColorRGB\", \"\",0.8,0.8,0.8\r\n"); + fi_fprintf(fph," Property: \"DiffuseFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"Bump\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"NormalMap\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"BumpFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"TransparentColor\", \"ColorRGB\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"TransparencyFactor\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"DisplacementColor\", \"ColorRGB\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"DisplacementFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"SpecularColor\", \"ColorRGB\", \"\",0.2,0.2,0.2\r\n"); + fi_fprintf(fph," Property: \"SpecularFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"ShininessExponent\", \"double\", \"\",20\r\n"); + fi_fprintf(fph," Property: \"ReflectionColor\", \"ColorRGB\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"ReflectionFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"Emissive\", \"Vector3D\", \"\",0,0,0\r\n"); + fi_fprintf(fph," Property: \"Ambient\", \"Vector3D\", \"\",0.2,0.2,0.2\r\n"); + fi_fprintf(fph," Property: \"Diffuse\", \"Vector3D\", \"\",0.8,0.8,0.8\r\n"); + fi_fprintf(fph," Property: \"Specular\", \"Vector3D\", \"\",0.2,0.2,0.2\r\n"); + fi_fprintf(fph," Property: \"Shininess\", \"double\", \"\",20\r\n"); + fi_fprintf(fph," Property: \"Opacity\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"Reflectivity\", \"double\", \"\",0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," GlobalSettings: {\r\n"); + fi_fprintf(fph," Version: 1000\r\n"); + fi_fprintf(fph," Properties60: {\r\n"); + fi_fprintf(fph," Property: \"UpAxis\", \"int\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"UpAxisSign\", \"int\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"FrontAxis\", \"int\", \"\",2\r\n"); + fi_fprintf(fph," Property: \"FrontAxisSign\", \"int\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"CoordAxis\", \"int\", \"\",0\r\n"); + fi_fprintf(fph," Property: \"CoordAxisSign\", \"int\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"OriginalUpAxis\", \"int\", \"\",-1\r\n"); + fi_fprintf(fph," Property: \"OriginalUpAxisSign\", \"int\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"UnitScaleFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," Property: \"OriginalUnitScaleFactor\", \"double\", \"\",1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"; Object connections\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Connections: {\r\n"); + fi_fprintf(fph," Connect: \"OO\", \"Model::aconcave_root\", \"Model::Scene\"\r\n"); + fi_fprintf(fph," Connect: \"OO\", \"Model::Box01\", \"Model::aconcave_root\"\r\n"); + fi_fprintf(fph," Connect: \"OO\", \"Material::Box01Mat\", \"Model::Box01\"\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,";Takes and animation section\r\n"); + fi_fprintf(fph,";----------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Takes: {\r\n"); + fi_fprintf(fph," Current: \"\"\r\n"); + fi_fprintf(fph,"}\r\n"); + fi_fprintf(fph,";Version 5 settings\r\n"); + fi_fprintf(fph,";------------------------------------------------------------------\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"Version5: {\r\n"); + fi_fprintf(fph," AmbientRenderSettings: {\r\n"); + fi_fprintf(fph," Version: 101\r\n"); + fi_fprintf(fph," AmbientLightColor: 0.4,0.4,0.4,0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," FogOptions: {\r\n"); + fi_fprintf(fph," FlogEnable: 0\r\n"); + fi_fprintf(fph," FogMode: 0\r\n"); + fi_fprintf(fph," FogDensity: 0.002\r\n"); + fi_fprintf(fph," FogStart: 0.3\r\n"); + fi_fprintf(fph," FogEnd: 1000\r\n"); + fi_fprintf(fph," FogColor: 1,1,1,1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," Settings: {\r\n"); + fi_fprintf(fph," FrameRate: \"30\"\r\n"); + fi_fprintf(fph," TimeFormat: 1\r\n"); + fi_fprintf(fph," SnapOnFrames: 0\r\n"); + fi_fprintf(fph," ReferenceTimeIndex: -1\r\n"); + fi_fprintf(fph," TimeLineStartTime: 0\r\n"); + fi_fprintf(fph," TimeLineStopTime: 46186158000\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," RendererSetting: {\r\n"); + fi_fprintf(fph," DefaultCamera: \"\"\r\n"); + fi_fprintf(fph," DefaultViewingMode: 0\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"}\r\n"); + + +} +#else + +void serializeFBX(FILE_INTERFACE * /*fph*/,MeshSystem * /*ms*/) +{ +} + +#endif + +};// end of namespace + diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.h new file mode 100644 index 00000000..6499065e --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef EXPORT_FBX_H + +#define EXPORT_FBX_H + +#include "MiFileInterface.h" +#include "MeshImport.h" + +namespace mimp +{ + + void serializeFBX(FILE_INTERFACE *fph,MeshSystem *ms); + +};// end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.cpp new file mode 100644 index 00000000..07aa15c4 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include "ExportPOVRay.h" +#include "MeshImport.h" +#include "MiFloatMath.h" +#include "MiFileInterface.h" + +#pragma warning(disable:4100) + +namespace mimp +{ + +static inline const MiF32 * getFloat3(const MiF32 *texel) +{ + static MiF32 pos[3]; + pos[0] = texel[0]; + pos[1] = texel[1]; + pos[2] = 0; + return pos; +} + +static void exportSubMesh(Mesh *m,SubMesh *sm,FILE_INTERFACE *fph) +{ + char scratch[512]; + MESH_IMPORT_STRING::snprintf(scratch,512,"%s_%s", m->mName, sm->mMaterialName ); + fm_VertexIndex *positions = fm_createVertexIndex(0.000001f,false); + fm_VertexIndex *normals = fm_createVertexIndex(0.000001f,false); + fm_VertexIndex *texels = fm_createVertexIndex(0.000001f,false); + + STDNAME::vector< MiU32 > positionIndices; + STDNAME::vector< MiU32 > normalIndices; + STDNAME::vector< MiU32 > texelIndices; + + for (MiU32 i=0; i<sm->mTriCount; i++) + { + MiU32 i1 = sm->mIndices[i*3+0]; + MiU32 i2 = sm->mIndices[i*3+1]; + MiU32 i3 = sm->mIndices[i*3+2]; + + MeshVertex &v1 = m->mVertices[i1]; + MeshVertex &v2 = m->mVertices[i2]; + MeshVertex &v3 = m->mVertices[i3]; + bool newPos; + + MiU32 p1 = positions->getIndex(v1.mPos,newPos); + MiU32 p2 = positions->getIndex(v2.mPos,newPos); + MiU32 p3 = positions->getIndex(v3.mPos,newPos); + positionIndices.push_back(p1); + positionIndices.push_back(p2); + positionIndices.push_back(p3); + + MiU32 n1 = normals->getIndex(v1.mNormal,newPos); + MiU32 n2 = normals->getIndex(v2.mNormal,newPos); + MiU32 n3 = normals->getIndex(v3.mNormal,newPos); + normalIndices.push_back(n1); + normalIndices.push_back(n2); + normalIndices.push_back(n3); + + MiU32 t1 = texels->getIndex( getFloat3(v1.mTexel1), newPos ); + MiU32 t2 = texels->getIndex( getFloat3(v2.mTexel1), newPos ); + MiU32 t3 = texels->getIndex( getFloat3(v3.mTexel1), newPos ); + texelIndices.push_back(t1); + texelIndices.push_back(t2); + texelIndices.push_back(t3); + + } + + fi_fprintf(fph,"// ------- Mesh %s SubMesh %s\r\n", m->mName, sm->mMaterialName ); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"#declare %s=\r\n", scratch); + fi_fprintf(fph," mesh2{\r\n" ); + + fi_fprintf(fph," vertex_vectors{\r\n"); + fi_fprintf(fph," %d\r\n", positions->getVcount()); + for (MiU32 i=0; i<positions->getVcount(); i++) + { + const MiF32 *pos = positions->getVertexFloat(i); + fi_fprintf(fph," <%0.9f, %0.9f, %0.9f>,\r\n", pos[0], pos[1], pos[2] ); + } + fi_fprintf(fph," }\r\n"); + + fi_fprintf(fph," normal_vectors{\r\n"); + fi_fprintf(fph," %d\r\n", normals->getVcount()); + for (MiU32 i=0; i<normals->getVcount(); i++) + { + const MiF32 *pos = normals->getVertexFloat(i); + fi_fprintf(fph," <%0.9f, %0.9f, %0.9f>,\r\n", pos[0], pos[1], pos[2] ); + } + fi_fprintf(fph," }\r\n"); + + + fi_fprintf(fph," uv_vectors{\r\n"); + fi_fprintf(fph," %d\r\n", texels->getVcount()); + for (MiU32 i=0; i<texels->getVcount(); i++) + { + const MiF32 *pos = texels->getVertexFloat(i); + fi_fprintf(fph," <%0.9f, %0.9f>,\r\n", pos[0], pos[1] ); + } + fi_fprintf(fph," }\r\n"); + + fi_fprintf(fph," face_indices{\r\n"); + fi_fprintf(fph," %d,\r\n", positionIndices.size()/3); + for (MiU32 i=0; i<positionIndices.size()/3; i++) + { + MiU32 i1 = positionIndices[i*3+0]; + MiU32 i2 = positionIndices[i*3+1]; + MiU32 i3 = positionIndices[i*3+2]; + fi_fprintf(fph," <%d,%d,%d>,\r\n", i1, i2, i3); + } + fi_fprintf(fph," }\r\n"); + + fi_fprintf(fph," normal_indices{\r\n"); + fi_fprintf(fph," %d,\r\n", normalIndices.size()/3); + for (MiU32 i=0; i<normalIndices.size()/3; i++) + { + MiU32 i1 = normalIndices[i*3+0]; + MiU32 i2 = normalIndices[i*3+1]; + MiU32 i3 = normalIndices[i*3+2]; + fi_fprintf(fph," <%d,%d,%d>,\r\n", i1, i2, i3); + } + fi_fprintf(fph," }\r\n"); + + fi_fprintf(fph," uv_indices{\r\n"); + fi_fprintf(fph," %d,\r\n", texelIndices.size()/3); + for (MiU32 i=0; i<texelIndices.size()/3; i++) + { + MiU32 i1 = texelIndices[i*3+0]; + MiU32 i2 = texelIndices[i*3+1]; + MiU32 i3 = texelIndices[i*3+2]; + fi_fprintf(fph," <%d,%d,%d>,\r\n", i1, i2, i3); + } + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + + + fm_releaseVertexIndex(positions); + fm_releaseVertexIndex(normals); + fm_releaseVertexIndex(texels); +} +void *serializePOVRay(const MeshSystem *ms,MiU32 &len) +{ + void * ret = NULL; + len = 0; + + if ( ms ) + { + FILE_INTERFACE *fph = fi_fopen("foo", "wmem", 0, 0); + + if ( fph ) + { + + fi_fprintf(fph," // Persistence of Vision Ray Tracer Scene Description File\r\n"); + fi_fprintf(fph," // File: mesh2.pov\r\n"); + fi_fprintf(fph," // Vers: 3.5\r\n"); + fi_fprintf(fph," // Desc: mesh2 demonstration scene\r\n"); + fi_fprintf(fph," // Date: November/December 2001\r\n"); + fi_fprintf(fph," // Auth: Christoph Hormann\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," // -w320 -h240\r\n"); + fi_fprintf(fph," // -w512 -h384 +a0.3\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"#version 3.5;\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," global_settings {\r\n"); + fi_fprintf(fph," assumed_gamma 1\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," light_source {\r\n"); + fi_fprintf(fph," <-0.6, 1.6, 3.7>*10000\r\n"); + fi_fprintf(fph," rgb 1.3\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," camera {\r\n"); + fi_fprintf(fph," location <7, 20, 20>\r\n"); + fi_fprintf(fph," direction y\r\n"); + fi_fprintf(fph," sky z\r\n"); + fi_fprintf(fph," up z\r\n"); + fi_fprintf(fph," right (4/3)*x\r\n"); + fi_fprintf(fph," look_at <0.0, 0, 1.2>\r\n"); + fi_fprintf(fph," angle 20\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," background {\r\n"); + fi_fprintf(fph," color rgb < 0.60, 0.70, 0.95 >\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," plane {\r\n"); + fi_fprintf(fph," z, 0\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," texture {\r\n"); + fi_fprintf(fph," pigment {\r\n"); + fi_fprintf(fph," bozo\r\n"); + fi_fprintf(fph," color_map {\r\n"); + fi_fprintf(fph," [ 0.0 color rgb<0.356, 0.321, 0.274> ]\r\n"); + fi_fprintf(fph," [ 0.1 color rgb<0.611, 0.500, 0.500> ]\r\n"); + fi_fprintf(fph," [ 0.4 color rgb<0.745, 0.623, 0.623> ]\r\n"); + fi_fprintf(fph," [ 1.0 color rgb<0.837, 0.782, 0.745> ]\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," warp { turbulence 0.6 }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," finish {\r\n"); + fi_fprintf(fph," diffuse 0.6\r\n"); + fi_fprintf(fph," ambient 0.1\r\n"); + fi_fprintf(fph," specular 0.2\r\n"); + fi_fprintf(fph," reflection {\r\n"); + fi_fprintf(fph," 0.2, 0.6\r\n"); + fi_fprintf(fph," fresnel on\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," conserve_energy\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"#declare Mesh_TextureA=\r\n"); + fi_fprintf(fph," texture{\r\n"); + fi_fprintf(fph," pigment{\r\n"); + fi_fprintf(fph," uv_mapping\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," spiral2 8\r\n"); + fi_fprintf(fph," color_map {\r\n"); + fi_fprintf(fph," [0.5 color rgb <0.2,0,0> ]\r\n"); + fi_fprintf(fph," [0.5 color rgb 1 ]\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," scale 0.8\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," finish {\r\n"); + fi_fprintf(fph," specular 0.3\r\n"); + fi_fprintf(fph," roughness 0.01\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph,"#declare Mesh_TextureB=\r\n"); + fi_fprintf(fph," texture{\r\n"); + fi_fprintf(fph," pigment{\r\n"); + fi_fprintf(fph," uv_mapping\r\n"); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," spiral2 8\r\n"); + fi_fprintf(fph," color_map {\r\n"); + fi_fprintf(fph," [0.5 color rgb 1 ]\r\n"); + fi_fprintf(fph," [0.5 color rgb <0,0,0.2> ]\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," scale 0.8\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," finish {\r\n"); + fi_fprintf(fph," specular 0.3\r\n"); + fi_fprintf(fph," roughness 0.01\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph," }\r\n"); + fi_fprintf(fph,"\r\n"); + +// let's save each sub-mesh we encounter... + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + Mesh *m = ms->mMeshes[i]; + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + exportSubMesh(m,sm,fph); + } + } + + for (MiU32 i=0; i<ms->mMeshCount; i++) + { + Mesh *m = ms->mMeshes[i]; + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + char scratch[512]; + MESH_IMPORT_STRING::snprintf(scratch,512,"%s_%s", m->mName, sm->mMaterialName ); + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," object {\r\n"); + fi_fprintf(fph," %s\r\n", scratch); + fi_fprintf(fph," texture { Mesh_TextureA }\r\n"); + fi_fprintf(fph," }\r\n"); + } + } + + + + size_t outputLength; + void *mem = fi_getMemBuffer(fph,&outputLength); + if ( mem ) + { + ret = MI_ALLOC(outputLength); + if ( ret ) + { + memcpy(ret,mem,outputLength); + len = (MiU32)outputLength; + } + } + fi_fclose(fph); + } + } + return ret; +} + + +};// end of namespace + diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.h new file mode 100644 index 00000000..58c5f570 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef EXPORT_POVRAY_H + +#define EXPORT_POVRAY_H + +#include "MiFileInterface.h" +#include "MeshImport.h" + +namespace mimp +{ + +void * serializePOVRay(const MeshSystem *ms,MiU32 &dlen); + +};// end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImport.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImport.cpp new file mode 100644 index 00000000..f2ae7664 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImport.cpp @@ -0,0 +1,2569 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#pragma warning(disable:4702) // disabling a warning that only shows up when building VC7 + +#include <assert.h> +#if defined(__GNUC__) +#include <string> +#endif +#include <vector> + +#include "MeshImport.h" +#include "VtxWeld.h" +#include "MeshImportBuilder.h" +#include "MiFileInterface.h" +#include "MiSutil.h" +#include "MiFloatMath.h" +#include "ExportFBX.h" +#include "ExportEZB.h" +#include "ExportPOVRay.h" +#include "ExportDynamicSystem.h" +#include "ExportAPX.h" + +#pragma warning(disable:4996) + + +#ifdef WIN32 +#ifdef MESHIMPORT_EXPORTS +#define MESHIMPORT_API __declspec(dllexport) +#else +#define MESHIMPORT_API __declspec(dllimport) +#endif +#else +#define MESHIMPORT_API +#endif + +#pragma warning(disable:4100) + +namespace mimp +{ + +static const char *cleanAttribute(const char *attribute) +{ + static char scratch[1024]; + char *end = &scratch[1020]; + char *dest = scratch; + while ( attribute && *attribute && dest < end ) + { + if ( *attribute == 34 ) + { + dest[0]= '%'; + dest[1] = '2'; + dest[2] = '0'; + dest+=3; + attribute++; + } + else + { + *dest++ = *attribute++; + } + } + *dest = 0; + return scratch; +} + +MeshImport *gMeshImport=NULL; + +struct Vector +{ + MiF32 x; + MiF32 y; + MiF32 z; +}; + +struct Vertex +{ + MiU16 mIndex; + MiF32 mTexel[2]; + MiU8 mMaterialIndex; + MiU8 mUnused; +}; + +struct Triangle +{ + MiU16 mWedgeIndex[3]; + MiU8 mMaterialIndex; + MiU8 mAuxMaterialIndex; + MiU32 mSmoothingGroups; +}; + +struct Material +{ + char mMaterialName[64]; + MiI32 mTextureIndex; + MiU32 mPolyFlags; + MiU32 mAuxMaterial; + MiU32 mAuxFlags; + MiI32 mLodBias; + MiI32 mLodStyle; +}; + +struct Bone +{ + char mName[64]; + MiU32 mFlags; + MiI32 mNumChildren; + MiI32 mParentIndex; + MiF32 mOrientation[4]; + MiF32 mPosition[3]; + MiF32 mLength; + MiF32 mXSize; + MiF32 mYSize; + MiF32 mZSize; +}; + +struct BoneInfluence +{ + MiF32 mWeight; + MiI32 mVertexIndex; + MiI32 mBoneIndex; +}; + +struct AnimInfo +{ + char mName[64]; + char mGroup[64]; // Animation's group name + MiI32 mTotalBones; // TotalBones * NumRawFrames is number of animation keys to digest. + MiI32 mRootInclude; // 0 none 1 included (unused) + MiI32 mKeyCompressionStyle; // Reserved: variants in tradeoffs for compression. + MiI32 mKeyQuotum; // Max key quotum for compression + MiF32 mKeyReduction; // desired + MiF32 mTrackTime; // explicit - can be overridden by the animation rate + MiF32 mAnimRate; // frames per second. + MiI32 mStartBone; // - Reserved: for partial animations (unused) + MiI32 mFirstRawFrame; // + MiI32 mNumRawFrames; // NumRawFrames and AnimRate dictate tracktime... +}; + +struct AnimKey +{ + MiF32 mPosition[3]; + MiF32 mOrientation[4]; + MiF32 mTime; +}; + +struct ScaleKey +{ + MiF32 mScale[4]; +}; + +}; // end of namespace + +extern "C" +{ + MESHIMPORT_API mimp::MeshImport * getInterface(mimp::MiI32 version_number); +}; + +namespace mimp +{ + +class LocalVertexIndex : public VertexIndex, public mimp::MeshImportAllocated +{ +public: + LocalVertexIndex(MiF32 granularity) + { + mVertexIndex = fm_createVertexIndex(granularity,false); + } + + virtual ~LocalVertexIndex(void) + { + fm_releaseVertexIndex(mVertexIndex); + } + + virtual MiU32 getIndex(const MiF32 pos[3],bool &newPos) // get welded index for this MiF32 vector[3] + { + return mVertexIndex->getIndex(pos,newPos); + } + + virtual const MiF32 * getVertices(void) const + { + return mVertexIndex->getVerticesFloat(); + } + + virtual const MiF32 * getVertex(MiU32 index) const + { + return mVertexIndex->getVertexFloat(index); + } + + virtual MiU32 getVcount(void) const + { + return mVertexIndex->getVcount(); + } + +private: + fm_VertexIndex *mVertexIndex; +}; + +class MyMeshImportApplicationResource : public MeshImportApplicationResource +{ +public: + virtual void * getApplicationResource(const char * /*base_name*/,const char *resource_name,MiU32 &len) + { + void * ret = 0; + len = 0; + + FILE *fph = fopen(resource_name,"rb"); + if ( fph ) + { + fseek(fph,0L,SEEK_END); + len = (MiU32)ftell(fph); + fseek(fph,0L,SEEK_SET); + if ( len > 0 ) + { + ret = MI_ALLOC(len+1); + fread(ret,len,1,fph); + ((MiU8*)ret)[len] = 0; + } + fclose(fph); + } + return ret; + } + + virtual void releaseApplicationResource(void *mem) + { + MI_FREE(mem); + } + +}; + +typedef STDNAME::vector< MeshImporter * > MeshImporterVector; + +class MyMeshImport : public mimp::MeshImport, public MyMeshImportApplicationResource, public mimp::MeshImportAllocated +{ +public: + MyMeshImport(void) + { + mApplicationResource = this; + } + + ~MyMeshImport(void) + { + } + + VertexIndex * createVertexIndex(MiF32 granularity) // create an indexed vertext system for floats + { + LocalVertexIndex *m = MI_NEW(LocalVertexIndex)(granularity); + return static_cast< VertexIndex *>(m); + } + + void releaseVertexIndex(VertexIndex *vindex) + { + LocalVertexIndex *m = static_cast< LocalVertexIndex *>(vindex); + delete m; + } + + virtual MeshImporter * locateMeshImporter(const char *fname) // based on this file name, find a matching mesh importer. + { + MeshImporter *ret = 0; + + const char *dot = lastDot(fname); + if ( dot ) + { + char scratch[512]; + strncpy(scratch,dot,512); + MeshImporterVector::iterator i; + for (i=mImporters.begin(); i!=mImporters.end(); ++i) + { + MeshImporter *mi = (*i); + MiI32 count = mi->getExtensionCount(); + for (MiI32 j=0; j<count; j++) + { + const char *ext = mi->getExtension(j); + if ( MESH_IMPORT_STRING::stricmp(ext,scratch) == 0 ) + { + ret = mi; + break; + } + } + if ( ret ) break; + } + } + return ret; + } + + virtual void addImporter(MeshImporter *importer) // add an additional importer + { + if ( importer ) + { + mImporters.push_back(importer); + } + else + { + printf("debug me"); + } + } + + bool importMesh(const char *meshName,const void *data,MiU32 dlen,MeshImportInterface *callback,const char *options) + { + bool ret = false; + + MeshImporter *mi = locateMeshImporter(meshName); + if ( mi ) + { + ret = mi->importMesh(meshName,data,dlen,callback,options,mApplicationResource); + } + else + { + printf("debug me"); + } + + return ret; + } + + virtual MeshSystem * getMeshSystem(MeshSystemContainer *_b) + { + MeshBuilder *b = (MeshBuilder *)_b; + return static_cast< MeshSystem *>(b); + } + + virtual MeshSystemContainer * createMeshSystemContainer(void) + { + MeshSystemContainer *ret = 0; + + MeshBuilder *b = createMeshBuilder(mApplicationResource); + if ( b ) + { + ret = (MeshSystemContainer *)b; + } + + return ret; + } + + bool isEZB(const char *fname) + { + char scratch[512]; + MESH_IMPORT_STRING::snprintf(scratch,512,"%s",fname); + MESH_IMPORT_STRING::strlwr(scratch); + char *ezb = strstr(scratch,".ezb"); + return ezb ? true : false; + } + + virtual MeshSystemContainer * createMeshSystemContainer(const char *meshName,const void *data,MiU32 dlen,const char *options) // imports and converts to a single MeshSystem data structure + { + MeshSystemContainer *ret = 0; + + if ( isEZB(meshName)) + { + MeshBuilder *b = createMeshBuilder(meshName,data,dlen,NULL,options,mApplicationResource); + if ( b ) + { + ret = (MeshSystemContainer *)b; + } + } + else + { + MeshImporter *mi = locateMeshImporter(meshName); + if ( mi ) + { + MeshBuilder *b = createMeshBuilder(meshName,data,dlen,mi,options,mApplicationResource); + if ( b ) + { + ret = (MeshSystemContainer *)b; + } + } + } + + return ret; + } + + virtual void releaseMeshSystemContainer(MeshSystemContainer *mesh) + { + MeshBuilder *b = (MeshBuilder *)mesh; + releaseMeshBuilder(b); + } + + virtual MiI32 getImporterCount(void) + { + return (MiI32)mImporters.size(); + } + + virtual MeshImporter *getImporter(MiI32 index) + { + MeshImporter *ret = 0; + assert( index >=0 && index < (MiI32)mImporters.size() ); + if ( index >= 0 && index < (MiI32)mImporters.size() ) + { + ret = mImporters[(MiU32)index]; + } + return ret; + } + + const char *getStr(const char *str) + { + if ( str == 0 ) str = ""; + return str; + } + + void printAABB(FILE_INTERFACE * /*fph*/,const MeshAABB & /*a*/) + { +// fi_fprintf(fph," <MeshAABB min=\"%s,%s,%s\" max=\"%s,%s,%s\"/>\r\n", FloatString(a.mMin[0]), FloatString(a.mMin[1]), FloatString(a.mMin[2]), FloatString(a.mMax[0]), FloatString(a.mMax[1]), FloatString(a.mMax[2]) ); + } + + void print(FILE_INTERFACE * /*fph*/,MeshRawTexture * /*t*/) + { + assert(0); // not yet implemented + } + + void print(FILE_INTERFACE * /*fph*/,MeshTetra * /*t*/) + { + assert(0); // not yet implemented + } + + void print(FILE_INTERFACE *fph,MeshBone &b,MeshSkeleton *s) + { + const char *parent = 0; + + if ( b.mParentIndex >= 0 ) + { + assert( b.mParentIndex >= 0 && b.mParentIndex < s->mBoneCount ); + if ( b.mParentIndex >= 0 && b.mParentIndex < s->mBoneCount ) + { + parent = s->mBones[b.mParentIndex].mName; + } + } + if ( parent ) + { + fi_fprintf(fph," <Bone name=\"%s\" parent=\"%s\" orientation=\"%s %s %s %s\" position=\"%s %s %s\" scale=\"%s %s %s\"/>\r\n", + b.mName, + parent, + FloatString(b.mOrientation[0]), + FloatString(b.mOrientation[1]), + FloatString(b.mOrientation[2]), + FloatString(b.mOrientation[3]), + FloatString(b.mPosition[0]), + FloatString(b.mPosition[1]), + FloatString(b.mPosition[2]), + FloatString(b.mScale[0]), + FloatString(b.mScale[1]), + FloatString(b.mScale[2]) ); + } + else + { + fi_fprintf(fph," <Bone name=\"%s\" orientation=\"%s %s %s %s\" position=\"%s %s %s\" scale=\"%s %s %s\"/>\r\n", + b.mName, + FloatString(b.mOrientation[0]), + FloatString(b.mOrientation[1]), + FloatString(b.mOrientation[2]), + FloatString(b.mOrientation[3]), + FloatString(b.mPosition[0]), + FloatString(b.mPosition[1]), + FloatString(b.mPosition[2]), + FloatString(b.mScale[0]), + FloatString(b.mScale[1]), + FloatString(b.mScale[2]) ); + } + } + + void print(FILE_INTERFACE *fph,MeshSkeleton *s) + { + fi_fprintf(fph," <Skeleton name=\"%s\" count=\"%d\">\r\n", s->mName, s->mBoneCount); + for (MiU32 i=0; i<(MiU32)s->mBoneCount; i++) + { + print(fph,s->mBones[i],s); + } + fi_fprintf(fph," </Skeleton>\r\n"); + } + + void print(FILE_INTERFACE *fph,const MeshAnimPose &p) + { + fi_fprintf(fph," %s %s %s %s %s %s %s %s %s %s,\r\n", + FloatString(p.mPos[0]), + FloatString(p.mPos[1]), + FloatString(p.mPos[2]), + FloatString(p.mQuat[0]), + FloatString(p.mQuat[1]), + FloatString(p.mQuat[2]), + FloatString(p.mQuat[3]), + FloatString(p.mScale[0]), + FloatString(p.mScale[1]), + FloatString(p.mScale[2]) ); + } + + void print(FILE_INTERFACE *fph,MeshAnimTrack *track) + { + fi_fprintf(fph," <AnimTrack name=\"%s\" count=\"%d\" has_scale=\"true\">\r\n", track->mName, track->mFrameCount); + for (MiI32 i=0; i<track->mFrameCount; i++) + { + print(fph,track->mPose[i]); + } + fi_fprintf(fph," </AnimTrack>\r\n"); + + } + + void print(FILE_INTERFACE *fph,MeshAnimation *a) + { + fi_fprintf(fph," <Animation name=\"%s\" trackcount=\"%d\" framecount=\"%d\" duration=\"%s\" dtime=\"%s\">\r\n", a->mName, a->mTrackCount, a->mFrameCount, FloatString( a->mDuration ), FloatString( a->mDtime) ); + + for (MiI32 i=0; i<a->mTrackCount; i++) + { + print(fph,a->mTracks[i]); + } + + fi_fprintf(fph," </Animation>\r\n"); + + } + + void print(FILE_INTERFACE *fph,const MeshMaterial &m) + { + fi_fprintf(fph," <Material name=\"%s\" meta_data=\"%s\"/>\r\n", m.mName, cleanAttribute(m.mMetaData) ); + } + + void print(FILE_INTERFACE * /*fph*/,MeshUserData * /*d*/) + { + } + + void print(FILE_INTERFACE * /*fph*/,MeshUserBinaryData * /*d*/) + { + } + + const char * getCtype(MiU32 flags) + { + mCtype.clear(); + + if ( flags & MIVF_POSITION ) { mCtype+="fff "; }; + if ( flags & MIVF_NORMAL ) { mCtype+="fff "; }; + if ( flags & MIVF_COLOR ) { mCtype+="x4 "; }; + if ( flags & MIVF_TEXEL1 ) { mCtype+="ff "; }; + if ( flags & MIVF_TEXEL2 ) { mCtype+="ff "; }; + if ( flags & MIVF_TEXEL3 ) { mCtype+="ff "; }; + if ( flags & MIVF_TEXEL4 ) { mCtype+="ff "; }; + if ( flags & MIVF_TANGENT ) { mCtype+="fff "; }; + if ( flags & MIVF_BINORMAL ) { mCtype+="fff "; }; + if ( flags & MIVF_BONE_WEIGHTING ) { mCtype+="ffff hhhh "; }; + if ( flags & MIVF_INTERP1 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP2 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP3 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP4 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP5 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP6 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP7 ) { mCtype+="ffff "; }; + if ( flags & MIVF_INTERP8 ) { mCtype+="ffff "; }; + if ( flags & MIVF_RADIUS ) mCtype+="f "; + + if ( !mCtype.empty() ) + { + char *foo = (char *)mCtype.c_str(); + MiI32 len = (MiI32)strlen(foo); + if ( foo[len-1] == ' ' ) + { + foo[len-1] = 0; + } + } + + return mCtype.c_str(); + } + + const char * getSemantics(MiU32 flags) + { + mSemantic.clear(); + + if ( flags & MIVF_POSITION ) { mSemantic+="position "; }; + if ( flags & MIVF_NORMAL ) { mSemantic+="normal "; }; + if ( flags & MIVF_COLOR ) { mSemantic+="color "; }; + if ( flags & MIVF_TEXEL1 ) { mSemantic+="texcoord1 "; }; + if ( flags & MIVF_TEXEL2 ) { mSemantic+="texcoord2 "; }; + if ( flags & MIVF_TEXEL3 ) { mSemantic+="texcoord3 "; }; + if ( flags & MIVF_TEXEL4 ) { mSemantic+="texcoord4 "; }; + if ( flags & MIVF_TANGENT ) { mSemantic+="tangent "; }; + if ( flags & MIVF_BINORMAL ) { mSemantic+="binormal "; }; + if ( flags & MIVF_BONE_WEIGHTING ) { mSemantic+="blendweights blendindices "; }; + if ( flags & MIVF_INTERP1 ) { mSemantic+="interp1 "; }; + if ( flags & MIVF_INTERP2 ) { mSemantic+="interp2 "; }; + if ( flags & MIVF_INTERP3 ) { mSemantic+="interp3 "; }; + if ( flags & MIVF_INTERP4 ) { mSemantic+="interp4 "; }; + if ( flags & MIVF_INTERP5 ) { mSemantic+="interp5 "; }; + if ( flags & MIVF_INTERP6 ) { mSemantic+="interp6 "; }; + if ( flags & MIVF_INTERP7 ) { mSemantic+="interp7 "; }; + if ( flags & MIVF_INTERP8 ) { mSemantic+="interp8 "; }; + if ( flags & MIVF_RADIUS ) mSemantic+="radius "; + + if ( !mSemantic.empty() ) + { + char *foo = (char *)mSemantic.c_str(); + MiI32 len = (MiI32)strlen(foo); + if ( foo[len-1] == ' ' ) + { + foo[len-1] = 0; + } + } + + + return mSemantic.c_str(); + } + + void printVertex(FILE_INTERFACE *fph,MiU32 flags,const MeshVertex &v,MiU32 &column,bool &newRow) + { + if ( newRow ) + { + if ( column != 0 ) + { + fi_fprintf(fph,"\r\n"); + } + newRow = false; + column = 0; + fi_fprintf(fph," "); + } + char scratch[1024] = { 0 }; + char temp[1024]; + + if ( flags & MIVF_POSITION ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mPos[0]), FloatString(v.mPos[1]), FloatString(v.mPos[2]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + + if ( flags & MIVF_NORMAL ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mNormal[0]), FloatString(v.mNormal[1]), FloatString(v.mNormal[2]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + + if ( flags & MIVF_COLOR ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%08X ", v.mColor ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_TEXEL1 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s ", FloatString(v.mTexel1[0]), FloatString(v.mTexel1[1]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_TEXEL2 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s ", FloatString(v.mTexel2[0]), FloatString(v.mTexel2[1]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_TEXEL3 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s ", FloatString(v.mTexel3[0]), FloatString(v.mTexel3[1]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_TEXEL4 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s ", FloatString(v.mTexel4[0]), FloatString(v.mTexel4[1]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_TANGENT ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mTangent[0]), FloatString(v.mTangent[1]), FloatString(v.mTangent[2]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_BINORMAL ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mBiNormal[0]), FloatString(v.mBiNormal[1]), FloatString(v.mBiNormal[2]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_BONE_WEIGHTING ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s %s ", FloatString(v.mWeight[0]), FloatString(v.mWeight[1]), FloatString(v.mWeight[2]), FloatString(v.mWeight[3]) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + MESH_IMPORT_STRING::snprintf(temp,1024,"%d %d %d %d ", v.mBone[0], v.mBone[1], v.mBone[2], v.mBone[3] ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP1 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp1[0]), FloatString(v.mInterp1[1]), FloatString(v.mInterp1[2]) , FloatString(v.mInterp1[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP2 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp2[0]), FloatString(v.mInterp2[1]), FloatString(v.mInterp2[2]) , FloatString(v.mInterp2[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP3 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp3[0]), FloatString(v.mInterp3[1]), FloatString(v.mInterp3[2]) , FloatString(v.mInterp3[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP4 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp4[0]), FloatString(v.mInterp4[1]), FloatString(v.mInterp4[2]) , FloatString(v.mInterp4[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP5 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp5[0]), FloatString(v.mInterp5[1]), FloatString(v.mInterp5[2]) , FloatString(v.mInterp5[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP6 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp6[0]), FloatString(v.mInterp6[1]), FloatString(v.mInterp6[2]) , FloatString(v.mInterp6[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP7 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp7[0]), FloatString(v.mInterp7[1]), FloatString(v.mInterp7[2]) , FloatString(v.mInterp7[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_INTERP8 ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s %s %s ", FloatString(v.mInterp8[0]), FloatString(v.mInterp8[1]), FloatString(v.mInterp8[2]) , FloatString(v.mInterp8[3])); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + if ( flags & MIVF_RADIUS ) + { + MESH_IMPORT_STRING::snprintf(temp,1024,"%s ", FloatString(v.mRadius) ); + MESH_IMPORT_STRING::strlcat(scratch,1024,temp); + } + MESH_IMPORT_STRING::strlcat(scratch,1024,", "); + MiU32 slen = (MiU32)strlen(scratch); + fi_fprintf(fph,"%s", scratch ); + column+=slen; + if ( column >= 160 ) + newRow = true; + } + + void printIndex(FILE_INTERFACE *fph,const MiU32 *idx,MiU32 &column,bool &newRow) + { + if ( newRow ) + { + if ( column != 0 ) + { + fi_fprintf(fph,"\r\n"); + } + newRow = false; + column = 0; + fi_fprintf(fph," "); + } + char temp[1024]; + MESH_IMPORT_STRING::snprintf(temp,1024,"%d %d %d, ", idx[0], idx[1], idx[2] ); + fi_fprintf(fph,"%s",temp); + MiU32 slen = (MiU32)strlen(temp); + column+=slen; + if ( column >= 160 ) + newRow = true; + } + + + void print(FILE_INTERFACE *fph,SubMesh *m) + { + fi_fprintf(fph," <MeshSection material=\"%s\" ctype=\"%s\" semantic=\"%s\">\r\n", m->mMaterialName, getCtype(m->mVertexFlags), getSemantics(m->mVertexFlags) ); + printAABB(fph,m->mAABB); + + fi_fprintf(fph," <indexbuffer triangle_count=\"%d\">\r\n", m->mTriCount ); + const MiU32 *scan = m->mIndices; + bool newRow = true; + MiU32 column = 0; + for (MiU32 i=0; i<m->mTriCount; i++) + { + printIndex(fph,scan,column,newRow); + scan+=3; + } + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </indexbuffer>\r\n"); + + fi_fprintf(fph," </MeshSection>\r\n"); + } + + void print(FILE_INTERFACE *fph,Mesh *m) + { + fi_fprintf(fph," <Mesh name=\"%s\" skeleton=\"%s\" submesh_count=\"%d\">\r\n", m->mName, m->mSkeletonName, m->mSubMeshCount ); + printAABB(fph,m->mAABB); + + fi_fprintf(fph," <vertexbuffer count=\"%d\" ctype=\"%s\" semantic=\"%s\">\r\n", m->mVertexCount, getCtype(m->mVertexFlags), getSemantics(m->mVertexFlags) ); + + bool newRow=true; + MiU32 column=0; + + for (MiU32 i=0; i<m->mVertexCount; i++) + { + printVertex(fph, m->mVertexFlags, m->mVertices[i], column, newRow ); + + } + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </vertexbuffer>\r\n"); + + + for (MiU32 i=0; i<m->mSubMeshCount; i++) + { + print(fph,m->mSubMeshes[i]); + } + + fi_fprintf(fph," </Mesh>\r\n"); + } + + void print(FILE_INTERFACE *fph,MeshInstance &m) + { + fi_fprintf(fph," <MeshInstance mesh=\"%s\" position=\"%s,%s,%s\" rotation=\"%s,%s,%s,%s\" scale=\"%s,%s,%s\"/>\r\n", + m.mMeshName, + FloatString( m.mPosition[0] ), + FloatString( m.mPosition[1] ), + FloatString( m.mPosition[2] ), + FloatString( m.mRotation[0] ), + FloatString( m.mRotation[1] ), + FloatString( m.mRotation[2] ), + FloatString( m.mRotation[3] ), + FloatString( m.mScale[0] ), + FloatString( m.mScale[1] ), + FloatString( m.mScale[2] ) ); + } + + const char * getTypeString(MeshCollisionType t) + { + const char *ret = "unknown"; + switch ( t ) + { + case MCT_BOX: ret = "BOX"; break; + case MCT_SPHERE: ret = "SPHERE"; break; + case MCT_CAPSULE: ret = "CAPSULE"; break; + case MCT_CONVEX: ret = "CONVEX"; break; + case MCT_LAST: break; // Make compiler happy + } + return ret; + } + + void print(FILE_INTERFACE *fph,MeshCollisionBox * /*b*/) + { + fi_fprintf(fph," <MeshCollisionBox >\r\n"); + fi_fprintf(fph," </MeshCollisionBox>\r\n"); + } + + void print(FILE_INTERFACE *fph,MeshCollisionSphere * /*b*/) + { + fi_fprintf(fph," <MeshCollisionSphere >\r\n"); + fi_fprintf(fph," </MeshCollisionSphere>\r\n"); + } + + void print(FILE_INTERFACE *fph,MeshCollisionCapsule * /*b*/) + { + fi_fprintf(fph," <MeshCollisionCapsule >\r\n"); + fi_fprintf(fph," </MeshCollisionCapsule>\r\n"); + } + + void print(FILE_INTERFACE *fph,MeshCollisionConvex *m) + { + fi_fprintf(fph," <MeshCollisionConvex >\r\n"); + + { + bool newRow = true; + fi_fprintf(fph," <vertexbuffer count=\"%d\" ctype=\"fff\" semantic=\"position\">\r\n", m->mVertexCount ); + for (MiU32 i=0; i<m->mVertexCount; i++) + { + const MiF32 *p = &m->mVertices[i*3]; + if ( newRow ) + { + fi_fprintf(fph," "); + newRow = false; + } + + fi_fprintf(fph,"%s %s %s, ",FloatString(p[0]), FloatString(p[1]), FloatString(p[2]) ); + if ( (i&7) == 0 ) + { + fi_fprintf(fph,"\r\n"); + newRow = true; + } + } + if ( !newRow ) + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </vertexbuffer>\r\n"); + } + + { + fi_fprintf(fph," <indexbuffer triangle_count=\"%d\">\r\n", m->mTriCount ); + const MiU32 *scan = m->mIndices; + bool newRow = true; + MiU32 column = 0; + for (MiU32 i=0; i<m->mTriCount; i++) + { + printIndex(fph,scan,column,newRow); + scan+=3; + } + fi_fprintf(fph,"\r\n"); + fi_fprintf(fph," </indexbuffer>\r\n"); + } + + fi_fprintf(fph," </MeshCollisionConvex>\r\n"); + } + + void print(FILE_INTERFACE * /*fph*/,MeshCollision * /*m*/) + { + assert(0); // TODO TODO +#if 0 + fi_fprintf(fph," <MeshCollision name=\"%s\" type=\"%s\" transform=\"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\">\r\n", + m->mName,getTypeString(m->mType), + FloatString( m->mTransform[0] ), + FloatString( m->mTransform[1] ), + FloatString( m->mTransform[2] ), + FloatString( m->mTransform[3] ), + FloatString( m->mTransform[4] ), + FloatString( m->mTransform[5] ), + FloatString( m->mTransform[6] ), + FloatString( m->mTransform[7] ), + FloatString( m->mTransform[8] ), + FloatString( m->mTransform[9] ), + FloatString( m->mTransform[10] ), + FloatString( m->mTransform[11] ), + FloatString( m->mTransform[12] ), + FloatString( m->mTransform[13] ), + FloatString( m->mTransform[14] ), + FloatString( m->mTransform[15] ) ); + + switch ( m->mType ) + { + case MCT_BOX: + { + MeshCollisionBox *b = static_cast< MeshCollisionBox *>(m); + print(fph,b); + } + break; + case MCT_SPHERE: + { + MeshCollisionSphere *b = static_cast< MeshCollisionSphere *>(m); + print(fph,b); + } + break; + case MCT_CAPSULE: + { + MeshCollisionCapsule *b = static_cast< MeshCollisionCapsule *>(m); + print(fph,b); + } + break; + case MCT_CONVEX: + { + MeshCollisionConvex *b = static_cast< MeshCollisionConvex *>(m); + print(fph,b); + } + break; + case MCT_LAST: // Make compiler happy + break; + } + + fi_fprintf(fph," </MeshCollision>\r\n"); +#endif + } + + void print(FILE_INTERFACE *fph,MeshCollisionRepresentation *m) + { + fi_fprintf(fph," <MeshCollisionRepresentation name=\"%s\" info=\"%s\" count=\"%d\">\r\n", m->mName, m->mInfo, m->mCollisionCount ); + for (MiU32 i=0; i<m->mCollisionCount; i++) + { + print(fph,m->mCollisionGeometry[i]); + } + fi_fprintf(fph," </MeshCollisionRepresentation>\r\n"); + + } + + void putHeader(FILE_INTERFACE *fph,const char *header,MiI32 type,MiI32 len,MiI32 count) + { + char h[20]; + strncpy(h,header,20); + fi_fwrite(h,sizeof(h),1,fph); + fi_fwrite(&type, sizeof(MiI32), 1, fph ); + fi_fwrite(&len, sizeof(MiI32), 1, fph ); + fi_fwrite(&count, sizeof(MiI32), 1, fph ); + } + + void serializePSK(FILE_INTERFACE *fph,MeshSystem *ms,FILE_INTERFACE *fpanim) + { + if ( ms->mMeshCount == 0 ) return; + + typedef STDNAME::vector< Vector > VectorVector; + typedef STDNAME::vector< Vertex > VertexVector; + typedef STDNAME::vector< Triangle > TriangleVector; + typedef STDNAME::vector< Material > MaterialVector; + typedef STDNAME::vector< Bone > BoneVector; + typedef STDNAME::vector< BoneInfluence > BoneInfluenceVector; + + Mesh *mesh = ms->mMeshes[0]; + + VectorVector _positions; + VertexVector _vertices; + TriangleVector _triangles; + MaterialVector _materials; + BoneVector _bones; + BoneInfluenceVector _boneInfluences; + const MiF32 POSITION_SCALE=50.0f; + + for (MiU32 i=0; i<mesh->mVertexCount; i++) + { + Vector v; + MeshVertex &mv = mesh->mVertices[i]; + v.x = mv.mPos[0]*POSITION_SCALE; + v.y = mv.mPos[1]*POSITION_SCALE; + v.z = mv.mPos[2]*POSITION_SCALE;; + _positions.push_back(v); + } + + for (MiU32 i=0; i<mesh->mVertexCount; i++) + { + // MiU16 mIndex; + // MiF32 mTexel[2]; + // MiU8 mMaterialIndex; + // MiU8 mUnused; + + Vertex v; + MeshVertex &mv = mesh->mVertices[i]; + + v.mIndex = (MiU16)i; + v.mTexel[0] = mv.mTexel1[0]; + v.mTexel[1] = mv.mTexel1[1]; + v.mMaterialIndex = 0; + v.mUnused = 0; + + _vertices.push_back(v); + } + + + for (MiU32 i=0; i<mesh->mSubMeshCount; i++) + { + SubMesh &sm = *mesh->mSubMeshes[i]; + MiU32 matid = 0; + for (MiU32 k=0; k<ms->mMaterialCount; k++) + { + if ( MESH_IMPORT_STRING::stricmp(sm.mMaterialName,ms->mMaterials[k].mName) == 0 ) + { + matid = k; + break; + } + } + for (MiU32 j=0; j<sm.mTriCount; j++) + { + MiU32 i1 = sm.mIndices[j*3+0]; + MiU32 i2 = sm.mIndices[j*3+1]; + MiU32 i3 = sm.mIndices[j*3+2]; + + Vertex &v1 = _vertices[i1]; + Vertex &v2 = _vertices[i2]; + Vertex &v3 = _vertices[i3]; + + v1.mMaterialIndex = (MiU8)matid; + v2.mMaterialIndex = (MiU8)matid; + v3.mMaterialIndex = (MiU8)matid; + +// MiU16 mWedgeIndex[3]; +// MiU8 mMaterialIndex; +// MiU8 mAuxMaterialIndex; +// MiU32 mSmoothingGroups; + + Triangle t; + + t.mWedgeIndex[0] = (MiU16)i3; + t.mWedgeIndex[1] = (MiU16)i2; + t.mWedgeIndex[2] = (MiU16)i1; + + t.mMaterialIndex = (MiU8)matid; + t.mAuxMaterialIndex = 0; + t.mSmoothingGroups = 0; + _triangles.push_back(t); + + } + } + + for (MiU32 i=0; i<ms->mMaterialCount; i++) + { +// char mMaterialName[64]; +// MiI32 mTextureIndex; +// MiU32 mPolyFlags; +// MiU32 mAuxMaterial; +// MiI32 mLodBias; +// MiI32 mLodStyle; + + MeshMaterial &mm = ms->mMaterials[i]; + Material m; + strncpy(m.mMaterialName,mm.mName,64); + m.mTextureIndex = 0; + m.mPolyFlags = 0; + m.mAuxMaterial = 0; + m.mLodBias = 0; + m.mLodStyle = 5; + _materials.push_back(m); + } + + if ( ms->mSkeletonCount ) + { + MeshSkeleton &sk = *ms->mSkeletons[0]; + for (MiI32 i=0; i<sk.mBoneCount; i++) + { +// char mName[64]; +// MiU32 mFlags; +// MiI32 mNumChildren; +// MiI32 mParentIndex; +// MiF32 mOrientation[4]; +// MiF32 mPosition[3]; +// MiF32 mLength; +// MiF32 mXSize; +// MiF32 mYSize; +// MiF32 mZSize; + + MeshBone &mb = sk.mBones[i]; + Bone b; + strncpy(b.mName, mb.mName, 64 ); + b.mParentIndex = (mb.mParentIndex == -1) ? 0 : mb.mParentIndex; + + b.mOrientation[0] = mb.mOrientation[0]; + b.mOrientation[1] = mb.mOrientation[1]; + b.mOrientation[2] = mb.mOrientation[2]; + b.mOrientation[3] = mb.mOrientation[3]; + + if ( i ) + { + b.mOrientation[3]*=-1; + } + + b.mPosition[0] = mb.mPosition[0]*POSITION_SCALE; + b.mPosition[1] = mb.mPosition[1]*POSITION_SCALE; + b.mPosition[2] = mb.mPosition[2]*POSITION_SCALE; + + b.mNumChildren = 0; + + if ( mb.mParentIndex != -1 ) + { + b.mLength = fm_distance( mb.mPosition, sk.mBones[ mb.mParentIndex ].mPosition)*POSITION_SCALE; + } + for (MiI32 k=i+1; k<sk.mBoneCount; k++) + { + MeshBone &ch = sk.mBones[k]; + if ( ch.mParentIndex == i ) + { + b.mNumChildren++; + } + } + + b.mXSize = mb.mScale[0]; + b.mYSize = mb.mScale[1]; + b.mZSize = mb.mScale[2]; + + _bones.push_back(b); + + } + } + + for (MiU32 i=0; i<mesh->mVertexCount; i++) + { + + BoneInfluence b; + MeshVertex &mv = mesh->mVertices[i]; + +// MiF32 mWeight; +// MiI32 mVertexIndex; +// MiI32 mBoneIndex; + b.mVertexIndex = (MiI32)i; + for (MiU32 j=0; j<4; j++) + { + if ( mv.mWeight[j] >0 ) + { + b.mWeight = mv.mWeight[j]; + b.mBoneIndex = mv.mBone[j]; + _boneInfluences.push_back(b); + } + } + } + + + + + + MiI32 positionsCount = (MiI32)_positions.size(); + Vector *positions = positionsCount ? &_positions[0] : 0; + + MiI32 vertexCount = (MiI32) _vertices.size(); + Vertex *vertices = vertexCount ? &_vertices[0] : 0; + + MiI32 triangleCount = (MiI32) _triangles.size(); + Triangle *triangles = triangleCount ? &_triangles[0] : 0; + + MiI32 materialCount = (MiI32) _materials.size(); + Material *materials = materialCount ? &_materials[0] : 0; + + MiI32 boneCount = (MiI32)_bones.size(); + Bone *bones = boneCount ? &_bones[0] : 0; + + MiI32 boneInfluenceCount = (MiI32)_boneInfluences.size(); + BoneInfluence *boneInfluences = boneInfluenceCount ? &_boneInfluences[0] : 0; + + putHeader(fph,"ACTRHEAD",2003321,0,0); + + putHeader(fph,"PNTS0000",0,sizeof(Vector),positionsCount); + if ( positionsCount ) fi_fwrite(positions,sizeof(Vector)*positionsCount,1,fph); + + putHeader(fph,"VTXW0000",0,sizeof(Vertex),vertexCount); + if ( vertexCount ) fi_fwrite(vertices, sizeof(Vertex)*vertexCount,1,fph); + + putHeader(fph,"FACE0000",0,sizeof(Triangle),triangleCount); + if ( triangleCount ) fi_fwrite(triangles,sizeof(Triangle)*triangleCount,1,fph); + + putHeader(fph,"MATT0000",0,sizeof(Material),materialCount); + if ( materialCount ) fi_fwrite(materials,sizeof(Material)*materialCount,1,fph); + + putHeader(fph,"REFSKELT",0,sizeof(Bone),boneCount); + if ( boneCount ) fi_fwrite(bones,sizeof(Bone)*boneCount,1,fph); + + putHeader(fph,"RAWWEIGHTS",0,sizeof(BoneInfluence),boneInfluenceCount); + if ( boneInfluenceCount ) fi_fwrite(boneInfluences,sizeof(BoneInfluence)*boneInfluenceCount,1,fph); + + + // ok let's output the animation data if there is any.. + if ( ms->mAnimationCount ) + { + + + //struct AnimInfo + //{ + // char mName[64]; + // char mGroup[64]; // Animation's group name + // MiI32 mTotalBones; // TotalBones * NumRawFrames is number of animation keys to digest. + // MiI32 mRootInclude; // 0 none 1 included (unused) + // MiI32 mKeyCompressionStyle; // Reserved: variants in tradeoffs for compression. + // MiI32 mKeyQuotum; // Max key quotum for compression + // MiF32 mKeyReduction; // desired + // MiF32 mTrackTime; // explicit - can be overridden by the animation rate + // MiF32 mAnimRate; // frames per second. + // MiI32 mStartBone; // - Reserved: for partial animations (unused) + // MiI32 mFirstRawFrame; // + // MiI32 mNumRawFrames; // NumRawFrames and AnimRate dictate tracktime... + //}; + + MeshAnimation *anim = ms->mAnimations[0]; + + AnimInfo ainfo; + strncpy(ainfo.mName, anim->mName, 64 ); + MESH_IMPORT_STRING::snprintf(ainfo.mGroup,64,"NONE"); + ainfo.mTotalBones = anim->mTrackCount; + ainfo.mRootInclude = 0; + ainfo.mKeyCompressionStyle = 0; + ainfo.mKeyQuotum = 55088; + ainfo.mKeyReduction = 1; + ainfo.mTrackTime = (MiF32)(anim->mFrameCount); // + ainfo.mAnimRate = 1.0f / anim->mDtime; + ainfo.mFirstRawFrame = 0; + ainfo.mStartBone = 0; + ainfo.mFirstRawFrame = 0; + ainfo.mNumRawFrames = anim->mTrackCount; + + typedef STDNAME::vector< AnimKey > AnimKeyVector; + typedef STDNAME::vector< Bone > BoneVector; + BoneVector animBones; + + MeshSkeleton *sk = 0; + if ( ms->mSkeletonCount ) + { + sk = ms->mSkeletons[0]; + if ( sk->mBoneCount != anim->mTrackCount ) + { + sk = 0; + } + } + + for (MiI32 i=0; i<anim->mTrackCount; i++) + { + MeshAnimTrack *track = anim->mTracks[i]; + MeshAnimPose &pose = track->mPose[0]; + Bone b; + strncpy(b.mName, track->mName, 64 ); + b.mFlags = 0; + b.mNumChildren = 0; + b.mParentIndex = 0; + + if ( sk ) + { + MeshBone &mb = sk->mBones[i]; + if ( strcmp(mb.mName,b.mName) == 0 ) + { + b = _bones[(MiU32)i]; // just copy the bone from the skeleton. + } + } + + b.mPosition[0] = pose.mPos[0]; + b.mPosition[1] = -pose.mPos[1]; + b.mPosition[2] = pose.mPos[2]; + + b.mOrientation[0] = pose.mQuat[0]; + b.mOrientation[1] = -pose.mQuat[1]; + b.mOrientation[2] = pose.mQuat[2]; + b.mOrientation[3] = -pose.mQuat[3]; + + if ( i > 0 ) + { + b.mOrientation[3]*=-1; + } + + b.mXSize = pose.mScale[0]; + b.mYSize = pose.mScale[1]; + b.mZSize = pose.mScale[2]; + + if ( i ) + { + + b.mLength = fm_distance( b.mPosition, animBones[ (MiU32)b.mParentIndex ].mPosition ); + } + else + { + b.mLength = 0; + } + + animBones.push_back(b); + } + + AnimKeyVector keys; + MiF32 ctime = 0; + for (MiI32 i=0; i<anim->mFrameCount; i++) + { + for (MiI32 j=0; j<anim->mTrackCount; j++) + { + MeshAnimTrack *track = anim->mTracks[j]; + MeshAnimPose &pose = track->mPose[i]; + AnimKey a; + + a.mPosition[0] = pose.mPos[0]; + a.mPosition[1] = pose.mPos[1]; + a.mPosition[2] = pose.mPos[2]; + + a.mOrientation[0] = pose.mQuat[0]; + a.mOrientation[1] = pose.mQuat[1]; + a.mOrientation[2] = pose.mQuat[2]; + a.mOrientation[3] = pose.mQuat[3]; + a.mTime = ctime; + + if ( j ) + { + a.mOrientation[3]*=-1; + } + keys.push_back(a); + } + ctime+=anim->mDtime; + } + + + MiI32 boneCount = (MiI32)animBones.size(); + Bone *bones = boneCount ? &animBones[0] : 0; + MiI32 keyCount = (MiI32)keys.size(); + AnimKey *k = keyCount ? &keys[0] : 0; + + + putHeader(fpanim,"ANIMHEAD",2003321,0,0); + + putHeader(fpanim,"BONENAMES", 0, sizeof(Bone), anim->mTrackCount); + if ( boneCount ) fi_fwrite(bones,sizeof(Bone)*boneCount,1,fpanim); + + putHeader(fpanim,"ANIMINFO", 0, sizeof(AnimInfo), 1 ); + fi_fwrite(&ainfo, sizeof(AnimInfo), 1, fpanim ); + + putHeader(fpanim,"ANIMKEYS", 0, sizeof(AnimKey), keyCount ); + if ( keyCount ) fi_fwrite(k, sizeof(AnimKey)*keyCount, 1, fpanim); + + putHeader(fpanim,"SCALEKEYS", 0, sizeof(ScaleKey), 0 ); + + + } + + + + } + + void serializeEzm(FILE_INTERFACE *fph,MeshSystem *mesh) + { + fi_fprintf(fph,"<?xml version=\"1.0\"?>\r\n"); + fi_fprintf(fph," <MeshSystem asset_name=\"%s\" asset_info=\"%s\" mesh_system_version=\"%d\" mesh_system_asset_version=\"%d\">\r\n", getStr(mesh->mAssetName), getStr(mesh->mAssetInfo), mesh->mMeshSystemVersion, mesh->mAssetVersion ); + printAABB(fph,mesh->mAABB); + + //******************************************************************* + //*** + //*** Output Textures + //*** + //******************************************************************* + if ( mesh->mTextureCount ) + { + fi_fprintf(fph," <Textures count=\"%d\">\r\n", mesh->mTextureCount ); + for (MiU32 i=0; i<mesh->mTextureCount; i++) + { + print(fph,mesh->mTextures[i]); + } + fi_fprintf(fph," </Textures>\r\n"); + } + + + //******************************************************************* + //*** + //*** Tetraheadral meshes + //*** + //******************************************************************* + if ( mesh->mTetraMeshCount ) + { + fi_fprintf(fph," <TetraMeshes count=\"%d\">\r\n", mesh->mTetraMeshCount ); + for (MiU32 i=0; i<mesh->mTetraMeshCount; i++) + { + print(fph,mesh->mTetraMeshes[i]); + } + fi_fprintf(fph," </TetraMeshes>\r\n"); + } + + //******************************************************************* + //*** + //*** Output skeletons + //*** + //******************************************************************* + if ( mesh->mSkeletonCount ) + { + fi_fprintf(fph," <Skeletons count=\"%d\">\r\n", mesh->mSkeletonCount); + for (MiU32 i=0; i<mesh->mSkeletonCount; i++) + { + print(fph,mesh->mSkeletons[i]); + } + fi_fprintf(fph," </Skeletons>\r\n"); + } + + //******************************************************************* + //*** + //*** Output Animations + //*** + //******************************************************************* + if ( mesh->mAnimationCount ) + { + fi_fprintf(fph," <Animations count=\"%d\">\r\n", mesh->mAnimationCount ); + for (MiU32 i=0; i<mesh->mAnimationCount; i++) + { + print(fph,mesh->mAnimations[i]); + } + fi_fprintf(fph," </Animations>\r\n"); + } + + //******************************************************************* + //*** + //*** Output Materials + //*** + //******************************************************************* + if ( mesh->mMaterialCount ) + { + fi_fprintf(fph," <Materials count=\"%d\">\r\n", mesh->mMaterialCount ); + for (MiU32 i=0; i<mesh->mMaterialCount; i++) + { + print(fph,mesh->mMaterials[i]); + } + fi_fprintf(fph," </Materials>\r\n", mesh->mMaterialCount ); + } + + + //******************************************************************* + //*** + //*** Output UserData + //*** + //******************************************************************* + // user data + if ( mesh->mUserDataCount ) + { + fi_fprintf(fph," <UserData count=\"%d\">\r\n", mesh->mUserDataCount ); + for (MiU32 i=0; i<mesh->mUserDataCount; i++) + { + print(fph,mesh->mUserData[i]); + } + fi_fprintf(fph," </UserData>\r\n"); + } + + //******************************************************************* + //*** + //*** Output UserBinaryData + //*** + //******************************************************************* + // user data + if ( mesh->mUserBinaryDataCount ) + { + fi_fprintf(fph," <UserBinaryData count=\"%d\">\r\n", mesh->mUserBinaryDataCount ); + for (MiU32 i=0; i<mesh->mUserBinaryDataCount; i++) + { + print(fph,mesh->mUserBinaryData[i]); + } + fi_fprintf(fph," </UserBinaryData>\r\n"); + } + + + //******************************************************************* + //*** + //*** Output Meshes + //*** + //******************************************************************* + if ( mesh->mMeshCount ) + { + fi_fprintf(fph," <Meshes count=\"%d\">\r\n", mesh->mMeshCount ); + for (MiU32 i=0; i<mesh->mMeshCount; i++) + { + print(fph,mesh->mMeshes[i]); + } + fi_fprintf(fph," </Meshes>\r\n"); + } + + //******************************************************************* + //*** + //*** Output MeshInstances + //*** + //******************************************************************* + if ( mesh->mMeshInstanceCount ) + { + fi_fprintf(fph," <MeshInstances count=\"%d\">\r\n", mesh->mMeshInstanceCount ); + for (MiU32 i=0; i<mesh->mMeshInstanceCount; i++) + { + print(fph,mesh->mMeshInstances[i]); + } + fi_fprintf(fph," </MeshInstances>\r\n"); + } + + //******************************************************************* + //*** + //*** Output MeshCollisionRepresentations + //*** + //******************************************************************* + if ( mesh->mMeshCollisionCount ) + { + fi_fprintf(fph," <MeshCollisionRepresentations count=\"%d\">\r\n", mesh->mMeshCollisionCount ); + for (MiU32 i=0; i<mesh->mMeshCollisionCount; i++) + { + print(fph,mesh->mMeshCollisionRepresentations[i]); + } + fi_fprintf(fph," </MeshCollisionRepresentations>\r\n"); + } + + fi_fprintf(fph," </MeshSystem>\r\n"); + } + + // ok..ready to serialize in the Ogre format.. + void serializeOgre(FILE_INTERFACE *fph,FILE_INTERFACE *exfph,MeshSystem *mesh,const char *saveName) + { + // ogre wants all the vertices in one big buffer.. + VertexPool< MeshVertex > bigPool; + + MiU32 vertexFlags = 0; + for (MiU32 i=0; i<mesh->mMeshCount; i++) + { + Mesh *m = mesh->mMeshes[i]; + vertexFlags|=m->mVertexFlags; + for (MiU32 k=0; k<m->mVertexCount; k++) + { + const MeshVertex &v = m->mVertices[k]; + bigPool.GetVertex(v); + } + } + + fi_fprintf(fph,"<mesh>\r\n"); + fi_fprintf(fph," <sharedgeometry vertexcount=\"%d\">\r\n", bigPool.GetSize() ); + + fi_fprintf(fph," <vertexbuffer positions=\"%s\" normals=\"%s\">\r\n", (vertexFlags & MIVF_POSITION) ? "true" : "false", (vertexFlags & MIVF_NORMAL) ? "true" : "false" ); + MiI32 vcount = bigPool.GetSize(); + if ( vcount ) + { + MeshVertex *data = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + fi_fprintf(fph," <vertex>\r\n"); + fi_fprintf(fph," <position x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString(data->mPos[0]), FloatString(data->mPos[1]), FloatString(data->mPos[2]) ); + fi_fprintf(fph," <normal x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString(data->mNormal[0]), FloatString(data->mNormal[1]), FloatString(data->mNormal[2]) ); + fi_fprintf(fph," </vertex>\r\n"); + data++; + } + } + fi_fprintf(fph," </vertexbuffer>\r\n"); + + if ( vertexFlags & MIVF_COLOR ) + { + fi_fprintf(fph," <vertexbuffer colours_diffuse=\"true\">\r\n"); + MiI32 vcount = bigPool.GetSize(); + MeshVertex *data = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + fi_fprintf(fph," <vertex>\r\n"); + + MiU32 a = data->mColor>>24; + MiU32 r = (data->mColor>>16)&0xFF; + MiU32 g = (data->mColor>>8)&0xFF; + MiU32 b = (data->mColor&0xFF); + MiF32 fa = (MiF32)a*(1.0f/255.0f); + MiF32 fr = (MiF32)r*(1.0f/255.0f); + MiF32 fg = (MiF32)g*(1.0f/255.0f); + MiF32 fb = (MiF32)b*(1.0f/255.0f); + fi_fprintf(fph," <colour_diffuse value=\"%s %s %s %s\" />\r\n", + FloatString(fa), + FloatString(fr), + FloatString(fg), + FloatString(fb) ); + + fi_fprintf(fph," </vertex>\r\n"); + data++; + } + fi_fprintf(fph," </vertexbuffer>\r\n"); + } + + if ( vertexFlags & MIVF_TEXEL1 ) + { + + fi_fprintf(fph," <vertexbuffer texture_coord_dimensions_0=\"2\" texture_coords=\"1\">\r\n"); + MiI32 vcount = bigPool.GetSize(); + MeshVertex *data = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + fi_fprintf(fph," <vertex>\r\n"); + fi_fprintf(fph," <texcoord u=\"%s\" v=\"%s\" />\r\n", FloatString(data->mTexel1[0]), FloatString(data->mTexel1[1]) ); + fi_fprintf(fph," </vertex>\r\n"); + data++; + } + fi_fprintf(fph," </vertexbuffer>\r\n"); + } + + fi_fprintf(fph," </sharedgeometry>\r\n"); + fi_fprintf(fph," <submeshes>\r\n"); + + for (MiU32 i=0; i<mesh->mMeshCount; i++) + { + Mesh *m = mesh->mMeshes[i]; + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + fi_fprintf(fph," <submesh material=\"%s\" usesharedvertices=\"true\" operationtype=\"triangle_list\">\r\n", sm->mMaterialName ); + fi_fprintf(fph," <faces count=\"%d\">\r\n", sm->mTriCount ); + for (MiU32 k=0; k<sm->mTriCount; k++) + { + MiU32 i1 = sm->mIndices[k*3+0]; + MiU32 i2 = sm->mIndices[k*3+1]; + MiU32 i3 = sm->mIndices[k*3+2]; + const MeshVertex &v1 = m->mVertices[i1]; + const MeshVertex &v2 = m->mVertices[i2]; + const MeshVertex &v3 = m->mVertices[i3]; + i1 = (MiU32)bigPool.GetVertex(v1); + i2 = (MiU32)bigPool.GetVertex(v2); + i3 = (MiU32)bigPool.GetVertex(v3); + fi_fprintf(fph," <face v1=\"%d\" v2=\"%d\" v3=\"%d\" />\r\n", i1, i2, i3 ); + } + fi_fprintf(fph," </faces>\r\n"); + fi_fprintf(fph," <boneassignments />\r\n"); + fi_fprintf(fph," </submesh>\r\n"); + } + } + fi_fprintf(fph," </submeshes>\r\n"); + if ( mesh->mSkeletonCount ) + { + MeshSkeleton *sk = mesh->mSkeletons[0]; + if ( saveName ) + { + const char *slash = lastSlash(saveName); + if ( slash == 0 ) + slash = saveName; + else + slash++; + + char scratch[512]; + MESH_IMPORT_STRING::snprintf(scratch,512,slash); + char *dot = stristr(scratch,".mesh.xml"); + if ( dot ) + { + *dot = 0; + } + + fi_fprintf(fph," <skeletonlink name=\"%s.skeleton\" />\r\n", scratch ); + } + else + fi_fprintf(fph," <skeletonlink name=\"%s\" />\r\n", sk->mName ); + } + + if ( vertexFlags & MIVF_BONE_WEIGHTING ) + { + fi_fprintf(fph," <boneassignments>\r\n"); + MiI32 vcount = bigPool.GetSize(); + MeshVertex *data = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + for (MiI32 j=0; j<4; j++) + { + if ( data->mWeight[j] == 0 ) break; + fi_fprintf(fph," <vertexboneassignment vertexindex=\"%d\" boneindex=\"%d\" weight=\"%s\" />\r\n", i, data->mBone[j], FloatString(data->mWeight[j] ) ); + } + data++; + } + fi_fprintf(fph," </boneassignments>\r\n"); + } + fi_fprintf(fph,"</mesh>\r\n"); + + // ok..now if we have a skeleton.. + fi_fprintf(exfph,"<skeleton>\r\n"); + if ( mesh->mSkeletonCount ) + { + MeshSkeleton *skeleton = mesh->mSkeletons[0]; // only serialize one skeleton! + fi_fprintf(exfph," <bones>\r\n"); + for (MiI32 i=0; i<skeleton->mBoneCount; i++) + { + MeshBone &b = skeleton->mBones[i]; + fi_fprintf(exfph," <bone id=\"%d\" name=\"%s\">\r\n", i, b.mName ); + fi_fprintf(exfph," <position x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString( b.mPosition[0] ), FloatString( b.mPosition[1] ), FloatString( b.mPosition[2] ) ); + MiF32 angle = 0; + MiF32 axis[3] = { 0, 0, 0 }; + b.getAngleAxis(angle,axis); + fi_fprintf(exfph," <rotation angle=\"%s\">\r\n", FloatString(angle) ); + fi_fprintf(exfph," <axis x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString( axis[0] ), FloatString( axis[1] ), FloatString( axis[2] ) ); + fi_fprintf(exfph," </rotation>\r\n"); + fi_fprintf(exfph," <scale x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString( b.mScale[0] ), FloatString( b.mScale[1] ), FloatString( b.mScale[2] ) ); + fi_fprintf(exfph," </bone>\r\n"); + } + fi_fprintf(exfph," </bones>\r\n"); + fi_fprintf(exfph," <bonehierarchy>\r\n"); + for (MiI32 i=0; i<skeleton->mBoneCount; i++) + { + MeshBone &b = skeleton->mBones[i]; + if ( b.mParentIndex != -1 ) + { + MeshBone &p = skeleton->mBones[b.mParentIndex]; + fi_fprintf(exfph," <boneparent bone=\"%s\" parent=\"%s\" />\r\n", b.mName, p.mName ); + } + } + fi_fprintf(exfph," </bonehierarchy>\r\n"); + } + if ( mesh->mAnimationCount ) + { + fi_fprintf(exfph," <animations>\r\n"); + + for (MiI32 i=0; i<(MiI32)mesh->mAnimationCount; i++) + { + MeshAnimation *anim = mesh->mAnimations[i]; // only serialize one animation + fi_fprintf(exfph," <animation name=\"%s\" length=\"%d\">\r\n", anim->mName, anim->mFrameCount ); + fi_fprintf(exfph," <tracks>\r\n"); + for (MiI32 j=0; j<anim->mTrackCount; j++) + { + MeshAnimTrack *track = anim->mTracks[j]; + + fi_fprintf(exfph," <track bone=\"%s\">\r\n", track->mName ); + fi_fprintf(exfph," <keyframes>\r\n"); + + MiF32 tm = 0; + + MiF32 base_inverse[16]; + fmi_identity(base_inverse); + if ( mesh->mSkeletonCount ) + { + MeshSkeleton *sk = mesh->mSkeletons[i]; + for (MiI32 i=0; i<sk->mBoneCount; i++) + { + MeshBone &b = sk->mBones[i]; + if ( strcmp(b.mName,track->mName) == 0 ) + { + // ok..compose the local space transform.. + MiF32 local_matrix[16]; + fmi_composeTransform( b.mPosition, b.mOrientation, b.mScale, local_matrix ); + fmi_inverseTransform(local_matrix,base_inverse); + } + } + } + + + for (MiI32 k=0; k<track->mFrameCount; k++) + { + MeshAnimPose &p = track->mPose[k]; + + MiF32 local_matrix[16]; + fmi_composeTransform(p.mPos,p.mQuat,p.mScale,local_matrix); + fmi_multiply(local_matrix,base_inverse,local_matrix); + + MiF32 trans[3] = { 0, 0, 0 }; + MiF32 scale[3] = { 0, 0, 0 }; + MiF32 rot[4]; + + fmi_decomposeTransform(local_matrix,trans,rot,scale); + + MiF32 angle = 0; + MiF32 axis[3] = { 0, 0, 0 }; + + fmi_getAngleAxis(angle,axis,rot); + + fi_fprintf(exfph," <keyframe time=\"%s\">\r\n", FloatString(tm) ); + fi_fprintf(exfph," <translate x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString(trans[0]), FloatString(trans[1]), FloatString(trans[2]) ); + fi_fprintf(exfph," <rotate angle=\"%s\">\r\n", FloatString(angle) ); + fi_fprintf(exfph," <axis x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString(axis[0]), FloatString(axis[1]), FloatString(axis[2]) ); + fi_fprintf(exfph," </rotate>\r\n"); + fi_fprintf(exfph," <scale x=\"%s\" y=\"%s\" z=\"%s\" />\r\n", FloatString( scale[0] ), FloatString(scale[1]), FloatString(scale[2]) ); + fi_fprintf(exfph," </keyframe>\r\n"); + + tm+=track->mDtime; + } + fi_fprintf(exfph," </keyframes>\r\n"); + fi_fprintf(exfph," </track>\r\n"); + } + fi_fprintf(exfph," </tracks>\r\n"); + fi_fprintf(exfph," </animation>\r\n"); + } + + fi_fprintf(exfph," </animations>\r\n"); + } + fi_fprintf(exfph,"</skeleton>\r\n"); + } + + typedef STDNAME::vector< MiU32 > U32Vector; + + class Msave + { + public: + const char *mMaterialName; + U32Vector mIndices; + }; + + typedef STDNAME::vector< Msave > MsaveVector; + + void serializeWavefront(FILE_INTERFACE *fph,FILE_INTERFACE *exfph,MeshSystem *mesh,const char *saveName,const MiF32 *exportTransform) + { + fi_fprintf(fph,"# Asset '%s'\r\n", mesh->mAssetName ); + char scratch[512]; + MESH_IMPORT_STRING::snprintf(scratch,512,saveName); + char *dot = (char *)lastDot(scratch); + if ( dot ) + { + *dot = 0; + } + MESH_IMPORT_STRING::strlcat(scratch,512,".mtl"); + fi_fprintf(fph,"mtllib %s\r\n", scratch ); + + for (MiU32 i=0; i<mesh->mMaterialCount; i++) + { + const MeshMaterial &m = mesh->mMaterials[i]; + fi_fprintf(exfph,"newmtl %s\r\n", m.mName ); + char scratch[512]; + strncpy(scratch,m.mName,512); + char *plus = strstr(scratch,"+"); + if ( plus ) + *plus = 0; + const char *diffuse = scratch; + fi_fprintf(exfph,"Ps 30.0000\r\n"); + fi_fprintf(exfph," Ni 1.5000\r\n"); + fi_fprintf(exfph," d 1.0000\r\n"); + fi_fprintf(exfph," Tr 0.0000\r\n"); + fi_fprintf(exfph," Tf 1.0000 1.0000 1.0000\r\n"); + fi_fprintf(exfph," illum 2\r\n"); + fi_fprintf(exfph," Ka 0.5500 0.5500 0.5500\r\n"); + fi_fprintf(exfph," Kd 0.5500 0.5500 0.5500\r\n"); + fi_fprintf(exfph," Ks 0.0000 0.0000 0.0000\r\n"); + fi_fprintf(exfph," Ke 0.0000 0.0000 0.0000\r\n"); + fi_fprintf(exfph," map_Ka %s\r\n", diffuse); + fi_fprintf(exfph," map_Kd %s\r\n", diffuse); + + + } + + if ( mesh->mMeshInstanceCount ) + { + + MsaveVector meshes; + VertexPool< MeshVertex > bigPool; + + for (MiU32 i=0; i<mesh->mMeshInstanceCount; i++) + { + MeshInstance &inst = mesh->mMeshInstances[i]; + for (MiU32 j=0; j<mesh->mMeshCount; j++) + { + Mesh *m = mesh->mMeshes[j]; + if ( strcmp(m->mName,inst.mMeshName) == 0 ) + { + MiF32 matrix[16]; + fmi_composeTransform(inst.mPosition,inst.mRotation,inst.mScale,matrix); + MiF32 rotate[16]; + fmi_quatToMatrix(inst.mRotation,rotate); + + bool compute_normal = false; + + for (MiU32 k=0; k<m->mSubMeshCount; k++) + { + SubMesh *sm = m->mSubMeshes[k]; + Msave ms; + ms.mMaterialName = sm->mMaterialName; + for (MiU32 l=0; l<sm->mTriCount; l++) + { + MiU32 i1 = sm->mIndices[l*3+0]; + MiU32 i2 = sm->mIndices[l*3+1]; + MiU32 i3 = sm->mIndices[l*3+2]; + + MeshVertex v1 = m->mVertices[i1]; + MeshVertex v2 = m->mVertices[i2]; + MeshVertex v3 = m->mVertices[i3]; + + fmi_transform(matrix,v1.mPos,v1.mPos); + fmi_transform(matrix,v2.mPos,v2.mPos); + fmi_transform(matrix,v3.mPos,v3.mPos); + fmi_transform(exportTransform,v1.mPos,v1.mPos); + fmi_transform(exportTransform,v2.mPos,v2.mPos); + fmi_transform(exportTransform,v3.mPos,v3.mPos); + + if ( l == 0 ) + { + if ( v1.mRadius == 1 || v2.mRadius == 1 || v3.mRadius == 1 ) + { + compute_normal = true; + } + if ( v1.mNormal[0] == 0 && v1.mNormal[1] == 0 && v1.mNormal[2] == 0 ) compute_normal = true; + } + + if ( compute_normal ) + { + + v1.mRadius = 1; + v2.mRadius = 1; + v3.mRadius = 1; + + MiF32 n[3]; + fmi_computePlane(v3.mPos,v2.mPos,v1.mPos,n); + + v1.mNormal[0]+=n[0]; + v1.mNormal[1]+=n[1]; + v1.mNormal[2]+=n[2]; + + v2.mNormal[0]+=n[0]; + v2.mNormal[1]+=n[1]; + v2.mNormal[2]+=n[2]; + + v3.mNormal[0]+=n[0]; + v3.mNormal[1]+=n[1]; + v3.mNormal[2]+=n[2]; + + } + else + { + + fmi_transform(rotate,v1.mNormal,v1.mNormal); + fmi_transform(rotate,v2.mNormal,v2.mNormal); + fmi_transform(rotate,v3.mNormal,v3.mNormal); + + fmi_transformRotate(exportTransform,v1.mNormal,v1.mNormal); + fmi_transformRotate(exportTransform,v2.mNormal,v2.mNormal); + fmi_transformRotate(exportTransform,v3.mNormal,v3.mNormal); + + } + + i1 = (MiU32)bigPool.GetVertex(v1)+1; + i2 = (MiU32)bigPool.GetVertex(v2)+1; + i3 = (MiU32)bigPool.GetVertex(v3)+1; + + ms.mIndices.push_back(i1); + ms.mIndices.push_back(i2); + ms.mIndices.push_back(i3); + + } + meshes.push_back(ms); + } + break; + } + } + } + + MiI32 vcount = bigPool.GetVertexCount(); + + if ( vcount ) + { + MeshVertex *vb = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + const MeshVertex &v = vb[i]; + fi_fprintf(fph,"v %s %s %s\r\n", FloatString(v.mPos[0]), FloatString(v.mPos[1]), FloatString(v.mPos[2])); + } + for (MiI32 i=0; i<vcount; i++) + { + const MeshVertex &v = vb[i]; + fi_fprintf(fph,"vt %s %s\r\n", FloatString(v.mTexel1[0]), FloatString(v.mTexel1[1])); + } + for (MiI32 i=0; i<vcount; i++) + { + MeshVertex &v = vb[i]; + fmi_normalize(v.mNormal); + fi_fprintf(fph,"vn %s %s %s\r\n", FloatString(v.mNormal[0]), FloatString(v.mNormal[1]), FloatString(v.mNormal[2])); + } + MsaveVector::iterator i; + for (i=meshes.begin(); i!=meshes.end(); ++i) + { + Msave &ms = (*i); + fi_fprintf(fph,"usemtl %s\r\n", ms.mMaterialName ); + MiU32 tcount = (MiU32)ms.mIndices.size()/3; + MiU32 *indices = &ms.mIndices[0]; + for (MiU32 k=0; k<tcount; k++) + { + MiU32 i1 = indices[k*3+0]; + MiU32 i2 = indices[k*3+1]; + MiU32 i3 = indices[k*3+2]; + fi_fprintf(fph,"f %d/%d/%d %d/%d/%d %d/%d/%d\r\n", i1, i1, i1, i2, i2, i2, i3, i3, i3 ); + } + } + } + } + else + { + MsaveVector meshes; + VertexPool< MeshVertex > bigPool; + + for (MiU32 j=0; j<mesh->mMeshCount; j++) + { + Mesh *mm = mesh->mMeshes[j]; + bool compute_normal = false; + for (MiU32 k=0; k<mm->mSubMeshCount; k++) + { + SubMesh *sm = mm->mSubMeshes[k]; + Msave ms; + ms.mMaterialName = sm->mMaterialName; + for (MiU32 l=0; l<sm->mTriCount; l++) + { + MiU32 i1 = sm->mIndices[l*3+0]; + MiU32 i2 = sm->mIndices[l*3+1]; + MiU32 i3 = sm->mIndices[l*3+2]; + + MeshVertex v1 = mm->mVertices[i1]; + MeshVertex v2 = mm->mVertices[i2]; + MeshVertex v3 = mm->mVertices[i3]; + + fmi_transform(exportTransform,v1.mPos,v1.mPos); + fmi_transform(exportTransform,v2.mPos,v2.mPos); + fmi_transform(exportTransform,v3.mPos,v3.mPos); + + if ( l == 0 ) + { + if ( v1.mRadius == 1 || v2.mRadius == 1 || v3.mRadius == 1 ) + { + compute_normal = true; + } + if ( v1.mNormal[0] == 0 && v1.mNormal[1] == 0 && v1.mNormal[2] == 0 ) compute_normal = true; + } + + if ( compute_normal ) + { + + v1.mRadius = 1; + v2.mRadius = 1; + v3.mRadius = 1; + + MiF32 n[3]; + fmi_computePlane(v3.mPos,v2.mPos,v1.mPos,n); + + v1.mNormal[0]+=n[0]; + v1.mNormal[1]+=n[1]; + v1.mNormal[2]+=n[2]; + + v2.mNormal[0]+=n[0]; + v2.mNormal[1]+=n[1]; + v2.mNormal[2]+=n[2]; + + v3.mNormal[0]+=n[0]; + v3.mNormal[1]+=n[1]; + v3.mNormal[2]+=n[2]; + + } + else + { + fmi_transformRotate(exportTransform,v1.mNormal,v1.mNormal); + fmi_transformRotate(exportTransform,v2.mNormal,v2.mNormal); + fmi_transformRotate(exportTransform,v3.mNormal,v3.mNormal); + } + + i1 = (MiU32)bigPool.GetVertex(v1)+1; + i2 = (MiU32)bigPool.GetVertex(v2)+1; + i3 = (MiU32)bigPool.GetVertex(v3)+1; + + ms.mIndices.push_back(i1); + ms.mIndices.push_back(i2); + ms.mIndices.push_back(i3); + + } + meshes.push_back(ms); + } + } + MiI32 vcount = bigPool.GetVertexCount(); + + if ( vcount ) + { + MeshVertex *vb = bigPool.GetBuffer(); + for (MiI32 i=0; i<vcount; i++) + { + const MeshVertex &v = vb[i]; + fi_fprintf(fph,"v %s %s %s\r\n", FloatString(v.mPos[0]), FloatString(v.mPos[1]), FloatString(v.mPos[2])); + } + for (MiI32 i=0; i<vcount; i++) + { + const MeshVertex &v = vb[i]; + fi_fprintf(fph,"vt %s %s\r\n", FloatString(v.mTexel1[0]), FloatString(v.mTexel1[1])); + } + for (MiI32 i=0; i<vcount; i++) + { + MeshVertex &v = vb[i]; + fmi_normalize(v.mNormal); + fi_fprintf(fph,"vn %s %s %s\r\n", FloatString(v.mNormal[0]), FloatString(v.mNormal[1]), FloatString(v.mNormal[2])); + } + MsaveVector::iterator i; + for (i=meshes.begin(); i!=meshes.end(); ++i) + { + Msave &ms = (*i); + fi_fprintf(fph,"usemtl %s\r\n", ms.mMaterialName ); + MiU32 tcount = (MiU32)ms.mIndices.size()/3; + MiU32 *indices = &ms.mIndices[0]; + for (MiU32 k=0; k<tcount; k++) + { + MiU32 i1 = indices[k*3+0]; + MiU32 i2 = indices[k*3+1]; + MiU32 i3 = indices[k*3+2]; + fi_fprintf(fph,"f %d/%d/%d %d/%d/%d %d/%d/%d\r\n", i1, i1, i1, i2, i2, i2, i3, i3, i3 ); + } + } + } + } + } + + virtual bool serializeMeshSystem(MeshSystem *mesh,MeshSerialize &data) + { + bool ret = false; + + if ( data.mFormat == MSF_EZB ) + { + data.mBaseData = (mimp::MiU8 *)serializeEZB(mesh,data.mBaseLen); + if ( data.mBaseData ) + { + ret = true; + } + } + else if ( data.mFormat == MSF_DYNAMIC_SYSTEM ) + { + data.mBaseData = (mimp::MiU8 *)serializeDynamicSystem(mesh,data.mBaseLen); + if ( data.mBaseData ) + { + data.mExtendedData = (mimp::MiU8 *)serializeDynamicSystemAuthoring(mesh,data.mExtendedLen); + ret = true; + } + } + else if ( data.mFormat == MSF_APX ) + { + data.mBaseData = (mimp::MiU8 *)serializeAPX(mesh,data.mBaseLen); + if ( data.mBaseData ) + { + ret = true; + } + } + else if ( data.mFormat == MSF_POVRAY ) + { + data.mBaseData = (mimp::MiU8 *)serializePOVRay(mesh,data.mBaseLen); + if ( data.mBaseData ) + { + ret = true; + } + } + else + { + + FILE_INTERFACE *fph = fi_fopen("foo", "wmem", 0, 0); + + if ( fph ) + { + if ( data.mFormat == MSF_OGRE3D ) + { + FILE_INTERFACE *exfph = fi_fopen("foo", "wmem", 0, 0); + serializeOgre(fph,exfph,mesh,data.mSaveFileName); + size_t olen; + void *temp = fi_getMemBuffer(exfph,&olen); + if ( temp ) + { + data.mExtendedData = (MiU8 *)MI_ALLOC(olen+1); + memcpy(data.mExtendedData,temp,olen); + data.mExtendedData[olen] = 0; + data.mExtendedLen = (MiU32)olen; + } + fi_fclose(exfph); + } + else if ( data.mFormat == MSF_EZMESH ) + { + serializeEzm(fph,mesh); + } + else if ( data.mFormat == MSF_FBX ) + { + serializeFBX(fph,mesh); + } + else if ( data.mFormat == MSF_PSK ) + { + FILE_INTERFACE *exfph = fi_fopen("foo", "wmem", 0, 0); + serializePSK(fph,mesh,exfph); + size_t olen; + void *temp = fi_getMemBuffer(exfph,&olen); + if ( temp ) + { + data.mExtendedData = (MiU8 *)MI_ALLOC(olen+1); + memcpy(data.mExtendedData,temp,olen); + data.mExtendedData[olen] = 0; + data.mExtendedLen = (MiU32)olen; + } + fi_fclose(exfph); + } + else if ( data.mFormat == MSF_WAVEFRONT ) + { + FILE_INTERFACE *exfph = fi_fopen("foo2", "wmem", 0, 0); + serializeWavefront(fph,exfph,mesh,data.mSaveFileName,data.mExportTransform); + size_t olen; + void *temp = fi_getMemBuffer(exfph,&olen); + if ( temp ) + { + data.mExtendedData = (MiU8 *)MI_ALLOC(olen+1); + memcpy(data.mExtendedData,temp,olen); + data.mExtendedData[olen] = 0; + data.mExtendedLen = (MiU32)olen; + } + fi_fclose(exfph); + } + size_t olen; + void *temp = fi_getMemBuffer(fph,&olen); + if ( temp ) + { + data.mBaseData = (MiU8 *)MI_ALLOC(olen+1); + memcpy(data.mBaseData,temp,olen); + data.mBaseData[olen] = 0; + data.mBaseLen = (MiU32)olen; + ret = true; + } + fi_fclose(fph); + } + } + + return ret; + } + + virtual void releaseSerializeMemory(MeshSerialize &data) + { + MI_FREE(data.mBaseData); + MI_FREE(data.mExtendedData); + data.mBaseData = 0; + data.mBaseLen = 0; + data.mExtendedData = 0; + data.mExtendedLen = 0; + } + + + virtual const char * getFileRequestDialogString(void) + { + typedef STDNAME::vector< std::string > StringVector; + StringVector descriptions; + StringVector extensions; + + MiU32 count = (MiU32)getImporterCount(); + for (unsigned i=0; i<count; i++) + { + mimp::MeshImporter *imp = getImporter((MiI32)i); + MiU32 ecount = (MiU32)imp->getExtensionCount(); + for (MiU32 j=0; j<ecount; j++) + { + const char *description = imp->getDescription((MiI32)j); + const char *itype = imp->getExtension((MiI32)j); + std::string desc = description; + std::string ext = itype; + descriptions.push_back(desc); + extensions.push_back(ext); + } + } + mFileRequest.clear(); + mFileRequest+="All ("; + count = (MiU32)descriptions.size(); + for (MiU32 i=0; i<count; i++) + { + mFileRequest+="*"; + mFileRequest+=extensions[i]; + if ( i != (count-1) ) + mFileRequest+=";"; + } + mFileRequest+=")|"; + for (MiU32 i=0; i<count; i++) + { + mFileRequest+="*"; + mFileRequest+=extensions[i]; + if ( i != (count-1) ) + mFileRequest+=";"; + } + mFileRequest+="|"; + for (MiU32 i=0; i<count; i++) + { + mFileRequest+=descriptions[i]; + mFileRequest+=" (*"; + mFileRequest+=extensions[i]; + mFileRequest+=")"; + mFileRequest+="|*"; + mFileRequest+=extensions[i]; + if ( i != (count-1) ) + mFileRequest+="|"; + } + return mFileRequest.c_str(); + } + + virtual void setMeshImportApplicationResource(MeshImportApplicationResource *resource) + { + mApplicationResource = resource; + } + + virtual MeshSkeletonInstance *createMeshSkeletonInstance(const MeshSkeleton &sk) + { + MeshSkeletonInstance *ret = 0; + + if ( sk.mBoneCount ) + { + ret = new MeshSkeletonInstance; + ret->mName = sk.mName; + ret->mBoneCount = sk.mBoneCount; + ret->mBones = new MeshBoneInstance[(MiU32)sk.mBoneCount]; + for (MiI32 i=0; i<ret->mBoneCount; i++) + { + const MeshBone &src = sk.mBones[i]; + MeshBoneInstance &dst = ret->mBones[i]; + dst.mBoneName = src.mName; + dst.mParentIndex = src.mParentIndex; + fmi_composeTransform(src.mPosition,src.mOrientation,src.mScale,dst.mLocalTransform); + if ( src.mParentIndex != -1 ) + { + MeshBoneInstance &parent = ret->mBones[src.mParentIndex]; + fmi_multiply(dst.mLocalTransform,parent.mTransform,dst.mTransform); // multiply times the parent matrix. + } + else + { + memcpy(dst.mTransform,dst.mLocalTransform,sizeof(MiF32)*16); + } + dst.composeInverse(); // compose the inverse transform. + } + } + return ret; + } + + virtual void releaseMeshSkeletonInstance(MeshSkeletonInstance *sk) + { + if ( sk ) + { + delete []sk->mBones; + delete sk; + } + } + + virtual bool sampleAnimationTrack(MiI32 trackIndex,const MeshSystem *msystem,MeshSkeletonInstance *skeleton) + { + bool ret = false; + + if ( msystem && skeleton && msystem->mAnimationCount ) + { + MeshAnimation *anim = msystem->mAnimations[0]; // got the animation. + for (MiI32 i=0; i<skeleton->mBoneCount; i++) + { + MeshBoneInstance &b = skeleton->mBones[i]; + // ok..look for this track in the animation... + MiF32 transform[16]; + + MeshAnimTrack *track = 0; + for (MiI32 j=0; j<anim->mTrackCount; j++) + { + MeshAnimTrack *t = anim->mTracks[j]; + if ( strcmp(t->mName,b.mBoneName) == 0 ) // if the names match + { + track = t; + break; + } + } + if ( track && track->mFrameCount ) + { + MiI32 tindex = trackIndex% track->mFrameCount; + MeshAnimPose &p = track->mPose[tindex]; + fmi_composeTransform(p.mPos,p.mQuat,p.mScale,transform); + } + else + { + memcpy(transform,b.mLocalTransform,sizeof(MiF32)*16); + } + if ( b.mParentIndex != -1 ) + { + MeshBoneInstance &parent = skeleton->mBones[b.mParentIndex]; + fmi_multiply(transform,parent.mAnimTransform,b.mAnimTransform); // multiply times the parent matrix. + } + else + { + memcpy(b.mAnimTransform,transform,sizeof(MiF32)*16); +// fmi_identity(b.mAnimTransform); + } + fmi_multiply(b.mInverseTransform,b.mAnimTransform,b.mCompositeAnimTransform); + } + ret = true; + } + + return ret; + } + + void transformPoint(const MiF32 v[3],MiF32 t[3],const MiF32 matrix[16]) + { + MiF32 tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0]; + MiF32 ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1]; + MiF32 tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2]; + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + + void rotatePoint(const MiF32 v[3],MiF32 t[3],const MiF32 matrix[16]) + { + MiF32 tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]); + MiF32 ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]); + MiF32 tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]); + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + + + void transformVertex(const MeshVertex &src,MeshVertex &dst,MeshSkeletonInstance *skeleton) + { + MiI32 bone = src.mBone[0]; + MiF32 weight = src.mWeight[0]; + assert (bone >= 0 && bone < skeleton->mBoneCount ); + memcpy(&dst,&src,sizeof(MeshVertex)); + if ( weight > 0 && bone >= 0 && bone < skeleton->mBoneCount ) + { + { + MiF32 result[3]; + dst.mPos[0] = 0; + dst.mPos[1] = 0; + dst.mPos[2] = 0; + for (MiI32 i=0; i<4; i++) + { + bone = src.mBone[i]; + weight = src.mWeight[i]; + if ( weight == 0 ) + break; + transformPoint(src.mPos,result,skeleton->mBones[bone].mCompositeAnimTransform); + dst.mPos[0]+=result[0]*weight; + dst.mPos[1]+=result[1]*weight; + dst.mPos[2]+=result[2]*weight; + } + } +#if 0 + { + MiF32 result[3]; + dst.mNormal[0] = 0; + dst.mNormal[1] = 0; + dst.mNormal[2] = 0; + for (MiI32 i=0; i<4; i++) + { + bone = src.mBone[i]; + weight = src.mWeight[i]; + if ( weight == 0 ) + break; + rotatePoint(src.mPos,result,skeleton->mBones[bone].mCompositeAnimTransform); + dst.mNormal[0]+=result[0]*weight; + dst.mNormal[1]+=result[1]*weight; + dst.mNormal[2]+=result[2]*weight; + } + } +#endif + } + } + + virtual void transformVertices(MiU32 vcount, + const MeshVertex *source_vertices, + MeshVertex *dest_vertices, + MeshSkeletonInstance *skeleton) + { + for (MiU32 i=0; i<vcount; i++) + { + transformVertex(*source_vertices,*dest_vertices,skeleton); + source_vertices++; + dest_vertices++; + } + } + + virtual void rotate(MeshSystemContainer *msc,MiF32 rotX,MiF32 rotY,MiF32 rotZ) // rotate mesh system using these euler angles expressed as degrees. + { + MeshBuilder *b = (MeshBuilder *)msc; + if ( b ) + { + b->rotate(rotX,rotY,rotZ); + } + } + + virtual void scale(MeshSystemContainer *msc,MiF32 s) + { + MeshBuilder *b = (MeshBuilder *)msc; + if ( b ) + { + b->scale(s); + } + } + + virtual MeshImportInterface * getMeshImportInterface(MeshSystemContainer *msc) + { + MeshImportInterface *ret = 0; + + if ( msc ) + { + MeshBuilder *b = (MeshBuilder *)msc; + b->setMeshImportBinary(false); + ret = static_cast< MeshImportInterface * >(b); + } + return ret; + } + + virtual void gather(MeshSystemContainer *msc) + { + if ( msc ) + { + MeshBuilder *b = (MeshBuilder *)msc; + b->gather(); + } + } + +private: + std::string mCtype; + std::string mSemantic; + std::string mFileRequest; + MeshImporterVector mImporters; + MeshImportApplicationResource *mApplicationResource; +}; + +}; // End of Namespace + + + +static mimp::MyMeshImport *gInterface=0; + +namespace mimp +{ + +extern "C" +{ +#ifdef PLUGINS_EMBEDDED + MeshImport * getInterfaceMeshImport(MiI32 version_number) +#else + MESHIMPORT_API MeshImport * getInterface(MiI32 version_number) +#endif +{ + if ( gInterface == 0 && version_number == MESHIMPORT_VERSION ) + { + gInterface = MI_NEW(MyMeshImport)(); + } + return static_cast<MeshImport *>(gInterface); +}; + +}; +}; // end of mimp namespace + +#ifndef PLUGINS_EMBEDDED + + +#ifdef WIN32 + +#include <windows.h> + +BOOL APIENTRY DllMain( HANDLE , + DWORD ul_reason_for_call, + LPVOID ) +{ + mimp::MiI32 ret = 0; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + ret = 1; + break; + case DLL_THREAD_ATTACH: + ret = 2; + break; + case DLL_THREAD_DETACH: + ret = 3; + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +#endif + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.cpp new file mode 100644 index 00000000..c417966f --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.cpp @@ -0,0 +1,1533 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#pragma warning(disable:4555) +#include "MeshImportBuilder.h" +#include "VtxWeld.h" +#include "MiStringDictionary.h" +#include "MiFloatMath.h" +#include "MiMemoryBuffer.h" +#include "MiIOStream.h" +#include "ExportEZB.h" + +#pragma warning(disable:4100 4189) + +namespace mimp +{ + +typedef STDNAME::vector< MeshVertex > MeshVertexVector; +typedef STDNAME::vector< MiU32 > MeshIndexVector; +typedef STDNAME::vector< SubMesh * > SubMeshVector; +typedef STDNAME::vector< Mesh * > MeshVector; +typedef STDNAME::vector< MeshAnimation * > MeshAnimationVector; +typedef STDNAME::vector< MeshSkeleton * > MeshSkeletonVector; +typedef STDNAME::vector< MeshRawTexture *> MeshRawTextureVector; +typedef STDNAME::vector< MeshTetra * > MeshTetraVector; +typedef STDNAME::vector< MeshUserData *> MeshUserDataVector; +typedef STDNAME::vector< MeshUserBinaryData * > MeshUserBinaryDataVector; +typedef STDNAME::vector< MeshPairCollision > MeshPairCollisionVector; + +static MiI32 gSerializeFrame=1; + +class MyMesh; + +class MySubMesh : public SubMesh +{ +public: + MySubMesh(const char *mat,MiU32 vertexFlags) + { + mMaterialName = mat; + mVertexFlags = (MeshVertexFlag)vertexFlags; + } + + ~MySubMesh(void) + { + } + + bool isSame(const char *mat,MiU32 vertexFlags) const + { + bool ret = false; + assert(mat); + assert(mMaterialName); + if ( strcmp(mat,mMaterialName) == 0 && mVertexFlags == vertexFlags ) ret = true; + return ret; + } + + void gather(void) + { + mTriCount = (MiU32)mMyIndices.size()/3; + mIndices = &mMyIndices[0]; + } + + void add(const MeshVertex &v1,const MeshVertex &v2,const MeshVertex &v3,VertexPool< MeshVertex > &vpool) + { + mAABB.include(v1.mPos); + mAABB.include(v2.mPos); + mAABB.include(v3.mPos); + + MiU32 i1 = (MiU32)vpool.GetVertex(v1); + MiU32 i2 = (MiU32)vpool.GetVertex(v2); + MiU32 i3 = (MiU32)vpool.GetVertex(v3); + + mMyIndices.push_back(i1); + mMyIndices.push_back(i2); + mMyIndices.push_back(i3); + } + + MeshIndexVector mMyIndices; + VertexPool< MeshVertex > mVertexPool; +}; + +class MyMesh : public Mesh +{ +public: + MyMesh(const char *meshName,const char *skeletonName) + { + mName = meshName; + mSkeletonName = skeletonName; + mCurrent = 0; + } + + virtual ~MyMesh(void) + { + release(); + } + + void release(void) + { + mSubMeshes = 0; + mSubMeshCount = 0; + SubMeshVector::iterator i; + for (i=mMySubMeshes.begin(); i!=mMySubMeshes.end(); ++i) + { + MySubMesh *s = static_cast<MySubMesh *>((*i)); + delete(s); + } + mMySubMeshes.clear(); + } + + bool isSame(const char *meshName) const + { + bool ret = false; + assert(meshName); + assert(mName); + if ( strcmp(mName,meshName) == 0 ) ret = true; + return ret; + } + + void getCurrent(const char *materialName,MiU32 vertexFlags) + { + if ( materialName == 0 ) materialName = "default_material"; + if ( mCurrent == 0 || !mCurrent->isSame(materialName,vertexFlags) ) + { + mCurrent =0; + SubMeshVector::iterator i; + for (i=mMySubMeshes.begin(); i!=mMySubMeshes.end(); ++i) + { + MySubMesh *s = static_cast< MySubMesh *>((*i)); + if ( s->isSame(materialName,vertexFlags) ) + { + mCurrent = s; + break; + } + } + if ( mCurrent == 0 ) + { + mCurrent = (MySubMesh *)MI_ALLOC(sizeof(MySubMesh)); + new (mCurrent ) MySubMesh(materialName,vertexFlags); + mMySubMeshes.push_back(mCurrent); + } + } + } + + virtual void importTriangle(const char *materialName, + MiU32 vertexFlags, + const MeshVertex &_v1, + const MeshVertex &_v2, + const MeshVertex &_v3) + { + MeshVertex v1 = _v1; + MeshVertex v2 = _v2; + MeshVertex v3 = _v3; + fm_normalize(v1.mNormal); + fm_normalize(v1.mBiNormal); + fm_normalize(v1.mTangent); + + fm_normalize(v2.mNormal); + fm_normalize(v2.mBiNormal); + fm_normalize(v2.mTangent); + + fm_normalize(v3.mNormal); + fm_normalize(v3.mBiNormal); + fm_normalize(v3.mTangent); + + + mAABB.include( v1.mPos ); + mAABB.include( v2.mPos ); + mAABB.include( v3.mPos ); + getCurrent(materialName,vertexFlags); + mVertexFlags|=vertexFlags; + + mCurrent->add(v1,v2,v3,mVertexPool); + } + + virtual void importIndexedTriangleList(const char *materialName, + MiU32 vertexFlags, + MiU32 /*vcount*/, + const MeshVertex *vertices, + MiU32 tcount, + const MiU32 *indices) + { + for (MiU32 i=0; i<tcount; i++) + { + MiU32 i1 = indices[i*3+0]; + MiU32 i2 = indices[i*3+1]; + MiU32 i3 = indices[i*3+2]; + const MeshVertex &v1 = vertices[i1]; + const MeshVertex &v2 = vertices[i2]; + const MeshVertex &v3 = vertices[i3]; + importTriangle(materialName,vertexFlags,v1,v2,v3); + } + } + + void gather(MiI32 bone_count) + { + mSubMeshes = 0; + mSubMeshCount = 0; + if ( !mMySubMeshes.empty() ) + { + mSubMeshCount = (MiU32)mMySubMeshes.size(); + mSubMeshes = &mMySubMeshes[0]; + for (MiU32 i=0; i<mSubMeshCount; i++) + { + MySubMesh *m = static_cast<MySubMesh *>(mSubMeshes[i]); + m->gather(); + } + } + mVertexCount = (MiU32)mVertexPool.GetSize(); + if ( mVertexCount > 0 ) + { + mVertices = mVertexPool.GetBuffer(); + if ( bone_count > 0 ) + { + for (MiU32 i=0; i<mVertexCount; i++) + { + MeshVertex &vtx = mVertices[i]; + if ( vtx.mBone[0] >= bone_count ) vtx.mBone[0] = 0; + if ( vtx.mBone[1] >= bone_count ) vtx.mBone[1] = 0; + if ( vtx.mBone[2] >= bone_count ) vtx.mBone[2] = 0; + if ( vtx.mBone[3] >= bone_count ) vtx.mBone[3] = 0; + } + } + } + } + + VertexPool< MeshVertex > mVertexPool; + MySubMesh *mCurrent; + SubMeshVector mMySubMeshes; +}; + +typedef STDNAME::map< StringRef, StringRef > StringRefMap; +typedef STDNAME::vector< MeshMaterial > MeshMaterialVector; +typedef STDNAME::vector< MeshInstance > MeshInstanceVector; +typedef STDNAME::vector< MyMesh *> MyMeshVector; +typedef STDNAME::vector< Mesh *> MeshVector; +typedef STDNAME::vector< MeshCollision * > MeshCollisionVector; + +class MyMeshCollisionRepresentation : public MeshCollisionRepresentation, public MeshImportAllocated +{ +public: + MyMeshCollisionRepresentation(const MeshCollisionRepresentation &mr,StringDict &dictionary) + { + bool first; + mName = dictionary.Get(mr.mName,first); + mInfo = dictionary.Get(mr.mInfo,first); + mCollisionCount = mr.mCollisionCount; + mCollisionGeometry = (MeshCollision **)MI_ALLOC( sizeof(MeshCollision *)*mCollisionCount); + + for (MiU32 i=0; i<mCollisionCount; i++) + { + const MeshCollision *source = mr.mCollisionGeometry[i]; + switch ( source->getType() ) + { + case MCT_BOX: + { + MeshCollisionBox *dest = (MeshCollisionBox *)MI_ALLOC(sizeof(MeshCollisionBox)); + new ( dest ) MeshCollisionBox; + const MeshCollisionBox *box = static_cast< const MeshCollisionBox *>(source); + *dest = *box; + dest->mName = dictionary.Get(box->mName,first); + mCollisionGeometry[i] = dest; + } + break; + case MCT_SPHERE: + { + MeshCollisionSphere *dest = (MeshCollisionSphere *)MI_ALLOC(sizeof(MeshCollisionSphere)); + new ( dest ) MeshCollisionSphere; + const MeshCollisionSphere *sphere = static_cast< const MeshCollisionSphere *>(source); + *dest = *sphere; + dest->mName = dictionary.Get(sphere->mName,first); + mCollisionGeometry[i] = dest; + } + break; + case MCT_CONVEX: + { + MeshCollisionConvex *dest = (MeshCollisionConvex *)MI_ALLOC(sizeof(MeshCollisionConvex)); + new ( dest ) MeshCollisionConvex; + const MeshCollisionConvex *convex = static_cast< const MeshCollisionConvex *>(source); + *dest = *convex; + if ( convex->mTriCount ) + { + dest->mIndices = (MiU32 *)MI_ALLOC(sizeof(MiU32)*convex->mTriCount*3); + memcpy(dest->mIndices,convex->mIndices,sizeof(MiU32)*convex->mTriCount*3); + } + else + { + dest->mIndices = NULL; + } + if ( convex->mVertexCount ) + { + dest->mVertices = (MiF32 *)MI_ALLOC(sizeof(MiF32)*convex->mVertexCount*3); + memcpy(dest->mVertices,convex->mVertices,sizeof(MiF32)*convex->mVertexCount*3); + } + else + { + dest->mVertices = NULL; + } + dest->mName = dictionary.Get(convex->mName,first); + mCollisionGeometry[i] = dest; + } + break; + default: + assert(0); + break; + } + } + + mPosition[0] = mr.mPosition[0]; + mPosition[1] = mr.mPosition[1]; + mPosition[2] = mr.mPosition[2]; + mOrientation[0] = mr.mOrientation[0]; + mOrientation[1] = mr.mOrientation[1]; + mOrientation[2] = mr.mOrientation[2]; + mOrientation[3] = mr.mOrientation[3]; + mSolverCount = mr.mSolverCount; + mAwake = mr.mAwake; + } + + ~MyMeshCollisionRepresentation(void) + { + for (MiU32 i=0; i<mCollisionCount; i++) + { + MeshCollision *mc = mCollisionGeometry[i]; + delete(mc); + } + MI_FREE(mCollisionGeometry); + } + + void gather(void) + { + } +}; + +typedef STDNAME::vector< MeshCollisionRepresentation * > MeshCollisionRepresentationVector; +typedef STDNAME::vector< MeshSimpleJoint > MeshSimpleJointVector; + +class MyMeshBuilder : public MeshBuilder +{ +public: + MyMeshBuilder(const char *meshName,const void *data,MiU32 dlen,MeshImporter *mi,const char *options,MeshImportApplicationResource *appResource) + { + gSerializeFrame++; + mCurrentMesh = 0; + mAppResource = appResource; + importAssetName(meshName,0); + if ( mi ) + { + mDeserializeBinary = false; + mImportState = mi->importMesh(meshName,data,dlen,this,options,appResource); + } + else + { + mDeserializeBinary = true; + mImportState = deserializeBinary(data,dlen,options,appResource); + } + if (mImportState) + { + gather(); + } + } + + MyMeshBuilder(MeshImportApplicationResource *appResource) + { + gSerializeFrame++; + mCurrentMesh = 0; + mAppResource = appResource; + mDeserializeBinary = false; + mImportState = true; + } + + + virtual ~MyMeshBuilder(void) + { + if ( mDeserializeBinary ) + { + for (MeshVector::iterator i=mFlatMeshes.begin(); i!=mFlatMeshes.end(); ++i) + { + Mesh *m = (*i); + MI_FREE(m->mVertices); + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *sm = m->mSubMeshes[j]; + MI_FREE(sm->mIndices); + delete(sm); + } + delete(m); + } + } + else + { + MI_FREE(mMeshes); + MyMeshVector::iterator i; + for (i=mMyMeshes.begin(); i!=mMyMeshes.end(); ++i) + { + MyMesh *src = (*i); + delete src; + } + } + + if ( !mMyAnimations.empty() ) + { + MeshAnimationVector::iterator i; + for (i=mMyAnimations.begin(); i!=mMyAnimations.end(); ++i) + { + MeshAnimation *a = (*i); + for (MiI32 j=0; j<a->mTrackCount; j++) + { + MeshAnimTrack *ma = a->mTracks[j]; + delete(ma->mPose); + delete(ma); + } + MI_FREE(a->mTracks); + delete(a); + } + } + + if ( !mMySkeletons.empty() ) + { + MeshSkeletonVector::iterator i; + for (i=mMySkeletons.begin(); i!=mMySkeletons.end(); ++i) + { + MeshSkeleton *s = (*i); + delete(s->mBones); + delete(s); + } + } + if ( !mCollisionReps.empty() ) + { + MeshCollisionRepresentationVector::iterator i; + for (i=mCollisionReps.begin(); i!=mCollisionReps.end(); ++i) + { + MyMeshCollisionRepresentation *mcr = static_cast< MyMeshCollisionRepresentation *>(*i); + delete mcr; + } + } + for (MeshRawTextureVector::iterator i=mMyRawTextures.begin(); i!=mMyRawTextures.end(); ++i) + { + MeshRawTexture *t = (*i); + MI_FREE(t->mData); + delete(t); + } + for (MeshTetraVector::iterator i=mMyMeshTextra.begin(); i!=mMyMeshTextra.end(); ++i) + { + MeshTetra *m = (*i); + delete(m); + } + for (MeshUserDataVector::iterator i=mMyMeshUserData.begin(); i!=mMyMeshUserData.end(); ++i) + { + MeshUserData *m = (*i); + delete(m); + } + for (MeshUserBinaryDataVector::iterator i=mMyMeshUserBinaryData.begin(); i!=mMyMeshUserBinaryData.end(); ++i) + { + MeshUserBinaryData *m = (*i); + MI_FREE(m->mUserData); + delete(m); + } + } + + virtual void setMeshImportBinary(bool state) + { + mDeserializeBinary = state; + } + + + void gather(void) + { + if ( !mDeserializeBinary ) + { + gatherMaterials(); + mMaterialCount = (MiU32)mMyMaterials.size(); + if ( mMaterialCount ) + { + mMaterials = &mMyMaterials[0]; + } + else + { + mMaterials = 0; + } + } + mMeshInstanceCount = (MiU32)mMyMeshInstances.size(); + if ( mMeshInstanceCount ) + { + mMeshInstances = &mMyMeshInstances[0]; + } + else + { + mMeshInstances = 0; + } + + mAnimationCount = (MiU32)mMyAnimations.size(); + if ( mAnimationCount ) + mAnimations = &mMyAnimations[0]; + else + mAnimations = 0; + + MiI32 bone_count = 0; + mSkeletonCount = (MiU32)mMySkeletons.size(); + if ( mSkeletonCount ) + { + mSkeletons = &mMySkeletons[0]; + bone_count = mSkeletons[0]->mBoneCount; + } + else + { + mSkeletons = 0; + } + + if ( mDeserializeBinary ) + { + mMeshCount = (MiU32)mFlatMeshes.size(); + if ( mMeshCount ) + { + mMeshes = &mFlatMeshes[0]; + } + else + { + mMeshes = NULL; + } + } + else + { + mMeshCount = (MiU32)mMyMeshes.size(); + if ( mMeshCount ) + { + MI_FREE(mMeshes); + mMeshes = (Mesh **)MI_ALLOC(sizeof(Mesh *)*mMeshCount); + Mesh **dst = mMeshes; + MyMeshVector::iterator i; + for (i=mMyMeshes.begin(); i!=mMyMeshes.end(); ++i) + { + MyMesh *src = (*i); + src->gather(bone_count); + *dst++ = static_cast< Mesh *>(src); + } + } + else + { + mMeshes = NULL; + } + } + + mMeshCollisionCount = (MiU32)mCollisionReps.size(); + + if ( mMeshCollisionCount ) + { + mMeshCollisionRepresentations = &mCollisionReps[0]; + for (MiU32 i=0; i<mMeshCollisionCount; i++) + { + MeshCollisionRepresentation *r = mMeshCollisionRepresentations[i]; + MyMeshCollisionRepresentation *mr = static_cast< MyMeshCollisionRepresentation *>(r); + mr->gather(); + } + } + else + { + mMeshCollisionRepresentations = 0; + } + // + mTextureCount = (MiU32)mMyRawTextures.size(); + if ( !mMyRawTextures.empty() ) + { + mTextures = &mMyRawTextures[0]; + } + mTetraMeshCount = (MiU32)mMyMeshTextra.size(); + if ( !mMyMeshTextra.empty() ) + { + mTetraMeshes = &mMyMeshTextra[0]; + } + mUserDataCount = (MiU32)mMyMeshUserData.size(); + if ( !mMyMeshUserData.empty() ) + { + mUserData = &mMyMeshUserData[0]; + } + mUserBinaryDataCount = (MiU32)mMyMeshUserBinaryData.size(); + if ( !mMyMeshUserBinaryData.empty() ) + { + mUserBinaryData = &mMyMeshUserBinaryData[0]; + } + + mMeshJointCount = (MiU32)mMyJoints.size(); + if ( !mMyJoints.empty() ) + { + mMeshJoints = &mMyJoints[0]; + } + + mMeshPairCollisionCount = mCollisionPairs.size(); + if ( !mCollisionPairs.empty() ) + { + mMeshPairCollisions = &mCollisionPairs[0]; + } + + fixupNamedPointers(); + } + + void gatherMaterials(void) + { + mMyMaterials.clear(); + MiU32 mcount = (MiU32)mMaterialMap.size(); + mMyMaterials.reserve(mcount); + StringRefMap::iterator i; + for (i=mMaterialMap.begin(); i!=mMaterialMap.end(); ++i) + { + MeshMaterial m; + m.mName = (*i).first.Get(); + m.mMetaData = (*i).second.Get(); + mMyMaterials.push_back(m); + } + } + + virtual void importUserData(const char * /*userKey*/,const char * /*userValue*/) // carry along raw user data as ASCII strings only.. + { + assert(0); // not yet implemented + } + + virtual void importUserBinaryData(const char * /*name*/,MiU32 /*len*/,const MiU8 * /*data*/) + { + assert(0); // not yet implemented + } + + virtual void importTetraMesh(const char * /*tetraName*/,const char * /*meshName*/,MiU32 /*tcount*/,const MiF32 * /*tetraData*/) + { + assert(0); // not yet implemented + } + + virtual void importMaterial(const char *matName,const char *metaData) + { + matName = getMaterialName(matName); + StringRef m = mStrings.Get(matName); + StringRef d = mStrings.Get(metaData); + StringRefMap::iterator found = mMaterialMap.find(m); + if ( found == mMaterialMap.end() ) + { + mMaterialMap[m] = d; + } + else + { + // only overwrite it if we have additional meta data we didn't have before.. + if ( metaData && strlen(metaData)) + { + mMaterialMap[m] = d; + } + } + } + + virtual void importAssetName(const char *assetName,const char *info) // name of the overall asset. + { + mAssetName = mStrings.Get(assetName).Get(); + mAssetInfo = mStrings.Get(info).Get(); + } + + virtual void importMesh(const char *meshName,const char *skeletonName) // name of a mesh and the skeleton it refers to. + { + StringRef m1 = mStrings.Get(meshName); + StringRef s1 = mStrings.Get(skeletonName); + + mCurrentMesh = 0; + MyMeshVector::iterator found; + for (found=mMyMeshes.begin(); found != mMyMeshes.end(); found++) + { + MyMesh *mm = (*found); + if ( mm->mName == m1 ) + { + mCurrentMesh = mm; + mCurrentMesh->mSkeletonName = s1.Get(); + break; + } + } + if ( mCurrentMesh == 0 ) + { + MyMesh *m = (MyMesh *)MI_ALLOC(sizeof(MyMesh)); + new (m ) MyMesh(m1.Get(),s1.Get()); + mMyMeshes.push_back(m); + mCurrentMesh = m; + } + } + + void getCurrentMesh(const char *meshName) + { + if ( meshName == 0 ) + { + meshName = "default_mesh"; + } + if ( mCurrentMesh == 0 || !mCurrentMesh->isSame(meshName) ) + { + importMesh(meshName,0); // make it the new current mesh + } + } + + virtual void importPlane(const MiF32 *p) + { + mPlane[0] = p[0]; + mPlane[1] = p[1]; + mPlane[2] = p[2]; + mPlane[3] = p[3]; + } + + + + virtual void importTriangle(const char *_meshName, + const char *_materialName, + MiU32 vertexFlags, + const MeshVertex &v1, + const MeshVertex &v2, + const MeshVertex &v3) + { + _materialName = getMaterialName(_materialName); + const char *meshName = mStrings.Get(_meshName).Get(); + const char *materialName = mStrings.Get(_materialName).Get(); + getCurrentMesh(meshName); + mAABB.include(v1.mPos); + mAABB.include(v2.mPos); + mAABB.include(v3.mPos); + mCurrentMesh->importTriangle(materialName,vertexFlags,v1,v2,v3); + } + + virtual void importIndexedTriangleList(const char *_meshName, + const char *_materialName, + MiU32 vertexFlags, + MiU32 vcount, + const MeshVertex *vertices, + MiU32 tcount, + const MiU32 *indices) + { + _materialName = getMaterialName(_materialName); + const char *meshName = mStrings.Get(_meshName).Get(); + const char *materialName = mStrings.Get(_materialName).Get(); + getCurrentMesh(meshName); + for (MiU32 i=0; i<vcount; i++) + { + mAABB.include( vertices[i].mPos ); + } + mCurrentMesh->importIndexedTriangleList(materialName,vertexFlags,vcount,vertices,tcount,indices); + } + + // do a deep copy... + virtual void importAnimation(const MeshAnimation &animation) + { + MeshAnimation *a = (MeshAnimation *)MI_ALLOC(sizeof(MeshAnimation)); + new ( a ) MeshAnimation; + a->mName = mStrings.Get(animation.mName).Get(); + a->mTrackCount = animation.mTrackCount; + a->mFrameCount = animation.mFrameCount; + a->mDuration = animation.mDuration; + a->mDtime = animation.mDtime; + a->mTracks = (MeshAnimTrack **)MI_ALLOC(sizeof(MeshAnimTrack *)*a->mTrackCount); + for (MiI32 i=0; i<a->mTrackCount; i++) + { + const MeshAnimTrack &src =*animation.mTracks[i]; + MeshAnimTrack *t = (MeshAnimTrack *)MI_ALLOC(sizeof(MeshAnimTrack)); + new ( t ) MeshAnimTrack; + t->mName = mStrings.Get(src.mName).Get(); + t->mFrameCount = src.mFrameCount; + t->mDuration = src.mDuration; + t->mDtime = src.mDtime; + t->mPose = (MeshAnimPose *)MI_ALLOC(sizeof(MeshAnimPose)*t->mFrameCount); + for (MiI32 j=0; j<t->mFrameCount; j++) + { + new ( &t->mPose[j] ) MeshAnimPose; + } + memcpy(t->mPose,src.mPose,sizeof(MeshAnimPose)*t->mFrameCount); + a->mTracks[i] = t; + } + mMyAnimations.push_back(a); + } + + virtual void importSkeleton(const MeshSkeleton &skeleton) + { + MeshSkeleton *sk = (MeshSkeleton *)MI_ALLOC(sizeof(MeshSkeleton)); + new (sk ) MeshSkeleton; + sk->mName = mStrings.Get( skeleton.mName ).Get(); + sk->mBoneCount = skeleton.mBoneCount; + sk->mBones = 0; + if ( sk->mBoneCount > 0 ) + { + sk->mBones = (MeshBone *)MI_ALLOC(sizeof(MeshBone)*sk->mBoneCount); + for (MiI32 j=0; j<sk->mBoneCount; j++) + { + new ( &sk->mBones[j])MeshBone; + } + MeshBone *dest = sk->mBones; + const MeshBone *src = skeleton.mBones; + for (MiU32 i=0; i<(MiU32)sk->mBoneCount; i++) + { + *dest = *src; + dest->mName = mStrings.Get(src->mName).Get(); + src++; + dest++; + } + } + mMySkeletons.push_back(sk); + } + + virtual void importRawTexture(const char * /*textureName*/,const MiU8 * /*pixels*/,MiU32 /*wid*/,MiU32 /*hit*/) + { +// assert(0); // not yet implemented + } + + virtual void importMeshInstance(const char *meshName,const MiF32 pos[3],const MiF32 rotation[4],const MiF32 scale[3]) + { + StringRef ref = mStrings.Get(meshName); + MeshInstance m; + m.mMeshName = ref.Get(); + m.mPosition[0] = pos[0]; + m.mPosition[1] = pos[1]; + m.mPosition[2] = pos[2]; + m.mRotation[0] = rotation[0]; + m.mRotation[1] = rotation[1]; + m.mRotation[2] = rotation[2]; + m.mRotation[3] = rotation[3]; + m.mScale[0] = scale[0]; + m.mScale[1] = scale[1]; + m.mScale[2] = scale[2]; + mMyMeshInstances.push_back(m); + } + + virtual void importCollisionRepresentation(const MeshCollisionRepresentation &mr) // the name of a new collision representation. + { + MyMeshCollisionRepresentation *mmr = MI_NEW(MyMeshCollisionRepresentation)(mr,mStrings); + mCollisionReps.push_back(mmr); + } + + virtual void importSimpleJoint(const MeshSimpleJoint &joint) + { + MeshSimpleJoint msj = joint; + bool first; + msj.mName = mStrings.Get(joint.mName,first); + msj.mParent = mStrings.Get(joint.mParent,first); + mMyJoints.push_back(msj); + } + + virtual void rotate(MiF32 rotX,MiF32 rotY,MiF32 rotZ) + { + MiF32 quat[4]; + fm_eulerToQuat(rotX*FM_DEG_TO_RAD,rotY*FM_DEG_TO_RAD,rotZ*FM_DEG_TO_RAD,quat); + + { + MeshSkeletonVector::iterator i; + for (i=mMySkeletons.begin(); i!=mMySkeletons.end(); ++i) + { + MeshSkeleton *ms = (*i); + for (MiI32 j=0; j<ms->mBoneCount; j++) + { + MeshBone &b = ms->mBones[j]; + if ( b.mParentIndex == -1 ) + { + fm_quatRotate(quat,b.mPosition,b.mPosition); + fm_multiplyQuat(quat,b.mOrientation,b.mOrientation); + } + } + } + } + + { + MyMeshVector::iterator i; + for (i=mMyMeshes.begin(); i!=mMyMeshes.end(); ++i) + { + MyMesh *m = (*i); + MiU32 vcount = (MiU32)m->mVertexPool.GetSize(); + if ( vcount > 0 ) + { + MeshVertex *vb = m->mVertexPool.GetBuffer(); + for (MiU32 j=0; j<vcount; j++) + { + fm_quatRotate(quat,vb->mPos,vb->mPos); + vb++; + } + } + } + } + + { + MeshAnimationVector::iterator i; + for (i=mMyAnimations.begin(); i!=mMyAnimations.end(); ++i) + { + MeshAnimation *ma = (*i); + for (MiI32 j=0; j<ma->mTrackCount && j <1; j++) + { + MeshAnimTrack *t = ma->mTracks[j]; + for (MiI32 k=0; k<t->mFrameCount; k++) + { + MeshAnimPose &p = t->mPose[k]; + fm_quatRotate(quat,p.mPos,p.mPos); + fm_multiplyQuat(quat,p.mQuat,p.mQuat); + } + } + } + } + } + + virtual void scale(MiF32 s) + { + { + MeshSkeletonVector::iterator i; + for (i=mMySkeletons.begin(); i!=mMySkeletons.end(); ++i) + { + MeshSkeleton *ms = (*i); + for (MiI32 j=0; j<ms->mBoneCount; j++) + { + MeshBone &b = ms->mBones[j]; + b.mPosition[0]*=s; + b.mPosition[1]*=s; + b.mPosition[2]*=s; + } + } + } + + { + MyMeshVector::iterator i; + for (i=mMyMeshes.begin(); i!=mMyMeshes.end(); ++i) + { + MyMesh *m = (*i); + MiU32 vcount = (MiU32)m->mVertexPool.GetSize(); + if ( vcount > 0 ) + { + MeshVertex *vb = m->mVertexPool.GetBuffer(); + for (MiU32 j=0; j<vcount; j++) + { + vb->mPos[0]*=s; + vb->mPos[1]*=s; + vb->mPos[2]*=s; + vb++; + } + } + } + } + + { + MeshAnimationVector::iterator i; + for (i=mMyAnimations.begin(); i!=mMyAnimations.end(); ++i) + { + MeshAnimation *ma = (*i); + for (MiI32 j=0; j<ma->mTrackCount; j++) + { + MeshAnimTrack *t = ma->mTracks[j]; + for (MiI32 k=0; k<t->mFrameCount; k++) + { + MeshAnimPose &p = t->mPose[k]; + p.mPos[0]*=s; + p.mPos[1]*=s; + p.mPos[2]*=s; + } + } + } + } + } + + virtual MiI32 getSerializeFrame(void) + { + return gSerializeFrame; + } + + const char *getMaterialName(const char *matName) + { + const char *ret = matName; + return ret; + } + + bool getImportState() const { return mImportState; } + + const char * streamString(MiIOStream &stream) + { + const char *ret = ""; + const char *str; + stream >> str; + if ( str ) + { + bool first; + ret = mStrings.Get(str,first); + } + return ret; + } + + void deserialize(MiIOStream &stream,MeshAABB &m) + { + stream >> m.mMin[0]; + stream >> m.mMin[1]; + stream >> m.mMin[2]; + stream >> m.mMax[0]; + stream >> m.mMax[1]; + stream >> m.mMax[2]; + } + + void deserialize(MiIOStream &stream,MeshRawTexture &m) + { + m.mName = streamString(stream); + stream >> m.mWidth; + stream >> m.mHeight; + stream >> m.mBPP; + MiU32 dataLen = 0; + stream >> dataLen; + if ( dataLen ) + { + m.mData = (MiU8 *)MI_ALLOC(dataLen); + stream.getStream().read(m.mData,dataLen); + } + } + + void deserialize(MiIOStream & /*stream*/,MeshTetra & /*mrt*/) + { + MI_ALWAYS_ASSERT(); // Not yet implemented + } + + void deserialize(MiIOStream &stream,MeshBone &m) + { + m.mName = streamString(stream); + stream >> m.mParentIndex; + stream >> m.mPosition[0]; + stream >> m.mPosition[1]; + stream >> m.mPosition[2]; + stream >> m.mOrientation[0]; + stream >> m.mOrientation[1]; + stream >> m.mOrientation[2]; + stream >> m.mOrientation[3]; + stream >> m.mScale[0]; + stream >> m.mScale[1]; + stream >> m.mScale[2]; + } + + void deserialize(MiIOStream &stream,MeshSkeleton &m) + { + m.mName = streamString(stream); + stream >> m.mBoneCount; + if ( m.mBoneCount ) + { + m.mBones = (MeshBone *)MI_ALLOC(sizeof(MeshBone)*m.mBoneCount); + for (MiI32 i=0; i<m.mBoneCount; i++) + { + new ( &m.mBones[i] ) MeshBone; + } + } + for (MiI32 i=0; i<m.mBoneCount; i++) + { + MeshBone &b = m.mBones[i]; + deserialize(stream,b); + } + } + + void deserialize(MiIOStream &stream,MeshAnimPose &m) + { + stream >> m.mPos[0]; + stream >> m.mPos[1]; + stream >> m.mPos[2]; + stream >> m.mQuat[0]; + stream >> m.mQuat[1]; + stream >> m.mQuat[2]; + stream >> m.mQuat[3]; + stream >> m.mScale[0]; + stream >> m.mScale[1]; + stream >> m.mScale[2]; + } + + void deserialize(MiIOStream &stream,MeshAnimTrack &m) + { + m.mName = streamString(stream); + stream >> m.mFrameCount; + stream >> m.mDuration; + stream >> m.mDtime; + if ( m.mFrameCount ) + { + m.mPose = (MeshAnimPose *)MI_ALLOC(sizeof(MeshAnimPose)*m.mFrameCount); + for (MiI32 i=0; i<m.mFrameCount; i++) + { + new ( &m.mPose[i] ) MeshAnimPose; + } + } + for (MiI32 i=0; i<m.mFrameCount; i++) + { + MeshAnimPose &p = m.mPose[i]; + deserialize(stream,p); + } + } + + void deserialize(MiIOStream &stream,MeshAnimation &m) + { + m.mName = streamString(stream); + stream >> m.mTrackCount; + stream >> m.mFrameCount; + stream >> m.mDuration; + stream >> m.mDtime; + if ( m.mTrackCount ) + { + m.mTracks = (MeshAnimTrack **)MI_ALLOC(sizeof(MeshAnimTrack *)*m.mTrackCount); + } + for (MiI32 i=0; i<m.mTrackCount; i++) + { + MeshAnimTrack *t = (MeshAnimTrack *)MI_ALLOC(sizeof(MeshAnimTrack)); + deserialize(stream,*t); + m.mTracks[i] = t; + } + } + + void deserialize(MiIOStream &stream,MeshMaterial &m) + { + m.mName = streamString(stream); + m.mMetaData = streamString(stream); + } + + void deserialize(MiIOStream &stream,MeshUserData &m) + { + m.mUserKey = streamString(stream); + m.mUserValue = streamString(stream); + } + + void deserialize(MiIOStream &stream,MeshUserBinaryData &m) + { + m.mName = streamString(stream); + stream >> m.mUserLen; + if ( m.mUserLen ) + { + m.mUserData = (MiU8 *)MI_ALLOC(m.mUserLen); + stream.getStream().read(m.mUserData,m.mUserLen); + } + } + + void deserialize(MiIOStream &stream,SubMesh &m) + { + m.mMaterialName = streamString(stream); + deserialize(stream,m.mAABB); + stream >> m.mVertexFlags; + stream >> m.mTriCount; + if ( m.mTriCount ) + { + m.mIndices = (MiU32 *)MI_ALLOC(sizeof(MiU32)*m.mTriCount*3); + } + for (MiU32 i=0; i<m.mTriCount*3; i++) + { + stream >> m.mIndices[i]; + } + } + + void deserialize(MiIOStream &stream,MeshVertex &m,MiU32 vertexFlags) + { + + if ( vertexFlags & MIVF_POSITION ) + { + stream >> m.mPos[0]; + stream >> m.mPos[1]; + stream >> m.mPos[2]; + } + if ( vertexFlags & MIVF_NORMAL ) + { + stream >> m.mNormal[0]; + stream >> m.mNormal[1]; + stream >> m.mNormal[2]; + } + if ( vertexFlags & MIVF_COLOR ) + { + stream >> m.mColor; + } + if ( vertexFlags & MIVF_TEXEL1 ) + { + stream >> m.mTexel1[0]; + stream >> m.mTexel1[1]; + } + if ( vertexFlags & MIVF_TEXEL2 ) + { + stream >> m.mTexel2[0]; + stream >> m.mTexel2[1]; + } + if ( vertexFlags & MIVF_TEXEL3 ) + { + stream >> m.mTexel3[0]; + stream >> m.mTexel3[1]; + } + if ( vertexFlags & MIVF_TEXEL4 ) + { + stream >> m.mTexel4[0]; + stream >> m.mTexel4[1]; + } + if ( vertexFlags & MIVF_TANGENT ) + { + stream >> m.mTangent[0]; + stream >> m.mTangent[1]; + stream >> m.mTangent[2]; + } + if ( vertexFlags & MIVF_BINORMAL ) + { + stream >> m.mBiNormal[0]; + stream >> m.mBiNormal[1]; + stream >> m.mBiNormal[2]; + } + if ( vertexFlags & MIVF_BONE_WEIGHTING ) + { + stream >> m.mBone[0]; + stream >> m.mBone[1]; + stream >> m.mBone[2]; + stream >> m.mBone[3]; + stream >> m.mWeight[0]; + stream >> m.mWeight[1]; + stream >> m.mWeight[2]; + stream >> m.mWeight[3]; + } + if ( vertexFlags & MIVF_RADIUS ) + { + stream >> m.mRadius; + } + if ( vertexFlags & MIVF_INTERP1 ) + { + stream >> m.mInterp1[0]; + stream >> m.mInterp1[1]; + stream >> m.mInterp1[2]; + stream >> m.mInterp1[3]; + } + if ( vertexFlags & MIVF_INTERP2 ) + { + stream >> m.mInterp2[0]; + stream >> m.mInterp2[1]; + stream >> m.mInterp2[2]; + stream >> m.mInterp2[3]; + } + if ( vertexFlags & MIVF_INTERP3 ) + { + stream >> m.mInterp3[0]; + stream >> m.mInterp3[1]; + stream >> m.mInterp3[2]; + stream >> m.mInterp3[3]; + } + if ( vertexFlags & MIVF_INTERP4 ) + { + stream >> m.mInterp4[0]; + stream >> m.mInterp4[1]; + stream >> m.mInterp4[2]; + stream >> m.mInterp4[3]; + } + if ( vertexFlags & MIVF_INTERP5 ) + { + stream >> m.mInterp5[0]; + stream >> m.mInterp5[1]; + stream >> m.mInterp5[2]; + stream >> m.mInterp5[3]; + } + if ( vertexFlags & MIVF_INTERP6 ) + { + stream >> m.mInterp6[0]; + stream >> m.mInterp6[1]; + stream >> m.mInterp6[2]; + stream >> m.mInterp6[3]; + } + if ( vertexFlags & MIVF_INTERP7 ) + { + stream >> m.mInterp7[0]; + stream >> m.mInterp7[1]; + stream >> m.mInterp7[2]; + stream >> m.mInterp7[3]; + } + if ( vertexFlags & MIVF_INTERP8 ) + { + stream >> m.mInterp8[0]; + stream >> m.mInterp8[1]; + stream >> m.mInterp8[2]; + stream >> m.mInterp8[3]; + } + + + } + + + void deserialize(MiIOStream &stream,Mesh &m) + { + m.mName = streamString(stream); + m.mSkeletonName = streamString(stream); + deserialize(stream,m.mAABB); + stream >> m.mSubMeshCount; + if ( m.mSubMeshCount ) + { + m.mSubMeshes = (SubMesh **)MI_ALLOC(sizeof(SubMesh *)*m.mSubMeshCount); + } + for (MiU32 i=0; i<m.mSubMeshCount; i++) + { + SubMesh *s = (SubMesh *)MI_ALLOC(sizeof(SubMesh)); + new (s ) SubMesh; + deserialize(stream,*s); + m.mSubMeshes[i] = s; + } + stream >> m.mVertexFlags; + stream >> m.mVertexCount; + if ( m.mVertexCount ) + { + m.mVertices = (MeshVertex *)MI_ALLOC(sizeof(MeshVertex)*m.mVertexCount); + } + for (MiU32 i=0; i<m.mVertexCount; i++) + { + MeshVertex &v = m.mVertices[i]; + new ( &v ) MeshVertex; + deserialize(stream,v,m.mVertexFlags); + } + } + + void deserialize(MiIOStream &stream,MeshInstance &m) + { + m.mMeshName = streamString(stream); + stream >> m.mPosition[0]; + stream >> m.mPosition[1]; + stream >> m.mPosition[2]; + stream >> m.mRotation[0]; + stream >> m.mRotation[1]; + stream >> m.mRotation[2]; + stream >> m.mRotation[3]; + stream >> m.mScale[0]; + stream >> m.mScale[1]; + stream >> m.mScale[2]; + } + + void deserialize(MiIOStream & /*stream*/,const MeshCollisionRepresentation & /*m*/) + { + MI_ALWAYS_ASSERT(); // need to implement + } + + + + bool deserializeBinary(const void *data,MiU32 dlen,const char * /*options*/,MeshImportApplicationResource * /*appResource*/) + { + bool ret = false; + + MiMemoryBuffer mb(data,dlen); + mb.setEndianMode(MiFileBuf::ENDIAN_BIG); + MiIOStream stream(mb,dlen); + + MiU32 version = 0; + stream >> version; + const char *tag; + stream >> tag; + + if ( version == MESH_BINARY_VERSION && tag && strcmp(tag,"EZMESH") == 0 ) + { + mAssetName = streamString(stream); + mAssetInfo = streamString(stream); + stream >> mMeshSystemVersion; + stream >> mAssetVersion; + deserialize(stream,mAABB); + stream >> mTextureCount; + for (MiU32 i=0; i<mTextureCount; i++) + { + MeshRawTexture *t = (MeshRawTexture *)MI_ALLOC(sizeof(MeshRawTexture)); + new (t ) MeshRawTexture; + deserialize(stream,*t); + mMyRawTextures.push_back(t); + } + stream >> mTetraMeshCount; + for (MiU32 i=0; i< mTetraMeshCount; i++) + { + MeshTetra *m = (MeshTetra *)MI_ALLOC(sizeof(MeshTetra)); + new ( m ) MeshTetra; + deserialize(stream,*m); + mMyMeshTextra.push_back(m); + } + stream >> mSkeletonCount; + for (MiU32 i=0; i< mSkeletonCount; i++) + { + MeshSkeleton *m = (MeshSkeleton *)MI_ALLOC(sizeof(MeshSkeleton)); + new ( m ) MeshSkeleton; + deserialize(stream,*m); + mMySkeletons.push_back(m); + } + stream >> mAnimationCount; + for (MiU32 i=0; i<mAnimationCount; i++) + { + MeshAnimation *m = (MeshAnimation *)MI_ALLOC(sizeof(MeshAnimation)); + new ( m ) MeshAnimation; + deserialize(stream,*m); + mMyAnimations.push_back(m); + } + stream >> mMaterialCount; + if ( mMaterialCount ) + { + mMaterials = (MeshMaterial *)MI_ALLOC(sizeof(MeshMaterial)*mMaterialCount); + } + for (MiU32 i=0; i<mMaterialCount; i++) + { + MeshMaterial &m = mMaterials[i]; + new ( &m ) MeshMaterial; + deserialize(stream,m); + } + stream >> mUserDataCount; + for (MiU32 i=0; i<mUserDataCount; i++) + { + MeshUserData *m = (MeshUserData *)MI_ALLOC(sizeof(MeshUserData)); + new ( m ) MeshUserData; + deserialize(stream,*m); + mMyMeshUserData.push_back(m); + } + stream >> mUserBinaryDataCount; + for (MiU32 i=0; i<mUserBinaryDataCount; i++) + { + MeshUserBinaryData *m = (MeshUserBinaryData *)MI_ALLOC(sizeof(MeshUserBinaryData)); + new ( m ) MeshUserBinaryData; + deserialize(stream,*m); + mMyMeshUserBinaryData.push_back(m); + } + stream >> mMeshCount; + for (MiU32 i=0; i<mMeshCount; i++) + { + Mesh *m = (Mesh *)MI_ALLOC(sizeof(Mesh)); + new ( m ) Mesh; + deserialize(stream,*m); + mFlatMeshes.push_back(m); + } + stream >> mMeshInstanceCount; + if ( mMeshInstanceCount ) + { + mMeshInstances = (MeshInstance *)MI_ALLOC(sizeof(MeshInstance)*mMeshInstanceCount); + } + for (MiU32 i=0; i<mMeshInstanceCount; i++) + { + MeshInstance &m = mMeshInstances[i]; + new ( &m ) MeshInstance; + deserialize(stream,m); + } + stream >> mMeshCollisionCount; + for (MiU32 i=0; i<mMeshCollisionCount; i++) + { + MeshCollisionRepresentation *m = (MeshCollisionRepresentation *)MI_ALLOC(sizeof(MeshCollisionRepresentation)); + new ( m ) MeshCollisionRepresentation; + deserialize(stream,*m); + mCollisionReps.push_back(m); + } + stream >> mPlane[0]; + stream >> mPlane[1]; + stream >> mPlane[2]; + stream >> mPlane[3]; + ret = true; + } + return ret; + } + + void fixupNamedPointers(void) + { + for (MiU32 i=0; i<mMeshCount; i++) + { + Mesh *m = mMeshes[i]; + // patch named pointeres for submesh materials + for (MiU32 j=0; j<m->mSubMeshCount; j++) + { + SubMesh *s = m->mSubMeshes[j]; + for (MiU32 j=0; j<mMaterialCount; j++) + { + MeshMaterial &mm = mMaterials[j]; + if ( strcmp(s->mMaterialName,mm.mName) == 0 ) + { + s->mMaterial = &mm; + break; + } + } + } + // patch named pointers for skeletons + for (MiU32 j=0; j<mSkeletonCount; j++) + { + MeshSkeleton *s = mSkeletons[j]; + if ( strcmp(s->mName,m->mSkeletonName) == 0 ) + { + m->mSkeleton = s; + break; + } + } + } + } + + virtual void importMeshPairCollision(MeshPairCollision &mpc) + { + MeshPairCollision m; + m.mBody1 = mStrings.Get(mpc.mBody1); + m.mBody2 = mStrings.Get(mpc.mBody2); + mCollisionPairs.push_back(m); + } + + +private: + bool mDeserializeBinary; + StringDict mStrings; + StringRefMap mMaterialMap; + MeshMaterialVector mMyMaterials; + MeshInstanceVector mMyMeshInstances; + MyMesh *mCurrentMesh; + + MyMeshVector mMyMeshes; + MeshVector mFlatMeshes; + + MeshAnimationVector mMyAnimations; + MeshSkeletonVector mMySkeletons; + MeshCollisionRepresentationVector mCollisionReps; + MeshSimpleJointVector mMyJoints; + MeshImportApplicationResource *mAppResource; + + MeshRawTextureVector mMyRawTextures; + MeshTetraVector mMyMeshTextra; + MeshUserDataVector mMyMeshUserData; + MeshUserBinaryDataVector mMyMeshUserBinaryData; + MeshPairCollisionVector mCollisionPairs; + + bool mImportState; +}; + +MeshBuilder * createMeshBuilder(const char *meshName,const void *data,MiU32 dlen,MeshImporter *mi,const char *options,MeshImportApplicationResource *appResource) +{ + MyMeshBuilder *b = (MyMeshBuilder *)MI_ALLOC(sizeof(MyMeshBuilder)); + new ( b ) MyMeshBuilder(meshName,data,dlen,mi,options,appResource); + bool state = b->getImportState(); + if (!state) + return 0; + return static_cast< MeshBuilder *>(b); +} + +MeshBuilder * createMeshBuilder(MeshImportApplicationResource *appResource) +{ + MyMeshBuilder *b = (MyMeshBuilder *)MI_ALLOC(sizeof(MyMeshBuilder)); + new ( b ) MyMeshBuilder(appResource); + bool state = b->getImportState(); + if (!state) + return 0; + return static_cast< MeshBuilder *>(b); +} + +void releaseMeshBuilder(MeshBuilder *m) +{ + MyMeshBuilder *b = static_cast< MyMeshBuilder *>(m); + b->~MyMeshBuilder(); + MI_FREE(b); +} + +}; // end of namesapace diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.h new file mode 100644 index 00000000..84330a74 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef MESH_IMPORT_BUILDER_H + +#define MESH_IMPORT_BUILDER_H + +#include "MeshImport.h" + +namespace mimp +{ + +class MeshBuilder : public MeshSystem, public MeshImportInterface +{ +public: + virtual void gather(void) = 0; + virtual void scale(MiF32 s) = 0; + virtual void rotate(MiF32 rotX,MiF32 rotY,MiF32 rotZ) = 0; + virtual void setMeshImportBinary(bool state) = 0; + + +}; + +MeshBuilder * createMeshBuilder(const char *meshName, + const void *data, + MiU32 dlen, + MeshImporter *mi, + const char *options, + MeshImportApplicationResource *appResource); + + +MeshBuilder * createMeshBuilder(MeshImportApplicationResource *appResource); +void releaseMeshBuilder(MeshBuilder *m); + +}; // end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.cpp new file mode 100644 index 00000000..848809a2 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "VtxWeld.h" + +namespace mimp +{ + +template<> MeshVertex VertexLess<MeshVertex>::mFind = MeshVertex(); +template<> STDNAME::vector<MeshVertex > *VertexLess<MeshVertex>::mList=0; + + +template<> +bool VertexLess<MeshVertex>::operator()(MiI32 v1,MiI32 v2) const +{ + + const MeshVertex& a = Get(v1); + const MeshVertex& b = Get(v2); + + if ( a.mPos[0] < b.mPos[0] ) return true; + if ( a.mPos[0] > b.mPos[0] ) return false; + + if ( a.mPos[1] < b.mPos[1] ) return true; + if ( a.mPos[1] > b.mPos[1] ) return false; + + if ( a.mPos[2] < b.mPos[2] ) return true; + if ( a.mPos[2] > b.mPos[2] ) return false; + + + if ( a.mNormal[0] < b.mNormal[0] ) return true; + if ( a.mNormal[0] > b.mNormal[0] ) return false; + + if ( a.mNormal[1] < b.mNormal[1] ) return true; + if ( a.mNormal[1] > b.mNormal[1] ) return false; + + if ( a.mNormal[2] < b.mNormal[2] ) return true; + if ( a.mNormal[2] > b.mNormal[2] ) return false; + + if ( a.mColor < b.mColor ) return true; + if ( a.mColor > b.mColor ) return false; + + + if ( a.mTexel1[0] < b.mTexel1[0] ) return true; + if ( a.mTexel1[0] > b.mTexel1[0] ) return false; + + if ( a.mTexel1[1] < b.mTexel1[1] ) return true; + if ( a.mTexel1[1] > b.mTexel1[1] ) return false; + + if ( a.mTexel2[0] < b.mTexel2[0] ) return true; + if ( a.mTexel2[0] > b.mTexel2[0] ) return false; + + if ( a.mTexel2[1] < b.mTexel2[1] ) return true; + if ( a.mTexel2[1] > b.mTexel2[1] ) return false; + + if ( a.mTexel3[0] < b.mTexel3[0] ) return true; + if ( a.mTexel3[0] > b.mTexel3[0] ) return false; + + if ( a.mTexel3[1] < b.mTexel3[1] ) return true; + if ( a.mTexel3[1] > b.mTexel3[1] ) return false; + + + if ( a.mTexel4[0] < b.mTexel4[0] ) return true; + if ( a.mTexel4[0] > b.mTexel4[0] ) return false; + + if ( a.mTexel4[1] < b.mTexel4[1] ) return true; + if ( a.mTexel4[1] > b.mTexel4[1] ) return false; + + if ( a.mTangent[0] < b.mTangent[0] ) return true; + if ( a.mTangent[0] > b.mTangent[0] ) return false; + + if ( a.mTangent[1] < b.mTangent[1] ) return true; + if ( a.mTangent[1] > b.mTangent[1] ) return false; + + if ( a.mTangent[2] < b.mTangent[2] ) return true; + if ( a.mTangent[2] > b.mTangent[2] ) return false; + + if ( a.mBiNormal[0] < b.mBiNormal[0] ) return true; + if ( a.mBiNormal[0] > b.mBiNormal[0] ) return false; + + if ( a.mBiNormal[1] < b.mBiNormal[1] ) return true; + if ( a.mBiNormal[1] > b.mBiNormal[1] ) return false; + + if ( a.mBiNormal[2] < b.mBiNormal[2] ) return true; + if ( a.mBiNormal[2] > b.mBiNormal[2] ) return false; + + if ( a.mWeight[0] < b.mWeight[0] ) return true; + if ( a.mWeight[0] > b.mWeight[0] ) return false; + + if ( a.mWeight[1] < b.mWeight[1] ) return true; + if ( a.mWeight[1] > b.mWeight[1] ) return false; + + if ( a.mWeight[2] < b.mWeight[2] ) return true; + if ( a.mWeight[2] > b.mWeight[2] ) return false; + + if ( a.mWeight[3] < b.mWeight[3] ) return true; + if ( a.mWeight[3] > b.mWeight[3] ) return false; + + if ( a.mBone[0] < b.mBone[0] ) return true; + if ( a.mBone[0] > b.mBone[0] ) return false; + + if ( a.mBone[1] < b.mBone[1] ) return true; + if ( a.mBone[1] > b.mBone[1] ) return false; + + if ( a.mBone[2] < b.mBone[2] ) return true; + if ( a.mBone[2] > b.mBone[2] ) return false; + + if ( a.mBone[3] < b.mBone[3] ) return true; + if ( a.mBone[3] > b.mBone[3] ) return false; + + if ( a.mRadius < b.mRadius ) return true; + if ( a.mRadius > b.mRadius ) return false; + + return false; +}; + + + +}; // end of name space diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.h b/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.h new file mode 100644 index 00000000..fe89c158 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef VTX_WELD_H + +#define VTX_WELD_H + +#include "MeshImport.h" +#include "MiPlatformConfig.h" + +namespace mimp +{ + +template <class Type> class VertexLess +{ +public: + typedef STDNAME::vector< Type > VertexVector; + + bool operator()(MiI32 v1,MiI32 v2) const; + + static void SetSearch(const Type& match,VertexVector *list) + { + mFind = match; + mList = list; + }; + +private: + const Type& Get(MiI32 index) const + { + if ( index == -1 ) return mFind; + VertexVector &vlist = *mList; + return vlist[(MiU32)index]; + } + static Type mFind; // vertice to locate. + static VertexVector *mList; +}; + +template <class Type> class VertexPool : public mimp::MeshImportAllocated +{ +public: + typedef STDNAME::set<MiI32, VertexLess<Type> > VertexSet; + typedef STDNAME::vector< Type > VertexVector; + + MiI32 GetVertex(const Type& vtx) + { + VertexLess<Type>::SetSearch(vtx,&mVtxs); + typename VertexSet::iterator found; + found = mVertSet.find( -1 ); + if ( found != mVertSet.end() ) + { + return *found; + } + MiI32 idx = (MiI32)mVtxs.size(); + mVtxs.push_back( vtx ); + mVertSet.insert( idx ); + return idx; + }; + + void GetPos(MiI32 idx,MiF32 pos[3]) const + { + pos[0] = mVtxs[idx].mPos[0]; + pos[1] = mVtxs[idx].mPos[1]; + pos[2] = mVtxs[idx].mPos[2]; + } + + const Type& Get(MiI32 idx) const + { + return mVtxs[idx]; + }; + + MiI32 GetSize(void) const + { + return (MiI32)mVtxs.size(); + }; + + void Clear(MiI32 reservesize) // clear the vertice pool. + { + mVertSet.clear(); + mVtxs.clear(); + mVtxs.reserve(reservesize); + }; + + const VertexVector& GetVertexList(void) const { return mVtxs; }; + + void Set(const Type& vtx) + { + mVtxs.push_back(vtx); + } + + MiI32 GetVertexCount(void) const + { + return (MiI32)mVtxs.size(); + }; + + bool GetVertex(MiI32 i,MiF32 vect[3]) const + { + vect[0] = mVtxs[i].mPos[0]; + vect[1] = mVtxs[i].mPos[1]; + vect[2] = mVtxs[i].mPos[2]; + return true; + }; + + + Type * GetBuffer(void) + { + return &mVtxs[0]; + }; +private: + VertexSet mVertSet; // ordered list. + VertexVector mVtxs; // set of vertices. +}; + +}; // end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.cpp new file mode 100644 index 00000000..49a1074b --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.cpp @@ -0,0 +1,1271 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#pragma warning(disable:4702) // disabling a warning that only shows up when building VC7 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdarg.h> +#pragma warning(disable:4555) +#include "MeshImport.h" +#include "ImportEzm.h" +#include "MiStringDictionary.h" +#include "MiSutil.h" +#include "MiStringTable.h" +#include "MiAsc2Bin.h" +#include "MiInparser.h" +#include "MiFastXml.h" +#include "MiMemoryBuffer.h" + +#pragma warning(disable:4100) +#pragma warning(disable:4996) + +namespace mimp +{ + +#define DEBUG_LOG 0 + + enum NodeType + { + NT_NONE, + NT_SCENE_GRAPH, + NT_MESH, + NT_ANIMATION, + NT_SKELETON, + NT_BONE, + NT_MESH_SECTION, + NT_VERTEX_BUFFER, + NT_INDEX_BUFFER, + NT_NODE_TRIANGLE, + NT_NODE_INSTANCE, + NT_ANIM_TRACK, + NT_MESH_SYSTEM, + NT_MESH_AABB, + NT_SKELETONS, + NT_ANIMATIONS, + NT_MATERIALS, + NT_MATERIAL, + NT_MESHES, + NT_MESH_COLLISION_REPRESENTATIONS, + NT_MESH_COLLISION_REPRESENTATION, + NT_MESH_COLLISION, + NT_MESH_COLLISION_CONVEX, + NT_LAST + }; + + enum AttributeType + { + AT_NONE, + AT_ASSET_NAME, + AT_ASSET_INFO, + AT_NAME, + AT_COUNT, + AT_TRIANGLE_COUNT, + AT_PARENT, + AT_MATERIAL, + AT_CTYPE, + AT_SEMANTIC, + AT_POSITION, + AT_ORIENTATION, + AT_DURATION, + AT_DTIME, + AT_TRACK_COUNT, + AT_FRAME_COUNT, + AT_HAS_SCALE, + AT_MESH_SYSTEM_VERSION, + AT_MESH_SYSTEM_ASSET_VERSION, + AT_MIN, + AT_MAX, + AT_SCALE, + AT_META_DATA, + AT_SKELETON, + AT_SUBMESH_COUNT, + AT_INFO, + AT_TYPE, + AT_TRANSFORM, + AT_LAST + }; + + class MeshImportEZM : public MeshImporter, public FastXml::Callback + { + public: + MeshImportEZM(void) + { + mType = NT_NONE; + mBone = 0; + mFrameCount = 0; + mDuration = 0; + mTrackCount = 0; + mDtime = 0; + mTrackIndex = 0; + mVertexFlags = 0; + + + mToElement.Add("SceneGraph", NT_SCENE_GRAPH); + mToElement.Add("Mesh", NT_MESH); + mToElement.Add("Animation", NT_ANIMATION); + mToElement.Add("Skeleton", NT_SKELETON); + mToElement.Add("Bone", NT_BONE); + mToElement.Add("MeshSection", NT_MESH_SECTION); + mToElement.Add("VertexBuffer", NT_VERTEX_BUFFER); + mToElement.Add("IndexBuffer", NT_INDEX_BUFFER); + mToElement.Add("NodeTriangle", NT_NODE_TRIANGLE); + mToElement.Add("NodeInstance", NT_NODE_INSTANCE); + mToElement.Add("AnimTrack", NT_ANIM_TRACK); + mToElement.Add("MeshSystem", NT_MESH_SYSTEM); + mToElement.Add("MeshAABB", NT_MESH_AABB); + mToElement.Add("Skeletons", NT_SKELETONS); + mToElement.Add("Animations", NT_ANIMATIONS); + mToElement.Add("Materials", NT_MATERIALS); + mToElement.Add("Material", NT_MATERIAL); + mToElement.Add("Meshes", NT_MESHES); + mToElement.Add("MeshCollisionRepresentations", NT_MESH_COLLISION_REPRESENTATIONS); + mToElement.Add("MeshCollisionRepresentation", NT_MESH_COLLISION_REPRESENTATION); + mToElement.Add("MeshCollision", NT_MESH_COLLISION); + mToElement.Add("MeshCollisionConvex", NT_MESH_COLLISION_CONVEX); + + mToAttribute.Add("name", AT_NAME); + mToAttribute.Add("count", AT_COUNT); + mToAttribute.Add("triangle_count", AT_TRIANGLE_COUNT); + mToAttribute.Add("parent", AT_PARENT); + mToAttribute.Add("material", AT_MATERIAL); + mToAttribute.Add("ctype", AT_CTYPE); + mToAttribute.Add("semantic", AT_SEMANTIC); + mToAttribute.Add("position", AT_POSITION); + mToAttribute.Add("orientation", AT_ORIENTATION); + mToAttribute.Add("duration", AT_DURATION); + mToAttribute.Add("dtime", AT_DTIME); + mToAttribute.Add("trackcount", AT_TRACK_COUNT); + mToAttribute.Add("framecount", AT_FRAME_COUNT); + mToAttribute.Add("has_scale", AT_HAS_SCALE); + mToAttribute.Add("asset_name", AT_ASSET_NAME); + mToAttribute.Add("asset_info", AT_ASSET_INFO); + mToAttribute.Add("mesh_system_version", AT_MESH_SYSTEM_VERSION); + mToAttribute.Add("mesh_system_asset_version", AT_MESH_SYSTEM_ASSET_VERSION); + mToAttribute.Add("min", AT_MIN); + mToAttribute.Add("max", AT_MAX); + mToAttribute.Add("scale", AT_SCALE); + mToAttribute.Add("meta_data", AT_META_DATA); + mToAttribute.Add("skeleton", AT_SKELETON); + mToAttribute.Add("submesh_count", AT_SUBMESH_COUNT); + mToAttribute.Add("info", AT_INFO); + mToAttribute.Add("type", AT_TYPE); + mToAttribute.Add("transform", AT_TRANSFORM); + + mHasScale = false; + mName = 0; + mCount = 0; + mParent = 0; + mCtype = 0; + mSemantic = 0; + mSkeleton = 0; + mBoneIndex = 0; + mIndexBuffer = 0; + mVertexBuffer = 0; + mVertices = NULL; + mVertexCount = 0; + mIndexCount = 0; + mAnimTrack = 0; + mAnimation = 0; + mMeshSystemVersion = 0; + mMeshSystemAssetVersion = 0; + mMeshCollisionRepresentation = 0; + mMeshCollision = 0; + mMeshCollisionConvex = 0; + + } + + virtual ~MeshImportEZM(void) + { + + } + + const MiU8 * getVertex(const MiU8 *src,MeshVertex &v,const char **types,MiI32 tcount) + { + bool firstTexel =true; + + for (MiI32 i=0; i<tcount; i++) + { + const char *type = types[i]; + if ( MESH_IMPORT_STRING::stricmp(type,"position") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mPos[0] = scan[0]; + v.mPos[1] = scan[1]; + v.mPos[2] = scan[2]; + src+=sizeof(MiF32)*3; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"normal") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mNormal[0] = scan[0]; + v.mNormal[1] = scan[1]; + v.mNormal[2] = scan[2]; + src+=sizeof(MiF32)*3; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"color") == 0 ) + { + const MiU32 *scan = (const MiU32 *)src; + v.mColor = scan[0]; + src+=sizeof(MiU32); + } + else if ( MESH_IMPORT_STRING::stricmp(type,"texcoord") == 0 || MESH_IMPORT_STRING::stricmp(type,"texcoord1") == 0 || MESH_IMPORT_STRING::stricmp(type,"texel1") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + if ( firstTexel ) + { + v.mTexel1[0] = scan[0]; + v.mTexel1[1] = scan[1]; + firstTexel =false; + } + else + { + v.mTexel2[0] = scan[0]; + v.mTexel2[1] = scan[1]; + } + src+=sizeof(MiF32)*2; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"texcoord2") == 0 || MESH_IMPORT_STRING::stricmp(type,"texel2") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mTexel2[0] = scan[0]; + v.mTexel2[1] = scan[1]; + src+=sizeof(MiF32)*2; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"texcoord3") == 0 || MESH_IMPORT_STRING::stricmp(type,"texel3") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mTexel3[0] = scan[0]; + v.mTexel3[1] = scan[1]; + src+=sizeof(MiF32)*2; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"texcoord4") == 0 || MESH_IMPORT_STRING::stricmp(type,"texel4") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mTexel4[0] = scan[0]; + v.mTexel4[1] = scan[1]; + src+=sizeof(MiF32)*2; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp1") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp1[0] = scan[0]; + v.mInterp1[1] = scan[1]; + v.mInterp1[2] = scan[2]; + v.mInterp1[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp2") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp2[0] = scan[0]; + v.mInterp2[1] = scan[1]; + v.mInterp2[2] = scan[2]; + v.mInterp2[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp3") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp3[0] = scan[0]; + v.mInterp3[1] = scan[1]; + v.mInterp3[2] = scan[2]; + v.mInterp3[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp4") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp4[0] = scan[0]; + v.mInterp4[1] = scan[1]; + v.mInterp4[2] = scan[2]; + v.mInterp4[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp5") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp5[0] = scan[0]; + v.mInterp5[1] = scan[1]; + v.mInterp5[2] = scan[2]; + v.mInterp5[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp6") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp6[0] = scan[0]; + v.mInterp6[1] = scan[1]; + v.mInterp6[2] = scan[2]; + v.mInterp6[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp7") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp7[0] = scan[0]; + v.mInterp7[1] = scan[1]; + v.mInterp7[2] = scan[2]; + v.mInterp7[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"interp8") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mInterp8[0] = scan[0]; + v.mInterp8[1] = scan[1]; + v.mInterp8[2] = scan[2]; + v.mInterp8[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"tangent") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mTangent[0] = scan[0]; + v.mTangent[1] = scan[1]; + v.mTangent[2] = scan[2]; + src+=sizeof(MiF32)*3; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"binormal") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mBiNormal[0] = scan[0]; + v.mBiNormal[1] = scan[1]; + v.mBiNormal[2] = scan[2]; + src+=sizeof(MiF32)*3; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"blendweights") == 0 || MESH_IMPORT_STRING::stricmp(type,"blendweighting") == 0 || MESH_IMPORT_STRING::stricmp(type,"boneweighting") == 0 ) + { + const MiF32 * scan = (const MiF32 *)src; + v.mWeight[0] = scan[0]; + v.mWeight[1] = scan[1]; + v.mWeight[2] = scan[2]; + v.mWeight[3] = scan[3]; + src+=sizeof(MiF32)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"blendindices") == 0 ) + { + const unsigned short * scan = (const unsigned short *)src; + v.mBone[0] = scan[0]; + v.mBone[1] = scan[1]; + v.mBone[2] = scan[2]; + v.mBone[3] = scan[3]; + if ( v.mWeight[0] == 0 ) + { + v.mBone[0] = 0; + } + if ( v.mWeight[1] == 0 ) + { + v.mBone[1] = 0; + } + if ( v.mWeight[2] == 0 ) + { + v.mBone[2] = 0; + } + if ( v.mWeight[3] == 0 ) + { + v.mBone[3] = 0; + } + + assert( v.mBone[0] < 256 ); + assert( v.mBone[1] < 256 ); + assert( v.mBone[2] < 256 ); + assert( v.mBone[3] < 256 ); + src+=sizeof(unsigned short)*4; + } + else if ( MESH_IMPORT_STRING::stricmp(type,"radius") == 0 ) + { + const MiF32 *scan = (const MiF32 *)src; + v.mRadius = scan[0]; + src+=sizeof(MiF32); + } + else + { + assert(0); + } + + } + return src; + } + + MiU32 validateSemantics(const char **a1,const char **a2,MiI32 count) + { + bool ret = true; + + for (MiI32 i=0; i<count; i++) + { + const char *p = a1[i]; + const char *t = a2[i]; + + if (MESH_IMPORT_STRING::stricmp(t,"position") == 0 || + MESH_IMPORT_STRING::stricmp(t,"normal") == 0 || + MESH_IMPORT_STRING::stricmp(t,"tangent") == 0 || + MESH_IMPORT_STRING::stricmp(t,"binormal") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp1") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp2") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp3") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp4") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp5") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp6") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp7") == 0 || + MESH_IMPORT_STRING::stricmp(t,"interp8") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"fff") != 0 ) + { + ret = false; + break; + } + } + else if ( MESH_IMPORT_STRING::stricmp(t,"color") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"x4") != 0 ) + { + ret = false; + break; + } + } + else if ( MESH_IMPORT_STRING::stricmp(t,"texel1") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texel2") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texel3") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texel4") == 0 || + MESH_IMPORT_STRING::stricmp(t,"tecoord") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texcoord1") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texcoord2") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texcoord3") == 0 || + MESH_IMPORT_STRING::stricmp(t,"texcoord4") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"ff") != 0 ) + { + ret =false; + break; + } + } + else if ( MESH_IMPORT_STRING::stricmp(t,"blendweights") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"ffff") != 0 ) + { + ret = false; + break; + } + } + else if ( MESH_IMPORT_STRING::stricmp(t,"blendindices") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"hhhh") != 0 ) + { + ret = false; + break; + } + } + else if ( MESH_IMPORT_STRING::stricmp(t,"radius") == 0 ) + { + if ( MESH_IMPORT_STRING::stricmp(p,"f") != 0 ) + { + ret = false; + break; + } + } + } + + MiU32 flags = 0; + + if ( ret ) + { + for (MiI32 i=0; i<count; i++) + { + const char *t = a2[i]; + + if ( MESH_IMPORT_STRING::stricmp(t,"position") == 0 ) flags|=MIVF_POSITION; + else if ( MESH_IMPORT_STRING::stricmp(t,"normal") == 0 ) flags|=MIVF_NORMAL; + else if ( MESH_IMPORT_STRING::stricmp(t,"color") == 0 ) flags|=MIVF_COLOR; + else if ( MESH_IMPORT_STRING::stricmp(t,"texel1") == 0 ) flags|=MIVF_TEXEL1; + else if ( MESH_IMPORT_STRING::stricmp(t,"texel2") == 0 ) flags|=MIVF_TEXEL2; + else if ( MESH_IMPORT_STRING::stricmp(t,"texel3") == 0 ) flags|=MIVF_TEXEL3; + else if ( MESH_IMPORT_STRING::stricmp(t,"texel4") == 0 ) flags|=MIVF_TEXEL4; + else if ( MESH_IMPORT_STRING::stricmp(t,"texcoord1") == 0 ) flags|=MIVF_TEXEL1; + else if ( MESH_IMPORT_STRING::stricmp(t,"texcoord2") == 0 ) flags|=MIVF_TEXEL2; + else if ( MESH_IMPORT_STRING::stricmp(t,"texcoord3") == 0 ) flags|=MIVF_TEXEL3; + else if ( MESH_IMPORT_STRING::stricmp(t,"texcoord4") == 0 ) flags|=MIVF_TEXEL4; + else if ( MESH_IMPORT_STRING::stricmp(t,"texcoord") == 0 ) + { + if ( flags & MIVF_TEXEL1 ) + flags|=MIVF_TEXEL2; + else + flags|=MIVF_TEXEL1; + } + else if ( MESH_IMPORT_STRING::stricmp(t,"tangent") == 0) flags|=MIVF_TANGENT; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp1") == 0) flags|=MIVF_INTERP1; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp2") == 0) flags|=MIVF_INTERP2; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp3") == 0) flags|=MIVF_INTERP3; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp4") == 0) flags|=MIVF_INTERP4; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp5") == 0) flags|=MIVF_INTERP5; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp6") == 0) flags|=MIVF_INTERP6; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp7") == 0) flags|=MIVF_INTERP7; + else if ( MESH_IMPORT_STRING::stricmp(t,"interp8") == 0) flags|=MIVF_INTERP8; + else if ( MESH_IMPORT_STRING::stricmp(t,"binormal") == 0 ) flags|=MIVF_BINORMAL; + else if ( MESH_IMPORT_STRING::stricmp(t,"blendweights") == 0 ) flags|=MIVF_BONE_WEIGHTING; + else if ( MESH_IMPORT_STRING::stricmp(t,"blendindices") == 0 ) flags|=MIVF_BONE_WEIGHTING; + else if ( MESH_IMPORT_STRING::stricmp(t,"boneweights") == 0 ) flags|=MIVF_BONE_WEIGHTING; + else if ( MESH_IMPORT_STRING::stricmp(t,"boneindices") == 0 ) flags|=MIVF_BONE_WEIGHTING; + else if ( MESH_IMPORT_STRING::stricmp(t,"radius") == 0 ) flags|=MIVF_RADIUS; + } + } + + return flags; + } + + virtual bool processComment(const char * /*comment*/) // encountered a comment in the XML + { + return true; + } + + // 'element' is the name of the element that is being closed. + // depth is the recursion depth of this element. + // Return true to continue processing the XML file. + // Return false to stop processing the XML file; leaves the read pointer of the stream right after this close tag. + // The bool 'isError' indicates whether processing was stopped due to an error, or intentionally canceled early. + virtual bool processClose(const char * /*element*/,MiU32 /*depth*/,bool &isError) // process the 'close' indicator for a previously encountered element + { + isError = false; + return true; + } + + virtual void * fastxml_malloc(MiU32 size) + { + return MI_ALLOC(size); + } + + virtual void fastxml_free(void *mem) + { + MI_FREE(mem); + } + + + + + + virtual const char * getExtension(MiI32 /*index*/) // report the default file name extension for this mesh type. + { + return ".ezm"; + } + + virtual const char * getDescription(MiI32 /*index*/) + { + return "PhysX Rocket EZ-Mesh format"; + } + + virtual bool importMesh(const char * /*meshName*/,const void *data,MiU32 dlen,MeshImportInterface *callback,const char * /*options*/,MeshImportApplicationResource * /*appResource*/) + { + bool ret = false; + + mCallback = callback; + + if ( data && mCallback ) + { + FastXml *f = createFastXml(this); + MiMemoryBuffer mb(data,dlen); + bool ok = f->processXml(mb,false); + if ( ok ) + { + mCallback->importAssetName(mAssetName.Get(), mAssetInfo.Get()); + ret = true; + } + if ( mAnimation ) + { + mCallback->importAnimation(*mAnimation); + for (MiI32 i=0; i<mAnimation->mTrackCount; i++) + { + MeshAnimTrack *t = mAnimation->mTracks[i]; + MI_FREE(t->mPose); + delete t; + } + MI_FREE(mAnimation->mTracks); + delete mAnimation; + mAnimation = 0; + } + + delete mMeshCollisionRepresentation; + delete mMeshCollision; + delete mMeshCollisionConvex; + mMeshCollisionRepresentation = 0; + mMeshCollision = 0; + mMeshCollisionConvex = 0; + + MI_FREE( mVertexBuffer); + mVertexBuffer = NULL; + MI_FREE(mVertices); + mVertices = NULL; + + + f->release(); + + } + + return ret; + } + + bool isHex(char c) + { + bool ret = false; + if ( c >= '0' && c <= '9' ) + ret = true; + else if ( c >= 'a' && c <= 'f' ) + ret = true; + else if ( c >= 'A' && c <= 'F' ) + ret = true; + return ret; + } + + char getHex(char c) + { + char ret = 0; + if ( c >= '0' && c <= '9' ) + ret = c-'0'; + else if ( c >= 'a' && c <= 'f' ) + ret = (c-'a')+10; + else if ( c >= 'A' && c <= 'F' ) + ret = (c-'A')+10; + return ret; + } + + const char * cleanAttribute(const char *input) + { + static char scratch[1024]; + const char *source = input; + char *dest = scratch; + char *end = &scratch[1024]; + while ( source && *source && dest < end ) + { + if ( *source == '%' && isHex(source[1]) && isHex(source[2])) + { + char a = getHex(source[1]); + char b = getHex(source[2]); + char c = a<<4|b; + *dest++ = c; + source+=3; + } + else + { + *dest++ = *source++; + } + } + + *dest = 0; + return scratch; + } + + void ProcessNode(const char *svalue,MiU32 argc,const char **argv) + { + mType = (NodeType)mToElement.Get(svalue); + switch ( mType ) + { + case NT_MATERIAL: + { + const char *name = getAttribute("name",(MiI32)argc,argv); + const char *meta_data = getAttribute("meta_data",(MiI32)argc,argv); + meta_data = cleanAttribute(meta_data); + mCallback->importMaterial(name,meta_data); + } + break; + case NT_NONE: + break; +#if 0 // TODO TODO + case NT_MESH_COLLISION_REPRESENTATION: + delete mMeshCollisionRepresentation; + mMeshCollisionRepresentation = new MeshCollisionRepresentation; + break; + case NT_MESH_COLLISION: + if ( mMeshCollisionRepresentation ) + { + mCallback->importCollisionRepresentation( mMeshCollisionRepresentation->mName, mMeshCollisionRepresentation->mInfo ); + mCollisionRepName = SGET(mMeshCollisionRepresentation->mName); + delete mMeshCollisionRepresentation; + mMeshCollisionRepresentation = 0; + } + delete mMeshCollision; + mMeshCollision = new MeshCollision; + break; + case NT_MESH_COLLISION_CONVEX: + assert(mMeshCollision); + if ( mMeshCollision ) + { + delete mMeshCollisionConvex; + mMeshCollisionConvex = new MeshCollisionConvex; + MeshCollision *d = static_cast< MeshCollision *>(mMeshCollisionConvex); + *d = *mMeshCollision; + delete mMeshCollision; + mMeshCollision = 0; + } + break; +#endif + case NT_ANIMATION: + if ( mAnimation ) + { + mCallback->importAnimation(*mAnimation); + delete mAnimation; + mAnimation = 0; + } + mName = 0; + mFrameCount = 0; + mDuration = 0; + mTrackCount = 0; + mDtime = 0; + mTrackIndex = 0; + break; + case NT_ANIM_TRACK: + if ( mAnimation == 0 ) + { + if ( mName && mFrameCount && mDuration && mTrackCount && mDtime ) + { + MiI32 framecount = atoi( mFrameCount ); + MiF32 duration = (MiF32) atof( mDuration ); + MiI32 trackcount = atoi(mTrackCount); + MiF32 dtime = (MiF32) atof(mDtime); + if ( trackcount >= 1 && framecount >= 1 ) + { + mAnimation = new MeshAnimation; + mAnimation->mName = mName; + mAnimation->mTrackCount = trackcount; + mAnimation->mFrameCount = framecount; + mAnimation->mDuration = duration; + mAnimation->mDtime = dtime; + mAnimation->mTracks = (MeshAnimTrack **)MI_ALLOC(sizeof(MeshAnimTrack *)*mAnimation->mTrackCount); + for (MiI32 i=0; i<mAnimation->mTrackCount; i++) + { + MeshAnimTrack *track = new MeshAnimTrack; + track->mDtime = mAnimation->mDuration; + track->mFrameCount = mAnimation->mFrameCount; + track->mDuration = mAnimation->mDuration; + track->mPose = (MeshAnimPose *)MI_ALLOC(sizeof(MeshAnimPose)*track->mFrameCount); + mAnimation->mTracks[i] = track; + } + } + } + } + if ( mAnimation ) + { + mAnimTrack = mAnimation->GetTrack(mTrackIndex); + mTrackIndex++; + } + break; + case NT_SKELETON: + { + delete mSkeleton; + mSkeleton = new MeshSkeleton; + } + case NT_BONE: + if ( mSkeleton ) + { + mBone = mSkeleton->GetBonePtr(mBoneIndex); + } + break; + default: + break; + } + } + void ProcessData(const char *svalue) + { + if ( svalue ) + { + switch ( mType ) + { + default: + break; + case NT_ANIM_TRACK: + if ( mAnimTrack ) + { + mAnimTrack->SetName(mStrings.Get(mName).Get()); + MiI32 count = atoi( mCount ); + if ( count == mAnimTrack->GetFrameCount() ) + { + if ( mHasScale ) + { + MiF32 *buff = (MiF32 *) MI_ALLOC(sizeof(MiF32)*10*count); + Asc2Bin(svalue, count, "fff ffff fff", buff ); + for (MiI32 i=0; i<count; i++) + { + MeshAnimPose *p = mAnimTrack->GetPose(i); + const MiF32 *src = &buff[i*10]; + + p->mPos[0] = src[0]; + p->mPos[1] = src[1]; + p->mPos[2] = src[2]; + + p->mQuat[0] = src[3]; + p->mQuat[1] = src[4]; + p->mQuat[2] = src[5]; + p->mQuat[3] = src[6]; + + p->mScale[0] = src[7]; + p->mScale[1] = src[8]; + p->mScale[2] = src[9]; + } + MI_FREE(buff); + } + else + { + MiF32 *buff = (MiF32 *) MI_ALLOC(sizeof(MiF32)*7*count); + Asc2Bin(svalue, count, "fff ffff", buff ); + for (MiI32 i=0; i<count; i++) + { + MeshAnimPose *p = mAnimTrack->GetPose(i); + const MiF32 *src = &buff[i*7]; + + p->mPos[0] = src[0]; + p->mPos[1] = src[1]; + p->mPos[2] = src[2]; + + p->mQuat[0] = src[3]; + p->mQuat[1] = src[4]; + p->mQuat[2] = src[5]; + p->mQuat[3] = src[6]; + + p->mScale[0] = 1; + p->mScale[1] = 1; + p->mScale[2] = 1; + } + MI_FREE(buff); + } + } + } + break; + case NT_NODE_INSTANCE: +#if 0 // TODO TODO + if ( mName ) + { + MiF32 transform[4*4]; + Asc2Bin(svalue, 4, "ffff", transform ); + MeshBone b; + b.SetTransform(transform); + MiF32 pos[3]; + MiF32 quat[3]; + MiF32 scale[3] = { 1, 1, 1 }; + b.ExtractOrientation(quat); + b.GetPos(pos); + mCallback->importMeshInstance(mName,pos,quat,scale); + mName = 0; + } +#endif + break; + case NT_NODE_TRIANGLE: + if ( mCtype && mSemantic ) + { + MiI32 c1,c2; + char scratch1[2048]; + char scratch2[2048]; + MESH_IMPORT_STRING::strlcpy(scratch1,2048,mCtype); + MESH_IMPORT_STRING::strlcpy(scratch2,2048,mSemantic); + const char **a1 = mParser1.GetArglist(scratch1,c1); + const char **a2 = mParser2.GetArglist(scratch2,c2); + if ( c1 > 0 && c2 > 0 && c1 == c2 ) + { + mVertexFlags = validateSemantics(a1,a2,c1); + if ( mVertexFlags ) + { + MeshVertex vtx[3]; + char scratch[1024]; + + const MiU8 *temp = (const MiU8 *)Asc2Bin(svalue, 3, mCtype, scratch ); + + temp = getVertex(temp,vtx[0],a2,c2); + temp = getVertex(temp,vtx[1],a2,c2); + temp = getVertex(temp,vtx[2],a2,c2); + mCallback->importTriangle(mCurrentMesh.Get(),mCurrentMaterial.Get(),mVertexFlags,vtx[0],vtx[1],vtx[2]); + //MI_FREE((void *)temp); + } + } + mCtype = 0; + mSemantic = 0; + } + break; + case NT_VERTEX_BUFFER: + MI_FREE( mVertexBuffer); + MI_FREE(mVertices); + mVertices = 0; + mVertexCount = 0; + mVertexBuffer = 0; + + if ( mCtype && mCount ) + { + mVertexCount = atoi(mCount); + if ( mVertexCount > 0 ) + { + mVertexBuffer = Asc2Bin(svalue, mVertexCount, mCtype, 0 ); + + if ( mVertexBuffer ) + { + + MiI32 c1,c2; + char scratch1[2048]; + char scratch2[2048]; + MESH_IMPORT_STRING::strlcpy(scratch1,2048,mCtype); + MESH_IMPORT_STRING::strlcpy(scratch2,2048,mSemantic); + + const char **a1 = mParser1.GetArglist(scratch1,c1); + const char **a2 = mParser2.GetArglist(scratch2,c2); + + if ( c1 > 0 && c2 > 0 && c1 == c2 ) + { + mVertexFlags = validateSemantics(a1,a2,c1); + if ( mVertexFlags ) + { + mVertices = (MeshVertex *)MI_ALLOC(sizeof(MeshVertex)*mVertexCount); + for (MiI32 i=0; i<mVertexCount; i++) + { + new ( &mVertices[i]) MeshVertex; + } + const MiU8 *scan = (const MiU8 *)mVertexBuffer; + for (MiI32 i=0; i<mVertexCount; i++) + { + scan = getVertex(scan,mVertices[i],a2,c2); + } + } + } + MI_FREE( mVertexBuffer); + mVertexBuffer = 0; + } + + } + mCtype = 0; + mCount = 0; + } + break; + case NT_INDEX_BUFFER: + if ( mCount ) + { + mIndexCount = atoi(mCount); + if ( mIndexCount > 0 ) + { + mIndexBuffer = Asc2Bin(svalue, mIndexCount, "ddd", 0 ); + } + } + + if ( mIndexBuffer && mVertices ) + { +#if 0 // TODO TODO + if ( mMeshCollisionConvex ) + { + MiF32 *vertices = (MiF32 *)MI_ALLOC(sizeof(MiF32)*mVertexCount*3); + MiF32 *dest = vertices; + for (MiI32 i=0; i<mVertexCount; i++) + { + dest[0] = mVertices[i].mPos[0]; + dest[1] = mVertices[i].mPos[1]; + dest[2] = mVertices[i].mPos[2]; + dest+=3; + } + + mCallback->importConvexHull(mCollisionRepName.Get(), + mMeshCollisionConvex->mName, + mMeshCollisionConvex->mTransform, + mVertexCount, + vertices, + mIndexCount, + (const MiU32 *)mIndexBuffer); + + MI_FREE(vertices); + delete mMeshCollisionConvex; + mMeshCollisionConvex = 0; + } + else +#endif + { + mCallback->importIndexedTriangleList(mCurrentMesh.Get(),mCurrentMaterial.Get(),mVertexFlags,(MiU32)mVertexCount,mVertices,(MiU32)mIndexCount,(const MiU32 *)mIndexBuffer ); + } + } + + + MI_FREE( mIndexBuffer); + mIndexBuffer = 0; + mIndexCount = 0; + break; + } + } + } + + void ProcessAttribute(const char *aname, // the name of the attribute + const char *savalue) // the value of the attribute + { + AttributeType attrib = (AttributeType) mToAttribute.Get(aname); + switch ( attrib ) + { + default: + break; + case AT_NONE: + assert(0); + break; + case AT_MESH_SYSTEM_VERSION: + mMeshSystemVersion = atoi(savalue); + break; + case AT_MESH_SYSTEM_ASSET_VERSION: + mMeshSystemAssetVersion = atoi(savalue); + break; + case AT_ASSET_NAME: + mAssetName = mStrings.Get(savalue); + break; + case AT_ASSET_INFO: + mAssetInfo = mStrings.Get(savalue); + break; + case AT_SCALE: + if ( mType == NT_BONE && mBone ) + { + Asc2Bin(savalue,1,"fff", mBone->mScale ); + } + break; + case AT_POSITION: + if ( mType == NT_BONE && mBone ) + { + Asc2Bin(savalue,1,"fff", mBone->mPosition ); + mBoneIndex++; + if ( mBoneIndex == mSkeleton->GetBoneCount() ) + { + mCallback->importSkeleton(*mSkeleton); + delete mSkeleton; + mSkeleton = 0; + mBoneIndex = 0; + } + } + break; + case AT_ORIENTATION: + if ( mType == NT_BONE && mBone ) + { + Asc2Bin(savalue,1,"ffff", mBone->mOrientation ); + } + break; + case AT_HAS_SCALE: + mHasScale = getBool(savalue); + break; + case AT_DURATION: + mDuration = savalue; + break; + + case AT_DTIME: + mDtime = savalue; + break; + + case AT_TRACK_COUNT: + mTrackCount = savalue; + break; + + case AT_FRAME_COUNT: + mFrameCount = savalue; + break; + case AT_INFO: + switch ( mType ) + { + default: + break; + case NT_MESH_COLLISION_REPRESENTATION: + assert(mMeshCollisionRepresentation); + if ( mMeshCollisionRepresentation ) + { + mMeshCollisionRepresentation->mInfo = mStrings.Get(savalue).Get(); + } + break; + } + break; +#if 0 // TODO TODO + case AT_TRANSFORM: + if (mType == NT_MESH_COLLISION ) + { + assert( mMeshCollision ); + if ( mMeshCollision ) + { + Asc2Bin(savalue,4,"ffff", mMeshCollision->mTransform ); + } + } + break; +#endif + case AT_NAME: + mName = savalue; + + switch ( mType ) + { + default: + break; + case NT_MESH_COLLISION: + assert( mMeshCollision ); + if ( mMeshCollision ) + { + mMeshCollision->mName = mStrings.Get(savalue).Get(); + } + break; + case NT_MESH_COLLISION_REPRESENTATION: + assert(mMeshCollisionRepresentation); + if ( mMeshCollisionRepresentation ) + { + mMeshCollisionRepresentation->mName = mStrings.Get(savalue).Get(); + } + break; + case NT_MESH: + mCurrentMesh = mStrings.Get(savalue); + mCallback->importMesh(savalue,0); + break; + case NT_SKELETON: + if ( mSkeleton ) + { + mSkeleton->SetName(mStrings.Get(savalue).Get()); + } + break; + case NT_BONE: + if ( mBone ) + { + mBone->SetName(mStrings.Get(savalue).Get()); + } + break; + } + break; + case AT_TRIANGLE_COUNT: + mCount = savalue; + break; + case AT_COUNT: + mCount = savalue; + if ( mType == NT_SKELETON ) + { + if ( mSkeleton ) + { + MiI32 count = atoi( savalue ); + if ( count > 0 ) + { + MeshBone *bones; + bones = new MeshBone[(MiU32)count]; + mSkeleton->SetBones(count,bones); + mBoneIndex = 0; + } + } + } + break; + case AT_PARENT: + mParent = savalue; + if ( mBone ) + { + for (MiI32 i=0; i<mBoneIndex; i++) + { + const MeshBone &b = mSkeleton->GetBone(i); + if ( strcmp(mParent,b.mName) == 0 ) + { + mBone->mParentIndex = i; + break; + } + } + } + break; + case AT_MATERIAL: + if ( mType == NT_MESH_SECTION ) + { + mCallback->importMaterial(savalue,0); + mCurrentMaterial = mStrings.Get(savalue); + } + break; + case AT_CTYPE: + mCtype = savalue; + break; + case AT_SEMANTIC: + mSemantic = savalue; + break; + } + + } + + virtual bool processElement(const char *elementName, // name of the element + MiI32 argc, // number of attributes + const char **argv, // list of attributes. + const char *elementData, // element data, null if none + MiI32 /*lineno*/) // line number in the source XML file + { + ProcessNode(elementName,(MiU32)argc,argv); + MiI32 acount = argc/2; + for (MiI32 i=0; i<acount; i++) + { + const char *key = argv[i*2]; + const char *value = argv[i*2+1]; + ProcessAttribute(key,value); + } + ProcessData(elementData); + return true; + } + + + + + private: + MeshImportInterface *mCallback; + + bool mHasScale; + + StringTableInt mToElement; // convert string to element enumeration. + StringTableInt mToAttribute; // convert string to attribute enumeration + NodeType mType; + + InPlaceParser mParser1; + InPlaceParser mParser2; + + const char * mName; + const char * mCount; + const char * mParent; + const char * mCtype; + const char * mSemantic; + + const char * mFrameCount; + const char * mDuration; + const char * mTrackCount; + const char * mDtime; + + MiI32 mTrackIndex; + MiI32 mBoneIndex; + MeshBone * mBone; + + MeshAnimation * mAnimation; + MeshAnimTrack * mAnimTrack; + MeshSkeleton * mSkeleton; + MiI32 mVertexCount; + MiI32 mIndexCount; + void * mVertexBuffer; + void * mIndexBuffer; + + MiI32 mMeshSystemVersion; + MiI32 mMeshSystemAssetVersion; + + StringRef mCurrentMesh; + StringRef mCurrentMaterial; + StringDict mStrings; + StringRef mAssetName; + StringRef mAssetInfo; + + MiU32 mVertexFlags; + MeshVertex *mVertices; + + StringRef mCollisionRepName; + MeshCollisionRepresentation *mMeshCollisionRepresentation; + MeshCollision *mMeshCollision; + MeshCollisionConvex *mMeshCollisionConvex; + + + }; + + + MeshImporter * createMeshImportEZM(void) + { + MeshImportEZM *m = new MeshImportEZM; + return static_cast< MeshImporter *>(m); + } + + void releaseMeshImportEZM(MeshImporter *iface) + { + MeshImportEZM *m = static_cast< MeshImportEZM *>(iface); + delete m; + } + +}; // end of namepsace diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.h b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.h new file mode 100644 index 00000000..2fff231c --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#ifndef IMPORT_EZM_H + +#define IMPORT_EZM_H + +#include "MeshImport.h" + +namespace mimp +{ + +MeshImporter * createMeshImportEZM(void); +void releaseMeshImportEZM(MeshImporter *iface); + +}; // end of namespace + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/MeshImportEzm.cpp b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/MeshImportEzm.cpp new file mode 100644 index 00000000..f6565a5f --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/MeshImportEzm/MeshImportEzm.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. +#include <assert.h> +#include "MeshImport.h" +#include "ImportEzm.h" + + +#ifdef WIN32 +#ifdef MESHIMPORTEZM_EXPORTS +#define MESHIMPORTEZM_API __declspec(dllexport) +#else +#define MESHIMPORTEZM_API __declspec(dllimport) +#endif +#else +#define MESHIMPORTEZM_API +#endif + +#ifndef _MSC_VER + +// Other platforms do not have these nice functions +// TODO: we should probably share this with other MeshImporters + +inline void *_aligned_malloc(size_t size, size_t /*alignment*/) +{ + void *memblock = malloc(size); + if( reinterpret_cast<size_t>(memblock) & (16 - 1) ) { + assert( 0 && "malloc result is not 16-byte aligned" ); + free(memblock); + return 0; + } + + return memblock; +} + +inline void _aligned_free(void *memblock) +{ + free(memblock); +} + +#endif + +#pragma warning(disable:4100) + +bool doShutdown(void); + +extern "C" +{ + MESHIMPORTEZM_API mimp::MeshImporter * getInterface(mimp::MiI32 version_number); +}; + +namespace mimp +{ + +class MyMeshImportEzm : public mimp::MeshImporter +{ +public: + MyMeshImportEzm(void) + { + } + + virtual ~MyMeshImportEzm(void) + { + } + + bool shutdown(void) + { + return doShutdown(); + } + + virtual MiI32 getExtensionCount(void) + { + return 2; + } + virtual const char* getExtension(MiI32 index) + { + switch (index) + { + case 0: + return ".ezm"; + case 1: + return ".ezb"; + default: + return NULL; + } + } + + virtual const char * getDescription(MiI32 index) + { + switch (index) + { + case 0: + return "EZ-Mesh format"; + case 1: + return "EZ-Mesh binary format"; + default: + return NULL; + } + } + + + virtual bool importMesh(const char *meshName,const void *data,MiU32 dlen,mimp::MeshImportInterface *callback,const char *options,MeshImportApplicationResource *appResource) + { + bool ret = false; + + MeshImporter *mi = createMeshImportEZM(); + if ( mi ) + { + ret = mi->importMesh(meshName,data,dlen,callback,options,appResource); + releaseMeshImportEZM(mi); + } + + return ret; + } + + virtual const void * saveMeshSystem(MeshSystem * /*ms*/,MiU32 & /*dlen*/,bool /*binary*/) + { + return NULL; + } + + virtual void releaseSavedMeshSystem(const void * /*mem*/) + { + + } +}; + +} // namespace mimp + + + + + + +static mimp::MyMeshImportEzm *gInterface=0; + +extern "C" +{ +#ifdef PLUGINS_EMBEDDED + mimp::MeshImporter * getInterfaceMeshImportEzm(mimp::MiI32 version_number) +#else + MESHIMPORTEZM_API mimp::MeshImporter * getInterface(mimp::MiI32 version_number) +#endif + { + if ( gInterface == 0 && version_number == MESHIMPORT_VERSION ) + { + gInterface = new mimp::MyMeshImportEzm; + } + return static_cast<mimp::MeshImporter *>(gInterface); + }; + +}; // End of namespace PATHPLANNING + +#ifndef PLUGINS_EMBEDDED + + + +bool doShutdown(void) +{ + bool ret = false; + if ( gInterface ) + { + ret = true; + delete gInterface; + gInterface = 0; + } + return ret; +} + + + +#ifdef WIN32 + +#include <windows.h> + +BOOL APIENTRY DllMain( HANDLE , + DWORD ul_reason_for_call, + LPVOID ) +{ + mimp::MiI32 ret = 0; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + ret = 1; + break; + case DLL_THREAD_ATTACH: + ret = 2; + break; + case DLL_THREAD_DETACH: + ret = 3; + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +#endif + +#endif diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiAsc2Bin.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiAsc2Bin.cpp new file mode 100644 index 00000000..c338b5ca --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiAsc2Bin.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> +#include <assert.h> + +#include "MiAsc2Bin.h" + +namespace mimp +{ + +static inline bool IsWhitespace(char c) +{ + if ( c == ' ' || c == 9 || c == 13 || c == 10 || c == ',' ) return true; + return false; +} + + + +static inline const char * SkipWhitespace(const char *str) +{ + if ( str ) + { + while ( *str && IsWhitespace(*str) ) str++; + } + return str; +} + +static char ToLower(char c) +{ + if ( c >= 'A' && c <= 'Z' ) c+=32; + return c; +} + +static inline MiU32 GetHex(MiU8 c) +{ + MiU32 v = 0; + c = (MiU8)ToLower((char)c); + if ( c >= '0' && c <= '9' ) + v = MiU32(c-'0'); + else + { + if ( c >= 'a' && c <= 'f' ) + { + v = MiU32(10 + c-'a'); + } + } + return v; +} + +static inline MiU8 GetHEX1(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + ret = (GetHex((MiU8)foo[0])<<4) | GetHex((MiU8)foo[1]); + + if ( endptr ) + { + *endptr = foo+2; + } + + return (MiU8) ret; +} + + +static inline unsigned short GetHEX2(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + ret = (GetHex((MiU8)foo[0])<<12) | (GetHex((MiU8)foo[1])<<8) | (GetHex((MiU8)foo[2])<<4) | GetHex((MiU8)foo[3]); + + if ( endptr ) + { + *endptr = foo+4; + } + + return (unsigned short) ret; +} + +static inline MiU32 GetHEX4(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + for (MiI32 i=0; i<8; i++) + { + ret = (ret<<4) | GetHex((MiU8)foo[i]); + } + + if ( endptr ) + { + *endptr = foo+8; + } + + return ret; +} + +static inline MiU32 GetHEX(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + while ( *foo ) + { + MiU8 c = (MiU8)ToLower( *foo ); + MiU32 v = 0; + if ( c >= '0' && c <= '9' ) + v = MiU8(c-'0'); + else + { + if ( c >= 'a' && c <= 'f' ) + { + v = MiU8(10 + c-'a'); + } + else + break; + } + ret = (ret<<4)|v; + foo++; + } + + if ( endptr ) *endptr = foo; + + return ret; +} + + + + +#define MAXNUM 32 + +static inline MiF32 GetFloatValue(const char *str,const char **next) +{ + MiF32 ret = 0; + + if ( next ) *next = 0; + + str = SkipWhitespace(str); + + char dest[MAXNUM]; + char *dst = dest; + const char *hex = 0; + + for (MiI32 i=0; i<(MAXNUM-1); i++) + { + char c = *str; + if ( c == 0 || IsWhitespace(c) ) + { + if ( next ) *next = str; + break; + } + else if ( c == '$' ) + { + hex = str+1; + } + *dst++ = ToLower(c); + str++; + } + + *dst = 0; + + if ( hex ) + { + MiU32 iv = GetHEX(hex,0); + MiF32 *v = (MiF32 *)&iv; + ret = *v; + } + else if ( dest[0] == 'f' ) + { + if ( strcmp(dest,"fltmax") == 0 || strcmp(dest,"fmax") == 0 ) + { + ret = FLT_MAX; + } + else if ( strcmp(dest,"fltmin") == 0 || strcmp(dest,"fmin") == 0 ) + { + ret = FLT_MIN; + } + } + else if ( dest[0] == 't' ) // t or 'true' is treated as the value '1'. + { + ret = 1; + } + else + { + ret = (MiF32)atof(dest); + } + return ret; +} + +static inline MiI32 GetIntValue(const char *str,const char **next) +{ + MiI32 ret = 0; + + if ( next ) *next = 0; + + str = SkipWhitespace(str); + + char dest[MAXNUM]; + char *dst = dest; + + for (MiI32 i=0; i<(MAXNUM-1); i++) + { + char c = *str; + if ( c == 0 || IsWhitespace(c) ) + { + if ( next ) *next = str; + break; + } + *dst++ = c; + str++; + } + + *dst = 0; + + ret = atoi(dest); + + return ret; +} + + + +#ifdef PLAYSTATION3 +#include <ctype.h> // for tolower() +#endif + +enum Atype { AT_FLOAT, AT_INT, AT_CHAR, AT_BYTE, AT_SHORT, AT_STR, AT_HEX1, AT_HEX2, AT_HEX4, AT_LAST }; + +#define MAXARG 64 + +#if 0 +void TestAsc2bin(void) +{ + Asc2Bin("1 2 A 3 4 Foo AB ABCD FFEDFDED",1,"f d c b h p x1 x2 x4", 0); +} +#endif + +void * Asc2Bin(const char *source,const MiI32 count,const char *spec,void *dest) +{ + + MiI32 cnt = 0; + MiI32 size = 0; + + Atype types[MAXARG]; + + const char *ctype = spec; + + while ( *ctype ) + { + switch ( ToLower(*ctype) ) + { + case 'f': size+= sizeof(MiF32); types[cnt] = AT_FLOAT; cnt++; break; + case 'd': size+= sizeof(MiI32); types[cnt] = AT_INT; cnt++; break; + case 'c': size+=sizeof(char); types[cnt] = AT_CHAR; cnt++; break; + case 'b': size+=sizeof(char); types[cnt] = AT_BYTE; cnt++; break; + case 'h': size+=sizeof(short); types[cnt] = AT_SHORT; cnt++; break; + case 'p': size+=sizeof(const char *); types[cnt] = AT_STR; cnt++; break; + case 'x': + { + Atype type = AT_HEX4; + MiI32 sz = 4; + switch ( ctype[1] ) + { + case '1': type = AT_HEX1; sz = 1; ctype++; break; + case '2': type = AT_HEX2; sz = 2; ctype++; break; + case '4': type = AT_HEX4; sz = 4; ctype++; break; + } + types[cnt] = type; + size+=sz; + cnt++; + } + break; + } + if ( cnt == MAXARG ) return 0; // over flowed the maximum specification! + ctype++; + } + + bool myalloc = false; + + if ( dest == 0 ) + { + myalloc = true; + dest = (char *) MI_ALLOC(sizeof(char)*count*size); + } + + // ok...ready to parse lovely data.... + memset(dest,0,size_t(count*size)); // zero out memory + + char *dst = (char *) dest; // where we are storing the results + for (MiI32 i=0; i<count; i++) + { + for (MiI32 j=0; j<cnt; j++) + { + source = SkipWhitespace(source); // skip white spaces. + + if (source == NULL || *source == 0 ) // we hit the end of the input data before we successfully parsed all input! + { + if ( myalloc ) + { + MI_FREE(dest); + } + return 0; + } + + switch ( types[j] ) + { + case AT_FLOAT: + { + MiF32 *v = (MiF32 *) dst; + *v = GetFloatValue(source,&source); + dst+=sizeof(MiF32); + } + break; + case AT_INT: + { + MiI32 *v = (MiI32 *) dst; + *v = GetIntValue( source, &source ); + dst+=sizeof(MiI32); + } + break; + case AT_CHAR: + { + *dst++ = *source++; + } + break; + case AT_BYTE: + { + char *v = (char *) dst; + *v = (char)GetIntValue(source,&source); + dst+=sizeof(char); + } + break; + case AT_SHORT: + { + short *v = (short *) dst; + *v = (short)(unsigned short)GetIntValue( source,&source ); + dst+=sizeof(short); + } + break; + case AT_STR: + { + const char **ptr = (const char **) dst; + *ptr = source; + dst+=sizeof(const char *); + while ( *source && !IsWhitespace(*source) ) source++; + } + break; + case AT_HEX1: + { + MiU32 hex = GetHEX1(source,&source); + MiU8 *v = (MiU8 *) dst; + *v = (MiU8)hex; + dst+=sizeof(MiU8); + } + break; + case AT_HEX2: + { + MiU32 hex = GetHEX2(source,&source); + unsigned short *v = (unsigned short *) dst; + *v = (unsigned short)hex; + dst+=sizeof(unsigned short); + } + break; + case AT_HEX4: + { + MiU32 hex = GetHEX4(source,&source); + MiU32 *v = (MiU32 *) dst; + *v = hex; + dst+=sizeof(MiU32); + } + break; + case AT_LAST: // Make compiler happy + break; + } + } + } + + return dest; +} + +}; diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiFastXML.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiFastXML.cpp new file mode 100644 index 00000000..856c314a --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiFastXML.cpp @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include "MiFastXml.h" +#include <stdio.h> +#include <string.h> +#include <new> + +#define DEBUG_LOG 0 + +namespace mimp +{ + +#define MIN_CLOSE_COUNT 2 +#define DEFAULT_READ_BUFFER_SIZE (16*1024) + +#define DEBUG_ASSERT(x) //MI_ASSERT(x) +#define DEBUG_ALWAYS_ASSERT() DEBUG_ASSERT(0) + +#define U(c) ((unsigned char)(c)) + +class MyFastXml : public FastXml +{ +public: + enum CharType + { + CT_DATA, + CT_EOF, + CT_SOFT, + CT_END_OF_ELEMENT, // either a forward slash or a greater than symbol + CT_END_OF_LINE, + }; + + MyFastXml(Callback *c) + { + mStreamFromMemory = true; + mCallback = c; + memset(mTypes, CT_DATA, sizeof(mTypes)); + mTypes[0] = CT_EOF; + mTypes[U(' ')] = mTypes[U('\t')] = CT_SOFT; + mTypes[U('/')] = mTypes[U('>')] = mTypes[U('?')] = CT_END_OF_ELEMENT; + mTypes[U('\n')] = mTypes[U('\r')] = CT_END_OF_LINE; + mError = 0; + mStackIndex = 0; + mFileBuf = NULL; + mReadBufferEnd = NULL; + mReadBuffer = NULL; + mReadBufferSize = DEFAULT_READ_BUFFER_SIZE; + mOpenCount = 0; + mLastReadLoc = 0; + for (MiU32 i=0; i<(MAX_STACK+1); i++) + { + mStack[i] = NULL; + mStackAllocated[i] = false; + } +#if DEBUG_LOG + mFph = fopen("xml_log.txt","wb"); +#endif + } + + virtual ~MyFastXml(void) + { + releaseMemory(); +#if DEBUG_LOG + if ( mFph ) + { + fclose(mFph); + } +#endif + } + +#if DEBUG_LOG + void indent(void) + { + if ( mFph ) + { + for (MiU32 i=0; i<mStackIndex; i++) + { + fprintf(mFph,"\t"); + fflush(mFph); + } + } + } +#endif + + char *processClose(char c, const char *element, char *scan, MiI32 argc, const char **argv, FastXml::Callback *iface,bool &isError) + { + isError = true; // by default, if we return null it's due to an error. + if ( c == '/' || c == '?' ) + { + char *slash = (char *)strchr(element, c); + if( slash ) + *slash = 0; + + if( c == '?' && strcmp(element, "xml") == 0 ) + { + if( !iface->processXmlDeclaration(argc/2, argv, 0, mLineNo) ) + return NULL; + } + else + { +#if DEBUG_LOG + if ( mFph ) + { + indent(); + fprintf(mFph,"<%s ",element); + for (MiI32 i=0; i<argc/2; i++) + { + fprintf(mFph," %s=\"%s\"", argv[i*2], argv[i*2+1] ); + } + fprintf(mFph,">\r\n"); + fflush(mFph); + } +#endif + + if ( !iface->processElement(element, argc, argv, 0, mLineNo) ) + { + mError = "User aborted the parsing process"; + return NULL; + } + + pushElement(element); + + const char *close = popElement(); +#if DEBUG_LOG + indent(); + fprintf(mFph,"</%s>\r\n", close ); + fflush(mFph); +#endif + if( !iface->processClose(close,mStackIndex,isError) ) + { + return NULL; + } + } + + if ( !slash ) + ++scan; + } + else + { + scan = skipNextData(scan); + char *data = scan; // this is the data portion of the element, only copies memory if we encounter line feeds + char *dest_data = 0; + while ( *scan && *scan != '<' ) + { + if ( mTypes[U(*scan)] == CT_END_OF_LINE ) + { + if ( *scan == '\r' ) mLineNo++; + dest_data = scan; + *dest_data++ = ' '; // replace the linefeed with a space... + scan = skipNextData(scan); + while ( *scan && *scan != '<' ) + { + if ( mTypes[U(*scan)] == CT_END_OF_LINE ) + { + if ( *scan == '\r' ) mLineNo++; + *dest_data++ = ' '; // replace the linefeed with a space... + scan = skipNextData(scan); + } + else + { + *dest_data++ = *scan++; + } + } + break; + } + else + ++scan; + } + + if ( *scan == '<' ) + { + if ( scan[1] != '/' ) + { + MI_ASSERT(mOpenCount>0); + mOpenCount--; + } + if ( dest_data ) + { + *dest_data = 0; + } + else + { + *scan = 0; + } + + scan++; // skip it.. + + if ( *data == 0 ) data = 0; + +#if DEBUG_LOG + if ( mFph ) + { + indent(); + fprintf(mFph,"<%s ",element); + for (MiI32 i=0; i<argc/2; i++) + { + fprintf(mFph," %s=\"%s\"", argv[i*2], argv[i*2+1] ); + } + fprintf(mFph,">\r\n"); + if ( data ) + { + indent(); + fprintf(mFph,"%s\r\n", data ); + } + fflush(mFph); + } +#endif + if ( !iface->processElement(element, argc, argv, data, mLineNo) ) + { + mError = "User aborted the parsing process"; + return 0; + } + + pushElement(element); + + // check for the comment use case... + if ( scan[0] == '!' && scan[1] == '-' && scan[2] == '-' ) + { + scan+=3; + while ( *scan && *scan == ' ' ) + ++scan; + + char *comment = scan; + char *comment_end = strstr(scan, "-->"); + if ( comment_end ) + { + *comment_end = 0; + scan = comment_end+3; + if( !iface->processComment(comment) ) + { + mError = "User aborted the parsing process"; + return 0; + } + } + } + else if ( *scan == '/' ) + { + scan = processClose(scan, iface, isError); + if( scan == NULL ) + { + return NULL; + } + } + } + else + { + mError = "Data portion of an element wasn't terminated properly"; + return NULL; + } + } + + if ( mOpenCount < MIN_CLOSE_COUNT ) + { + scan = readData(scan); + } + + return scan; + } + + char *processClose(char *scan, FastXml::Callback *iface,bool &isError) + { + const char *start = popElement(), *close = start; + if( scan[1] != '>') + { + scan++; + close = scan; + while ( *scan && *scan != '>' ) scan++; + *scan = 0; + } + + if( 0 != strcmp(start, close) ) + { + mError = "Open and closing tags do not match"; + return 0; + } +#if DEBUG_LOG + indent(); + fprintf(mFph,"</%s>\r\n", close ); + fflush(mFph); +#endif + if( !iface->processClose(close,mStackIndex,isError) ) + { + // we need to set the read pointer! + MiU32 offset = (MiU32)(mReadBufferEnd-scan)-1; + MiU32 readLoc = mLastReadLoc-offset; + mFileBuf->seekRead(readLoc); + return NULL; + } + ++scan; + + return scan; + } + + virtual bool processXml(MiFileBuf &fileBuf,bool streamFromMemory) + { + releaseMemory(); + mFileBuf = &fileBuf; + mStreamFromMemory = streamFromMemory; + return processXml(mCallback); + } + + // if we have finished processing the data we had pending.. + char * readData(char *scan) + { + for (MiU32 i=0; i<(mStackIndex+1); i++) + { + if ( !mStackAllocated[i] ) + { + const char *text = mStack[i]; + if ( text ) + { + MiU32 tlen = (MiU32)strlen(text); + mStack[i] = (const char *)mCallback->fastxml_malloc(tlen+1); + memcpy((void *)mStack[i],text,tlen+1); + mStackAllocated[i] = true; + + } + } + } + + if ( !mStreamFromMemory ) + { + if ( scan == NULL ) + { + MiU32 seekLoc = mFileBuf->tellRead(); + mReadBufferSize = (mFileBuf->getFileLength()-seekLoc); + } + else + { + return scan; + } + } + + if ( mReadBuffer == NULL ) + { + mReadBuffer = (char *)mCallback->fastxml_malloc(mReadBufferSize+1); + } + MiU32 offset = 0; + MiU32 readLen = mReadBufferSize; + + if ( scan ) + { + offset = (MiU32)(scan - mReadBuffer ); + MiU32 copyLen = mReadBufferSize-offset; + if ( copyLen ) + { + MI_ASSERT(scan >= mReadBuffer); + memmove(mReadBuffer,scan,copyLen); + mReadBuffer[copyLen] = 0; + readLen = mReadBufferSize - copyLen; + } + offset = copyLen; + } + + MiU32 readCount = mFileBuf->read(&mReadBuffer[offset],readLen); + + while ( readCount > 0 ) + { + + mReadBuffer[readCount+offset] = 0; // end of string terminator... + mReadBufferEnd = &mReadBuffer[readCount+offset]; + + const char *scan = &mReadBuffer[offset]; + while ( *scan ) + { + if ( *scan == '<' && scan[1] != '/' ) + { + mOpenCount++; + } + scan++; + } + + if ( mOpenCount < MIN_CLOSE_COUNT ) + { + MiU32 oldSize = (MiU32)(mReadBufferEnd-mReadBuffer); + mReadBufferSize = mReadBufferSize*2; + char *oldReadBuffer = mReadBuffer; + mReadBuffer = (char *)mCallback->fastxml_malloc(mReadBufferSize+1); + memcpy(mReadBuffer,oldReadBuffer,oldSize); + mCallback->fastxml_free(oldReadBuffer); + offset = oldSize; + MiU32 readSize = mReadBufferSize - oldSize; + readCount = mFileBuf->read(&mReadBuffer[offset],readSize); + if ( readCount == 0 ) + break; + } + else + { + break; + } + } + mLastReadLoc = mFileBuf->tellRead(); + + return mReadBuffer; + } + + bool processXml(FastXml::Callback *iface) + { + bool ret = true; + + const int MAX_ATTRIBUTE = 2048; // can't imagine having more than 2,048 attributes in a single element right? + + mLineNo = 1; + + char *element, *scan = readData(0); + + while( *scan ) + { + + scan = skipNextData(scan); + + if( *scan == 0 ) break; + + if( *scan == '<' ) + { + + if ( scan[1] != '/' ) + { + MI_ASSERT(mOpenCount>0); + mOpenCount--; + } + scan++; + + if( *scan == '?' ) //Allow xml declarations + { + scan++; + } + else if ( scan[0] == '!' && scan[1] == '-' && scan[2] == '-' ) + { + scan+=3; + while ( *scan && *scan == ' ' ) + scan++; + char *comment = scan, *comment_end = strstr(scan, "-->"); + if ( comment_end ) + { + *comment_end = 0; + scan = comment_end+3; + if( !iface->processComment(comment) ) + { + mError = "User aborted the parsing process"; + DEBUG_ALWAYS_ASSERT(); + return false; + } + } + continue; + } + else if ( scan[0] == '!' ) //Allow doctype + { + scan++; + + //DOCTYPE syntax differs from usual XML so we parse it here + + //Read DOCTYPE + const char *tag = "DOCTYPE"; + if( !strstr(scan, tag) ) + { + mError = "Invalid DOCTYPE"; + DEBUG_ALWAYS_ASSERT(); + return false; + } + + scan += strlen(tag); + + //Skip whites + while( CT_SOFT == mTypes[U(*scan)] ) + ++scan; + + //Read rootElement + const char *rootElement = scan; + while( CT_DATA == mTypes[U(*scan)] ) + ++scan; + + char *endRootElement = scan; + + //TODO: read remaining fields (fpi, uri, etc.) + while( CT_END_OF_ELEMENT != mTypes[U(*scan++)] ); + + *endRootElement = 0; + + if( !iface->processDoctype(rootElement, 0, 0, 0) ) + { + mError = "User aborted the parsing process"; + DEBUG_ALWAYS_ASSERT(); + return false; + } + + continue; //Restart loop + } + } + + + if( *scan == '/' ) + { + bool isError; + scan = processClose(scan, iface, isError); + if( !scan ) + { + if ( isError ) + { + DEBUG_ALWAYS_ASSERT(); + mError = "User aborted the parsing process"; + } + return !isError; + } + } + else + { + if( *scan == '?' ) + scan++; + element = scan; + MiI32 argc = 0; + const char *argv[MAX_ATTRIBUTE]; + bool close; + scan = nextSoftOrClose(scan, close); + if( close ) + { + char c = *(scan-1); + if ( c != '?' && c != '/' ) + { + c = '>'; + } + *scan++ = 0; + bool isError; + scan = processClose(c, element, scan, argc, argv, iface, isError); + if ( !scan ) + { + if ( isError ) + { + DEBUG_ALWAYS_ASSERT(); + mError = "User aborted the parsing process"; + } + return !isError; + } + } + else + { + if ( *scan == 0 ) + { + return ret; + } + + *scan = 0; // place a zero byte to indicate the end of the element name... + scan++; + + while ( *scan ) + { + scan = skipNextData(scan); // advance past any soft seperators (tab or space) + + if ( mTypes[U(*scan)] == CT_END_OF_ELEMENT ) + { + char c = *scan++; + if( '?' == c ) + { + if( '>' != *scan ) //?> + { + DEBUG_ALWAYS_ASSERT(); + return false; + } + + scan++; + } + bool isError; + scan = processClose(c, element, scan, argc, argv, iface, isError); + if ( !scan ) + { + if ( isError ) + { + DEBUG_ALWAYS_ASSERT(); + mError = "User aborted the parsing process"; + } + return !isError; + } + break; + } + else + { + if( argc >= MAX_ATTRIBUTE ) + { + DEBUG_ALWAYS_ASSERT(); + mError = "encountered too many attributes"; + return false; + } + argv[argc] = scan; + scan = nextSep(scan); // scan up to a space, or an equal + if( *scan ) + { + if( *scan != '=' ) + { + *scan = 0; + scan++; + while ( *scan && *scan != '=' ) scan++; + if ( *scan == '=' ) scan++; + } + else + { + *scan=0; + scan++; + } + + if( *scan ) // if not eof... + { + scan = skipNextData(scan); + if( *scan == '"' ) + { + scan++; + argc++; + argv[argc] = scan; + argc++; + while ( *scan && *scan != 34 ) scan++; + if( *scan == '"' ) + { + *scan = 0; + scan++; + } + else + { + DEBUG_ALWAYS_ASSERT(); + mError = "Failed to find closing quote for attribute"; + return false; + } + } + else + { + //mError = "Expected quote to begin attribute"; + //return false; + // PH: let's try to have a more graceful fallback + argc--; + while(*scan != '/' && *scan != '>' && *scan != 0) + scan++; + } + } + } //if( *scan ) + } //if ( mTypes[*scan] + } //if( close ) + } //if( *scan == '/' + } //while( *scan ) + } + + if( mStackIndex ) + { + DEBUG_ALWAYS_ASSERT(); + mError = "Invalid file format"; + return false; + } + + return ret; + } + + const char *getError(MiI32 &lineno) + { + const char *ret = mError; + lineno = mLineNo; + mError = 0; + return ret; + } + + virtual void release(void) + { + Callback *c = mCallback; // get the user allocator interface + MyFastXml *f = this; // cast the this pointer + f->~MyFastXml(); // explicitely invoke the destructor for this class + c->fastxml_free(f); // now free up the memory associated with it. + } + +private: + + MI_INLINE void releaseMemory(void) + { + mFileBuf = NULL; + mCallback->fastxml_free(mReadBuffer); + mReadBuffer = NULL; + mLastReadLoc = 0; + mStackIndex = 0; + mReadBufferEnd = NULL; + mOpenCount = 0; + mError = NULL; + for (MiU32 i=0; i<(mStackIndex+1); i++) + { + if ( mStackAllocated[i] ) + { + mCallback->fastxml_free((void *)mStack[i]); + mStackAllocated[i] = false; + } + mStack[i] = NULL; + } + } + + MI_INLINE char *nextSoft(char *scan) + { + while ( *scan && mTypes[U(*scan)] != CT_SOFT ) scan++; + return scan; + } + + MI_INLINE char *nextSoftOrClose(char *scan, bool &close) + { + while ( *scan && mTypes[U(*scan)] != CT_SOFT && *scan != '>' ) scan++; + close = *scan == '>'; + return scan; + } + + MI_INLINE char *nextSep(char *scan) + { + while ( *scan && mTypes[U(*scan)] != CT_SOFT && *scan != '=' ) scan++; + return scan; + } + + MI_INLINE char *skipNextData(char *scan) + { + // while we have data, and we encounter soft seperators or line feeds... + while ( (*scan && mTypes[U(*scan)] == CT_SOFT) || mTypes[U(*scan)] == CT_END_OF_LINE ) + { + if ( *scan == '\n' ) mLineNo++; + scan++; + } + return scan; + } + + void pushElement(const char *element) + { + MI_ASSERT( mStackIndex < MAX_STACK ); + if( mStackIndex < MAX_STACK ) + { + if ( mStackAllocated[mStackIndex] ) + { + mCallback->fastxml_free((void *)mStack[mStackIndex]); + mStackAllocated[mStackIndex] = false; + } + mStack[mStackIndex++] = element; + } + } + + const char *popElement(void) + { + MI_ASSERT(mStackIndex>0); + if ( mStackAllocated[mStackIndex] ) + { + mCallback->fastxml_free((void*)mStack[mStackIndex]); + mStackAllocated[mStackIndex] = false; + } + mStack[mStackIndex] = NULL; + return mStackIndex ? mStack[--mStackIndex] : NULL; + } + + static const unsigned MAX_STACK = 2048; + + char mTypes[256]; + + MiFileBuf *mFileBuf; + + char *mReadBuffer; + char *mReadBufferEnd; + + MiU32 mOpenCount; + MiU32 mReadBufferSize; + MiU32 mLastReadLoc; + + MiI32 mLineNo; + const char *mError; + MiU32 mStackIndex; + const char *mStack[MAX_STACK+1]; + bool mStreamFromMemory; + bool mStackAllocated[MAX_STACK+1]; + Callback *mCallback; +#if DEBUG_LOG + FILE *mFph; +#endif +}; + +const char *getAttribute(const char *attr, MiI32 argc, const char **argv) +{ + MiI32 count = argc/2; + for(MiI32 i = 0; i < count; ++i) + { + const char *key = argv[i*2], *value = argv[i*2+1]; + if( strcmp(key, attr) == 0 ) + return value; + } + + return 0; +} + +FastXml * createFastXml(FastXml::Callback *iface) +{ + MyFastXml *m = (MyFastXml *)iface->fastxml_malloc(sizeof(MyFastXml)); + if ( m ) + { + new ( m ) MyFastXml(iface); + } + return static_cast< FastXml *>(m); +} + +} // end of namespace diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiFileInterface.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiFileInterface.cpp new file mode 100644 index 00000000..91835972 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiFileInterface.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "MiPlatformConfig.h" +#include "MiFileInterface.h" + +#pragma warning(disable:4267) + +/* + * Copyright 2009-2011 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. Users and possessors of this source code + * are hereby granted a nonexclusive, royalty-free license to use this code + * in individual and commercial software. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + + +//******************************************************************************************** +//*** +//*** A wrapper interface for standard FILE IO services that provides support to read and +//** write 'files' to and from a buffer in memory. +//*** +//******************************************************************************************** + + + +#pragma warning(disable:4996) // Disabling stupid .NET deprecated warning. + +#define DEFAULT_BUFFER_SIZE 8192 +#define BUFFER_GROW_SIZE 1000000 // grow in 1 MB chunks + +namespace mimp +{ + +class MemoryBlock : public MeshImportAllocated +{ +public: + MemoryBlock(size_t size) + { + mNextBlock = 0; + mMemory = (char *)MI_ALLOC(size); + mSize = size; + mLen = 0; + } + + ~MemoryBlock(void) + { + MI_FREE(mMemory); + } + + const char * write(const char *mem,size_t len,size_t &remaining) + { + const char *ret = 0; + + if ( (len+mLen) <= mSize ) + { + char *dest = &mMemory[mLen]; + memcpy(dest,mem,len); + mLen+=len; + remaining = 0; + } + else + { + MiU32 slen = mSize-mLen; + if ( slen ) + { + char *dest = &mMemory[mLen]; + memcpy(dest,mem,slen); + mLen+=slen; + } + ret = mem+slen; + remaining = len-slen; + MI_ASSERT( remaining != 0 ); + } + return ret; + } + + char * getData(char *dest) + { + memcpy(dest,mMemory,mLen); + dest+=mLen; + return dest; + } + + MemoryBlock *mNextBlock; + char *mMemory; + MiU32 mLen; + MiU32 mSize; + +}; + +class _FILE_INTERFACE : public MeshImportAllocated +{ +public: + _FILE_INTERFACE(const char *fname,const char *spec,void *mem,size_t len) + { + mHeadBlock = 0; + mTailBlock = 0; + mMyAlloc = false; + mRead = true; // default is read access. + mFph = 0; + mData = (char *) mem; + mLen = len; + mLoc = 0; + + if ( spec && MESH_IMPORT_STRING::stricmp(spec,"wmem") == 0 ) + { + mRead = false; + if ( mem == 0 || len == 0 ) + { + mHeadBlock = MI_NEW(MemoryBlock)(DEFAULT_BUFFER_SIZE); + mTailBlock = mHeadBlock; + mData = 0; + mLen = 0; + mMyAlloc = true; + } + } + + if ( mData == 0 && mHeadBlock == 0 ) + { + mFph = fopen(fname,spec); + } + + strncpy(mName,fname,512); + } + + ~_FILE_INTERFACE(void) + { + if ( mMyAlloc ) + { + MI_FREE(mData); + + MemoryBlock *mb = mHeadBlock; + while ( mb ) + { + MemoryBlock *next = mb->mNextBlock; + delete mb; + mb = next; + } + + } + if ( mFph ) + { + fclose(mFph); + } + } + + size_t read(char *data,size_t size) + { + size_t ret = 0; + if ( (mLoc+size) <= mLen ) + { + memcpy(data, &mData[mLoc], size ); + mLoc+=size; + ret = 1; + } + return ret; + } + + void validateLen(void) + { + if ( mHeadBlock ) + { + MiU32 slen = 0; + + MemoryBlock *mb = mHeadBlock; + while ( mb ) + { + slen+=mb->mLen; + mb = mb->mNextBlock; + } + MI_ASSERT( slen == mLoc ); + } + } + + size_t write(const char *data,size_t size) + { + size_t ret = 0; + + if ( mMyAlloc ) + { +#ifdef _DEBUG + validateLen(); +#endif + size_t remaining; + data = mTailBlock->write(data,size,remaining); + while ( data ) + { + size_t _size = remaining; + MemoryBlock *block = MI_NEW(MemoryBlock)(BUFFER_GROW_SIZE); + mTailBlock->mNextBlock = block; + mTailBlock = block; + data = mTailBlock->write(data,_size,remaining); + } + mLoc+=size; +#ifdef _DEBUG + validateLen(); +#endif + ret = 1; + } + else + { + if ( (mLoc+size) <= mLen ) + { + memcpy(&mData[mLoc],data,size); + mLoc+=size; + ret = 1; + } + } + return ret; + } + + size_t read(void *buffer,size_t size,size_t count) + { + size_t ret = 0; + if ( mFph ) + { + ret = fread(buffer,size,count,mFph); + } + else + { + char *data = (char *)buffer; + for (size_t i=0; i<count; i++) + { + if ( (mLoc+size) <= mLen ) + { + read(data,size); + data+=size; + ret++; + } + else + { + break; + } + } + } + return ret; + } + + size_t write(const void *buffer,size_t size,size_t count) + { + size_t ret = 0; + + if ( mFph ) + { + ret = fwrite(buffer,size,count,mFph); + } + else + { + const char *data = (const char *)buffer; + for (size_t i=0; i<count; i++) + { + if ( write(data,size) ) + { + data+=size; + ret++; + } + else + { + break; + } + } + } + return ret; + } + + size_t writeString(const char *str) + { + size_t ret = 0; + if ( str ) + { + size_t len = strlen(str); + ret = write(str,len, 1 ); + } + return ret; + } + + + size_t flush(void) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)fflush(mFph); + } + return ret; + } + + + size_t seek(size_t loc,size_t mode) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)fseek(mFph,(long)loc,(int)mode); + } + else + { + if ( mode == SEEK_SET ) + { + if ( loc <= mLen ) + { + mLoc = loc; + ret = 1; + } + } + else if ( mode == SEEK_END ) + { + mLoc = mLen; + } + else + { + MI_ALWAYS_ASSERT(); + } + } + return ret; + } + + size_t tell(void) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)ftell(mFph); + } + else + { + ret = mLoc; + } + return ret; + } + + size_t myputc(char c) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)fputc(c,mFph); + } + else + { + ret = write(&c,1); + } + return ret; + } + + size_t eof(void) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)feof(mFph); + } + else + { + if ( mLoc >= mLen ) + ret = 1; + } + return ret; + } + + size_t error(void) + { + size_t ret = 0; + if ( mFph ) + { + ret = (size_t)ferror(mFph); + } + return ret; + } + + void * getMemBuffer(size_t &outputLength) + { + outputLength = mLoc; + + if ( mHeadBlock && mLoc > 0 ) + { + MI_ASSERT(mData==0); + mData = (char *)MI_ALLOC(mLoc); + char *dest = mData; + MemoryBlock *mb = mHeadBlock; + while ( mb ) + { + dest = mb->getData(dest); + MemoryBlock *next = mb->mNextBlock; + delete mb; + mb = next; + } + + mHeadBlock = 0; + mTailBlock = 0; + } + return mData; + } + + void myclearerr(void) + { + if ( mFph ) + { + clearerr(mFph); + } + } + + FILE *mFph; + char *mData; + size_t mLen; + size_t mLoc; + bool mRead; + char mName[512]; + bool mMyAlloc; + MemoryBlock *mHeadBlock; + MemoryBlock *mTailBlock; + +}; + +FILE_INTERFACE * fi_fopen(const char *fname,const char *spec,void *mem,size_t len) +{ + _FILE_INTERFACE *ret = 0; + + ret = MI_NEW(_FILE_INTERFACE)(fname,spec,mem,len); + + if ( mem == 0 && ret->mData == 0 && ret->mHeadBlock == 0 ) + { + if ( ret->mFph == 0 ) + { + delete ret; + ret = 0; + } + } + + return (FILE_INTERFACE *)ret; +} + +size_t fi_fclose(FILE_INTERFACE *_file) +{ + size_t ret = 0; + + if ( _file ) + { + _FILE_INTERFACE *file = (_FILE_INTERFACE *)_file; + delete file; + } + return ret; +} + +void fi_clearerr(FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + if ( fph ) + { + fph->myclearerr(); + } +} + +size_t fi_fread(void *buffer,size_t size,size_t count,FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->read(buffer,size,count); + } + return ret; +} + +size_t fi_fwrite(const void *buffer,size_t size,size_t count,FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->write(buffer,size,count); + } + return ret; +} + +size_t fi_fprintf(FILE_INTERFACE *_fph,const char *fmt,...) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + + char buffer[2048]; + buffer[2047] = 0; + va_list arg; + va_start( arg, fmt ); + MESH_IMPORT_STRING::vsnprintf(buffer,2047, fmt, arg); + va_end(arg); + + if ( fph ) + { + ret = fph->writeString(buffer); + } + + return ret; +} + + +size_t fi_fflush(FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->flush(); + } + return ret; +} + + +size_t fi_fseek(FILE_INTERFACE *_fph,size_t loc,size_t mode) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->seek(loc,mode); + } + return ret; +} + +size_t fi_ftell(FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->tell(); + } + return ret; +} + +size_t fi_fputc(char c,FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->myputc(c); + } + return ret; +} + +size_t fi_fputs(const char *str,FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->writeString(str); + } + return ret; +} + +size_t fi_feof(FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->eof(); + } + return ret; +} + +size_t fi_ferror(FILE_INTERFACE *_fph) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + size_t ret = 0; + if ( fph ) + { + ret = fph->error(); + } + return ret; +} + +void * fi_getMemBuffer(FILE_INTERFACE *_fph,size_t *outputLength) +{ + _FILE_INTERFACE *fph = (_FILE_INTERFACE *)_fph; + *outputLength = 0; + void * ret = 0; + if ( fph && outputLength ) + { + ret = fph->getMemBuffer(*outputLength); + } + return ret; +} + +}; + diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.cpp new file mode 100644 index 00000000..b4a7bbc6 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <math.h> +#include <float.h> +#include "MiFloatMath.h" + +#define REAL MiF32 + +#include "MiFloatMath.inl" + +#undef REAL +#define REAL MiF64 + +#include "MiFloatMath.inl" diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.inl b/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.inl new file mode 100644 index 00000000..78f4cd28 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.inl @@ -0,0 +1,5648 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +// a set of routines that let you do common 3d math +// operations without any vector, matrix, or quaternion +// classes or templates. +// +// a vector (or point) is a 'MiF32 *' to 3 floating point numbers. +// a matrix is a 'MiF32 *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL +// a quaternion is a 'MiF32 *' to 4 floats representing a quaternion x,y,z,w +// + +#pragma warning(disable:4996) + +namespace mimp +{ + +void fm_inverseRT(const REAL matrix[16],const REAL pos[3],REAL t[3]) // inverse rotate translate the point. +{ + + REAL _x = pos[0] - matrix[3*4+0]; + REAL _y = pos[1] - matrix[3*4+1]; + REAL _z = pos[2] - matrix[3*4+2]; + + // Multiply inverse-translated source vector by inverted rotation transform + + t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z); + t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z); + t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z); + +} + +REAL fm_getDeterminant(const REAL matrix[16]) +{ + REAL tempv[3]; + REAL p0[3]; + REAL p1[3]; + REAL p2[3]; + + + p0[0] = matrix[0*4+0]; + p0[1] = matrix[0*4+1]; + p0[2] = matrix[0*4+2]; + + p1[0] = matrix[1*4+0]; + p1[1] = matrix[1*4+1]; + p1[2] = matrix[1*4+2]; + + p2[0] = matrix[2*4+0]; + p2[1] = matrix[2*4+1]; + p2[2] = matrix[2*4+2]; + + fm_cross(tempv,p1,p2); + + return fm_dot(p0,tempv); + +} + +REAL fm_squared(REAL x) { return x*x; }; + +void fm_decomposeTransform(const REAL local_transform[16],REAL trans[3],REAL rot[4],REAL scale[3]) +{ + + trans[0] = local_transform[12]; + trans[1] = local_transform[13]; + trans[2] = local_transform[14]; + + scale[0] = static_cast<REAL>(::sqrt(fm_squared(local_transform[0*4+0]) + fm_squared(local_transform[0*4+1]) + fm_squared(local_transform[0*4+2]))); + scale[1] = static_cast<REAL>(::sqrt(fm_squared(local_transform[1*4+0]) + fm_squared(local_transform[1*4+1]) + fm_squared(local_transform[1*4+2]))); + scale[2] = static_cast<REAL>(::sqrt(fm_squared(local_transform[2*4+0]) + fm_squared(local_transform[2*4+1]) + fm_squared(local_transform[2*4+2]))); + + REAL m[16]; + memcpy(m,local_transform,sizeof(REAL)*16); + + REAL sx = 1.0f / scale[0]; + REAL sy = 1.0f / scale[1]; + REAL sz = 1.0f / scale[2]; + + m[0*4+0]*=sx; + m[0*4+1]*=sx; + m[0*4+2]*=sx; + + m[1*4+0]*=sy; + m[1*4+1]*=sy; + m[1*4+2]*=sy; + + m[2*4+0]*=sz; + m[2*4+1]*=sz; + m[2*4+2]*=sz; + + fm_matrixToQuat(m,rot); + +} + +void fm_getSubMatrix(MiI32 ki,MiI32 kj,REAL pDst[16],const REAL matrix[16]) +{ + MiI32 row, col; + MiI32 dstCol = 0, dstRow = 0; + + for ( col = 0; col < 4; col++ ) + { + if ( col == kj ) + { + continue; + } + for ( dstRow = 0, row = 0; row < 4; row++ ) + { + if ( row == ki ) + { + continue; + } + pDst[dstCol*4+dstRow] = matrix[col*4+row]; + dstRow++; + } + dstCol++; + } +} + +void fm_inverseTransform(const REAL matrix[16],REAL inverse_matrix[16]) +{ + REAL determinant = fm_getDeterminant(matrix); + determinant = 1.0f / determinant; + for (MiI32 i = 0; i < 4; i++ ) + { + for (MiI32 j = 0; j < 4; j++ ) + { + MiI32 sign = 1 - ( ( i + j ) % 2 ) * 2; + REAL subMat[16]; + fm_identity(subMat); + fm_getSubMatrix( i, j, subMat, matrix ); + REAL subDeterminant = fm_getDeterminant(subMat); + inverse_matrix[i*4+j] = ( subDeterminant * sign ) * determinant; + } + } +} + +void fm_identity(REAL matrix[16]) // set 4x4 matrix to identity. +{ + matrix[0*4+0] = 1; + matrix[1*4+1] = 1; + matrix[2*4+2] = 1; + matrix[3*4+3] = 1; + + matrix[1*4+0] = 0; + matrix[2*4+0] = 0; + matrix[3*4+0] = 0; + + matrix[0*4+1] = 0; + matrix[2*4+1] = 0; + matrix[3*4+1] = 0; + + matrix[0*4+2] = 0; + matrix[1*4+2] = 0; + matrix[3*4+2] = 0; + + matrix[0*4+3] = 0; + matrix[1*4+3] = 0; + matrix[2*4+3] = 0; + +} + +void fm_quatToEuler(const REAL quat[4],REAL &ax,REAL &ay,REAL &az) +{ + REAL x = quat[0]; + REAL y = quat[1]; + REAL z = quat[2]; + REAL w = quat[3]; + + REAL sint = (2.0f * w * y) - (2.0f * x * z); + REAL cost_temp = 1.0f - (sint * sint); + REAL cost = 0; + + if ( (REAL)fabs(cost_temp) > 0.001f ) + { + cost = static_cast<REAL>(::sqrt( cost_temp )); + } + + REAL sinv, cosv, sinf, cosf; + if ( (REAL)fabs(cost) > 0.001f ) + { + cost = 1.0f / cost; + sinv = ((2.0f * y * z) + (2.0f * w * x)) * cost; + cosv = (1.0f - (2.0f * x * x) - (2.0f * y * y)) * cost; + sinf = ((2.0f * x * y) + (2.0f * w * z)) * cost; + cosf = (1.0f - (2.0f * y * y) - (2.0f * z * z)) * cost; + } + else + { + sinv = (2.0f * w * x) - (2.0f * y * z); + cosv = 1.0f - (2.0f * x * x) - (2.0f * z * z); + sinf = 0; + cosf = 1.0f; + } + + // compute output rotations + ax = static_cast<REAL>(::atan2( sinv, cosv )); + ay = static_cast<REAL>(::atan2( sint, cost )); + az = static_cast<REAL>(::atan2( sinf, cosf )); + +} + +void fm_eulerToMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) +{ + REAL quat[4]; + fm_eulerToQuat(ax,ay,az,quat); + fm_quatToMatrix(quat,matrix); +} + +void fm_getAABB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *bmin,REAL *bmax) +{ + + const MiU8 *source = (const MiU8 *) points; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + + for (MiU32 i=1; i<vcount; i++) + { + source+=pstride; + const REAL *p = (const REAL *) source; + + if ( p[0] < bmin[0] ) bmin[0] = p[0]; + if ( p[1] < bmin[1] ) bmin[1] = p[1]; + if ( p[2] < bmin[2] ) bmin[2] = p[2]; + + if ( p[0] > bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + } +} + +void fm_eulerToQuat(const REAL *euler,REAL *quat) // convert euler angles to quaternion. +{ + fm_eulerToQuat(euler[0],euler[1],euler[2],quat); +} + +void fm_eulerToQuat(REAL roll,REAL pitch,REAL yaw,REAL *quat) // convert euler angles to quaternion. +{ + roll *= 0.5f; + pitch *= 0.5f; + yaw *= 0.5f; + + REAL cr = static_cast<REAL>(::cos(roll)); + REAL cp = static_cast<REAL>(::cos(pitch)); + REAL cy = static_cast<REAL>(::cos(yaw)); + + REAL sr = static_cast<REAL>(::sin(roll)); + REAL sp = static_cast<REAL>(::sin(pitch)); + REAL sy = static_cast<REAL>(::sin(yaw)); + + REAL cpcy = cp * cy; + REAL spsy = sp * sy; + REAL spcy = sp * cy; + REAL cpsy = cp * sy; + + quat[0] = ( sr * cpcy - cr * spsy); + quat[1] = ( cr * spcy + sr * cpsy); + quat[2] = ( cr * cpsy - sr * spcy); + quat[3] = cr * cpcy + sr * spsy; +} + +void fm_quatToMatrix(const REAL *quat,REAL *matrix) // convert quaterinion rotation to matrix, zeros out the translation component. +{ + + REAL xx = quat[0]*quat[0]; + REAL yy = quat[1]*quat[1]; + REAL zz = quat[2]*quat[2]; + REAL xy = quat[0]*quat[1]; + REAL xz = quat[0]*quat[2]; + REAL yz = quat[1]*quat[2]; + REAL wx = quat[3]*quat[0]; + REAL wy = quat[3]*quat[1]; + REAL wz = quat[3]*quat[2]; + + matrix[0*4+0] = 1 - 2 * ( yy + zz ); + matrix[1*4+0] = 2 * ( xy - wz ); + matrix[2*4+0] = 2 * ( xz + wy ); + + matrix[0*4+1] = 2 * ( xy + wz ); + matrix[1*4+1] = 1 - 2 * ( xx + zz ); + matrix[2*4+1] = 2 * ( yz - wx ); + + matrix[0*4+2] = 2 * ( xz - wy ); + matrix[1*4+2] = 2 * ( yz + wx ); + matrix[2*4+2] = 1 - 2 * ( xx + yy ); + + matrix[3*4+0] = matrix[3*4+1] = matrix[3*4+2] = (REAL) 0.0f; + matrix[0*4+3] = matrix[1*4+3] = matrix[2*4+3] = (REAL) 0.0f; + matrix[3*4+3] =(REAL) 1.0f; + +} + + +void fm_quatRotate(const REAL *quat,const REAL *v,REAL *r) // rotate a vector directly by a quaternion. +{ + REAL left[4]; + + left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2]; + left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0]; + left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1]; + left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2]; + + r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]); + r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]); + r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]); + +} + + +void fm_getTranslation(const REAL *matrix,REAL *t) +{ + t[0] = matrix[3*4+0]; + t[1] = matrix[3*4+1]; + t[2] = matrix[3*4+2]; +} + +void fm_matrixToQuat(const REAL *matrix,REAL *quat) // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w +{ + + REAL tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2]; + + // check the diagonal + + if (tr > 0.0f ) + { + REAL s = (REAL) ::sqrt ( (MiF64) (tr + 1.0f) ); + quat[3] = s * 0.5f; + s = 0.5f / s; + quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s; + quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s; + quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s; + + } + else + { + // diagonal is negative + MiI32 nxt[3] = {1, 2, 0}; + REAL qa[4]; + + MiI32 i = 0; + + if (matrix[1*4+1] > matrix[0*4+0]) i = 1; + if (matrix[2*4+2] > matrix[i*4+i]) i = 2; + + MiI32 j = nxt[i]; + MiI32 k = nxt[j]; + + REAL s = static_cast<REAL>(::sqrt ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) )); + + qa[i] = s * 0.5f; + + if (s != 0.0f ) s = 0.5f / s; + + qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s; + qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s; + qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s; + + quat[0] = qa[0]; + quat[1] = qa[1]; + quat[2] = qa[2]; + quat[3] = qa[3]; + } + + +} + + +REAL fm_sphereVolume(REAL radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed ) +{ + return (4.0f / 3.0f ) * FM_PI * radius * radius * radius; +} + + +REAL fm_cylinderVolume(REAL radius,REAL h) +{ + return FM_PI * radius * radius *h; +} + +REAL fm_capsuleVolume(REAL radius,REAL h) +{ + REAL volume = fm_sphereVolume(radius); // volume of the sphere portion. + REAL ch = h-radius*2; // this is the cylinder length + if ( ch > 0 ) + { + volume+=fm_cylinderVolume(radius,ch); + } + return volume; +} + +void fm_transform(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point +{ + if ( matrix ) + { + REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0]; + REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1]; + REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2]; + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + else + { + t[0] = v[0]; + t[1] = v[1]; + t[2] = v[2]; + } +} + +void fm_rotate(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point +{ + if ( matrix ) + { + REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]); + REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]); + REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]); + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + else + { + t[0] = v[0]; + t[1] = v[1]; + t[2] = v[2]; + } +} + + +REAL fm_distance(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + + return static_cast<REAL>(::sqrt( dx*dx + dy*dy + dz *dz )); +} + +REAL fm_distanceSquared(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + + return dx*dx + dy*dy + dz *dz; +} + + +REAL fm_distanceSquaredXZ(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dz = p1[2] - p2[2]; + + return dx*dx + dz *dz; +} + + +REAL fm_computePlane(const REAL *A,const REAL *B,const REAL *C,REAL *n) // returns D +{ + REAL vx = (B[0] - C[0]); + REAL vy = (B[1] - C[1]); + REAL vz = (B[2] - C[2]); + + REAL wx = (A[0] - B[0]); + REAL wy = (A[1] - B[1]); + REAL wz = (A[2] - B[2]); + + REAL vw_x = vy * wz - vz * wy; + REAL vw_y = vz * wx - vx * wz; + REAL vw_z = vx * wy - vy * wx; + + REAL mag = static_cast<REAL>(::sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z))); + + if ( mag < 0.000001f ) + { + mag = 0; + } + else + { + mag = 1.0f/mag; + } + + REAL x = vw_x * mag; + REAL y = vw_y * mag; + REAL z = vw_z * mag; + + + REAL D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2])); + + n[0] = x; + n[1] = y; + n[2] = z; + + return D; +} + +REAL fm_distToPlane(const REAL *plane,const REAL *p) // computes the distance of this point from the plane. +{ + return p[0]*plane[0]+p[1]*plane[1]+p[2]*plane[2]+plane[3]; +} + +REAL fm_dot(const REAL *p1,const REAL *p2) +{ + return p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]; +} + +void fm_cross(REAL *cross,const REAL *a,const REAL *b) +{ + cross[0] = a[1]*b[2] - a[2]*b[1]; + cross[1] = a[2]*b[0] - a[0]*b[2]; + cross[2] = a[0]*b[1] - a[1]*b[0]; +} + +void fm_computeNormalVector(REAL *n,const REAL *p1,const REAL *p2) +{ + n[0] = p2[0] - p1[0]; + n[1] = p2[1] - p1[1]; + n[2] = p2[2] - p1[2]; + fm_normalize(n); +} + +bool fm_computeWindingOrder(const REAL *p1,const REAL *p2,const REAL *p3) // returns true if the triangle is clockwise. +{ + bool ret = false; + + REAL v1[3]; + REAL v2[3]; + + fm_computeNormalVector(v1,p1,p2); // p2-p1 (as vector) and then normalized + fm_computeNormalVector(v2,p1,p3); // p3-p1 (as vector) and then normalized + + REAL cross[3]; + + fm_cross(cross, v1, v2 ); + REAL ref[3] = { 1, 0, 0 }; + + REAL d = fm_dot( cross, ref ); + + + if ( d <= 0 ) + ret = false; + else + ret = true; + + return ret; +} + +REAL fm_normalize(REAL *n) // normalize this vector +{ + REAL dist = (REAL)::sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); + if ( dist > 0.0000001f ) + { + REAL mag = 1.0f / dist; + n[0]*=mag; + n[1]*=mag; + n[2]*=mag; + } + else + { + n[0] = 1; + n[1] = 0; + n[2] = 0; + } + + return dist; +} + + +void fm_matrixMultiply(const REAL *pA,const REAL *pB,REAL *pM) +{ +#if 1 + + REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; + REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; + REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; + REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; + + REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; + REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; + REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; + REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; + + REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; + REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; + REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; + REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; + + REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; + REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; + REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; + REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; + + pM[0] = a; + pM[1] = b; + pM[2] = c; + pM[3] = d; + + pM[4] = e; + pM[5] = f; + pM[6] = g; + pM[7] = h; + + pM[8] = i; + pM[9] = j; + pM[10] = k; + pM[11] = l; + + pM[12] = m; + pM[13] = n; + pM[14] = o; + pM[15] = p; + + +#else + memset(pM, 0, sizeof(REAL)*16); + for(MiI32 i=0; i<4; i++ ) + for(MiI32 j=0; j<4; j++ ) + for(MiI32 k=0; k<4; k++ ) + pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; +#endif +} + + +void fm_eulerToQuatDX(REAL x,REAL y,REAL z,REAL *quat) // convert euler angles to quaternion using the fucked up DirectX method +{ + REAL matrix[16]; + fm_eulerToMatrix(x,y,z,matrix); + fm_matrixToQuat(matrix,quat); +} + +// implementation copied from: http://blogs.msdn.com/mikepelton/archive/2004/10/29/249501.aspx +void fm_eulerToMatrixDX(REAL x,REAL y,REAL z,REAL *matrix) // convert euler angles to quaternion using the fucked up DirectX method. +{ + fm_identity(matrix); + matrix[0*4+0] = static_cast<REAL>(::cos(z)*::cos(y) + ::sin(z)*::sin(x)*::sin(y)); + matrix[0*4+1] = static_cast<REAL>(::sin(z)*::cos(x)); + matrix[0*4+2] = static_cast<REAL>(::cos(z)*-::sin(y) + ::sin(z)*::sin(x)*::cos(y)); + + matrix[1*4+0] = static_cast<REAL>(-::sin(z)*::cos(y)+::cos(z)*::sin(x)*::sin(y)); + matrix[1*4+1] = static_cast<REAL>(::cos(z)*::cos(x)); + matrix[1*4+2] = static_cast<REAL>(::sin(z)*::sin(y) +::cos(z)*::sin(x)*::cos(y)); + + matrix[2*4+0] = static_cast<REAL>(::cos(x)*::sin(y)); + matrix[2*4+1] = static_cast<REAL>(-::sin(x)); + matrix[2*4+2] = static_cast<REAL>(::cos(x)*::cos(y)); +} + + +void fm_scale(REAL x,REAL y,REAL z,REAL *fscale) // apply scale to the matrix. +{ + fscale[0*4+0] = x; + fscale[1*4+1] = y; + fscale[2*4+2] = z; +} + + +void fm_composeTransform(const REAL *position,const REAL *quat,const REAL *scale,REAL *matrix) +{ + fm_identity(matrix); + fm_quatToMatrix(quat,matrix); + + if ( scale && ( scale[0] != 1 || scale[1] != 1 || scale[2] != 1 ) ) + { + REAL work[16]; + memcpy(work,matrix,sizeof(REAL)*16); + REAL mscale[16]; + fm_identity(mscale); + fm_scale(scale[0],scale[1],scale[2],mscale); + fm_matrixMultiply(work,mscale,matrix); + } + + matrix[12] = position[0]; + matrix[13] = position[1]; + matrix[14] = position[2]; +} + + +void fm_setTranslation(const REAL *translation,REAL *matrix) +{ + matrix[12] = translation[0]; + matrix[13] = translation[1]; + matrix[14] = translation[2]; +} + +static REAL enorm0_3d ( REAL x0, REAL y0, REAL z0, REAL x1, REAL y1, REAL z1 ) + +/**********************************************************************/ + +/* +Purpose: + +ENORM0_3D computes the Euclidean norm of (P1-P0) in 3D. + +Modified: + +18 April 1999 + +Author: + +John Burkardt + +Parameters: + +Input, REAL X0, Y0, Z0, X1, Y1, Z1, the coordinates of the points +P0 and P1. + +Output, REAL ENORM0_3D, the Euclidean norm of (P1-P0). +*/ +{ + REAL value; + + value = static_cast<REAL>(::sqrt ( + ( x1 - x0 ) * ( x1 - x0 ) + + ( y1 - y0 ) * ( y1 - y0 ) + + ( z1 - z0 ) * ( z1 - z0 ) )); + + return value; +} + + +static REAL triangle_area_3d ( REAL x1, REAL y1, REAL z1, REAL x2,REAL y2, REAL z2, REAL x3, REAL y3, REAL z3 ) + + /**********************************************************************/ + + /* + Purpose: + + TRIANGLE_AREA_3D computes the area of a triangle in 3D. + + Modified: + + 22 April 1999 + + Author: + + John Burkardt + + Parameters: + + Input, REAL X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, the (X,Y,Z) + coordinates of the corners of the triangle. + + Output, REAL TRIANGLE_AREA_3D, the area of the triangle. + */ +{ + REAL a; + REAL alpha; + REAL area; + REAL b; + REAL base; + REAL c; + REAL dot; + REAL height; + /* + Find the projection of (P3-P1) onto (P2-P1). + */ + dot = + ( x2 - x1 ) * ( x3 - x1 ) + + ( y2 - y1 ) * ( y3 - y1 ) + + ( z2 - z1 ) * ( z3 - z1 ); + + base = enorm0_3d ( x1, y1, z1, x2, y2, z2 ); + /* + The height of the triangle is the length of (P3-P1) after its + projection onto (P2-P1) has been subtracted. + */ + if ( base == 0.0 ) { + + height = 0.0; + + } + else { + + alpha = dot / ( base * base ); + + a = x3 - x1 - alpha * ( x2 - x1 ); + b = y3 - y1 - alpha * ( y2 - y1 ); + c = z3 - z1 - alpha * ( z2 - z1 ); + + height = static_cast<REAL>(::sqrt ( a * a + b * b + c * c )); + + } + + area = 0.5f * base * height; + + return area; +} + + +REAL fm_computeArea(const REAL *p1,const REAL *p2,const REAL *p3) +{ + REAL ret = 0; + + ret = triangle_area_3d(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]); + + return ret; +} + + +void fm_lerp(const REAL *p1,const REAL *p2,REAL *dest,REAL lerpValue) +{ + dest[0] = ((p2[0] - p1[0])*lerpValue) + p1[0]; + dest[1] = ((p2[1] - p1[1])*lerpValue) + p1[1]; + dest[2] = ((p2[2] - p1[2])*lerpValue) + p1[2]; +} + +bool fm_pointTestXZ(const REAL *p,const REAL *i,const REAL *j) +{ + bool ret = false; + + if (((( i[2] <= p[2] ) && ( p[2] < j[2] )) || (( j[2] <= p[2] ) && ( p[2] < i[2] ))) && ( p[0] < (j[0] - i[0]) * (p[2] - i[2]) / (j[2] - i[2]) + i[0])) + ret = true; + + return ret; +}; + + +bool fm_insideTriangleXZ(const REAL *p,const REAL *p1,const REAL *p2,const REAL *p3) +{ + bool ret = false; + + MiI32 c = 0; + if ( fm_pointTestXZ(p,p1,p2) ) c = !c; + if ( fm_pointTestXZ(p,p2,p3) ) c = !c; + if ( fm_pointTestXZ(p,p3,p1) ) c = !c; + if ( c ) ret = true; + + return ret; +} + +bool fm_insideAABB(const REAL *pos,const REAL *bmin,const REAL *bmax) +{ + bool ret = false; + + if ( pos[0] >= bmin[0] && pos[0] <= bmax[0] && + pos[1] >= bmin[1] && pos[1] <= bmax[1] && + pos[2] >= bmin[2] && pos[2] <= bmax[2] ) + ret = true; + + return ret; +} + + +MiU32 fm_clipTestPoint(const REAL *bmin,const REAL *bmax,const REAL *pos) +{ + MiU32 ret = 0; + + if ( pos[0] < bmin[0] ) + ret|=FMCS_XMIN; + else if ( pos[0] > bmax[0] ) + ret|=FMCS_XMAX; + + if ( pos[1] < bmin[1] ) + ret|=FMCS_YMIN; + else if ( pos[1] > bmax[1] ) + ret|=FMCS_YMAX; + + if ( pos[2] < bmin[2] ) + ret|=FMCS_ZMIN; + else if ( pos[2] > bmax[2] ) + ret|=FMCS_ZMAX; + + return ret; +} + +MiU32 fm_clipTestPointXZ(const REAL *bmin,const REAL *bmax,const REAL *pos) // only tests X and Z, not Y +{ + MiU32 ret = 0; + + if ( pos[0] < bmin[0] ) + ret|=FMCS_XMIN; + else if ( pos[0] > bmax[0] ) + ret|=FMCS_XMAX; + + if ( pos[2] < bmin[2] ) + ret|=FMCS_ZMIN; + else if ( pos[2] > bmax[2] ) + ret|=FMCS_ZMAX; + + return ret; +} + +MiU32 fm_clipTestAABB(const REAL *bmin,const REAL *bmax,const REAL *p1,const REAL *p2,const REAL *p3,MiU32 &andCode) +{ + MiU32 orCode = 0; + + andCode = FMCS_XMIN | FMCS_XMAX | FMCS_YMIN | FMCS_YMAX | FMCS_ZMIN | FMCS_ZMAX; + + MiU32 c = fm_clipTestPoint(bmin,bmax,p1); + orCode|=c; + andCode&=c; + + c = fm_clipTestPoint(bmin,bmax,p2); + orCode|=c; + andCode&=c; + + c = fm_clipTestPoint(bmin,bmax,p3); + orCode|=c; + andCode&=c; + + return orCode; +} + +bool intersect(const REAL *si,const REAL *ei,const REAL *bmin,const REAL *bmax,REAL *time) +{ + REAL st,et,fst = 0,fet = 1; + + for (MiI32 i = 0; i < 3; i++) + { + if (*si < *ei) + { + if (*si > *bmax || *ei < *bmin) + return false; + REAL di = *ei - *si; + st = (*si < *bmin)? (*bmin - *si) / di: 0; + et = (*ei > *bmax)? (*bmax - *si) / di: 1; + } + else + { + if (*ei > *bmax || *si < *bmin) + return false; + REAL di = *ei - *si; + st = (*si > *bmax)? (*bmax - *si) / di: 0; + et = (*ei < *bmin)? (*bmin - *si) / di: 1; + } + + if (st > fst) fst = st; + if (et < fet) fet = et; + if (fet < fst) + return false; + bmin++; bmax++; + si++; ei++; + } + + *time = fst; + return true; +} + + + +bool fm_lineTestAABB(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) +{ + bool sect = intersect(p1,p2,bmin,bmax,&time); + return sect; +} + + +bool fm_lineTestAABBXZ(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) +{ + REAL _bmin[3]; + REAL _bmax[3]; + + _bmin[0] = bmin[0]; + _bmin[1] = -1e9; + _bmin[2] = bmin[2]; + + _bmax[0] = bmax[0]; + _bmax[1] = 1e9; + _bmax[2] = bmax[2]; + + bool sect = intersect(p1,p2,_bmin,_bmax,&time); + + return sect; +} + +void fm_minmax(const REAL *p,REAL *bmin,REAL *bmax) // accmulate to a min-max value +{ + + if ( p[0] < bmin[0] ) bmin[0] = p[0]; + if ( p[1] < bmin[1] ) bmin[1] = p[1]; + if ( p[2] < bmin[2] ) bmin[2] = p[2]; + + if ( p[0] > bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + +} + +REAL fm_solveX(const REAL *plane,REAL y,REAL z) // solve for X given this plane equation and the other two components. +{ + REAL x = (y*plane[1]+z*plane[2]+plane[3]) / -plane[0]; + return x; +} + +REAL fm_solveY(const REAL *plane,REAL x,REAL z) // solve for Y given this plane equation and the other two components. +{ + REAL y = (x*plane[0]+z*plane[2]+plane[3]) / -plane[1]; + return y; +} + + +REAL fm_solveZ(const REAL *plane,REAL x,REAL y) // solve for Y given this plane equation and the other two components. +{ + REAL z = (x*plane[0]+y*plane[1]+plane[3]) / -plane[2]; + return z; +} + + +void fm_getAABBCenter(const REAL *bmin,const REAL *bmax,REAL *center) +{ + center[0] = (bmax[0]-bmin[0])*0.5f+bmin[0]; + center[1] = (bmax[1]-bmin[1])*0.5f+bmin[1]; + center[2] = (bmax[2]-bmin[2])*0.5f+bmin[2]; +} + +FM_Axis fm_getDominantAxis(const REAL normal[3]) +{ + FM_Axis ret = FM_XAXIS; + + REAL x = static_cast<REAL>(fabs(normal[0])); + REAL y = static_cast<REAL>(fabs(normal[1])); + REAL z = static_cast<REAL>(fabs(normal[2])); + + if ( y > x && y > z ) + ret = FM_YAXIS; + else if ( z > x && z > y ) + ret = FM_ZAXIS; + + return ret; +} + + +bool fm_lineSphereIntersect(const REAL *center,REAL radius,const REAL *p1,const REAL *p2,REAL *intersect) +{ + bool ret = false; + + REAL dir[3]; + + dir[0] = p2[0]-p1[0]; + dir[1] = p2[1]-p1[1]; + dir[2] = p2[2]-p1[2]; + + REAL distance = static_cast<REAL>(::sqrt( dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2])); + + if ( distance > 0 ) + { + REAL recip = 1.0f / distance; + dir[0]*=recip; + dir[1]*=recip; + dir[2]*=recip; + ret = fm_raySphereIntersect(center,radius,p1,dir,distance,intersect); + } + else + { + dir[0] = center[0]-p1[0]; + dir[1] = center[1]-p1[1]; + dir[2] = center[2]-p1[2]; + REAL d2 = dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]; + REAL r2 = radius*radius; + if ( d2 < r2 ) + { + ret = true; + if ( intersect ) + { + intersect[0] = p1[0]; + intersect[1] = p1[1]; + intersect[2] = p1[2]; + } + } + } + return ret; +} + +#define DOT(p1,p2) (p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]) + +bool fm_raySphereIntersect(const REAL *center,REAL radius,const REAL *pos,const REAL *dir,REAL distance,REAL *intersect) +{ + bool ret = false; + + REAL E0[3]; + + E0[0] = center[0] - pos[0]; + E0[1] = center[1] - pos[1]; + E0[2] = center[2] - pos[2]; + + REAL V[3]; + + V[0] = dir[0]; + V[1] = dir[1]; + V[2] = dir[2]; + + + REAL dist2 = E0[0]*E0[0] + E0[1]*E0[1] + E0[2] * E0[2]; + REAL radius2 = radius*radius; // radius squared.. + + // Bug Fix For Gem, if origin is *inside* the sphere, invert the + // direction vector so that we get a valid intersection location. + if ( dist2 < radius2 ) + { + V[0]*=-1; + V[1]*=-1; + V[2]*=-1; + } + + + REAL v = DOT(E0,V); + + REAL disc = radius2 - (dist2 - v*v); + + if (disc > 0.0f) + { + if ( intersect ) + { + REAL d = static_cast<REAL>(::sqrt(disc)); + REAL diff = v-d; + if ( diff < distance ) + { + intersect[0] = pos[0]+V[0]*diff; + intersect[1] = pos[1]+V[1]*diff; + intersect[2] = pos[2]+V[2]*diff; + ret = true; + } + } + } + + return ret; +} + + +void fm_catmullRom(REAL *out_vector,const REAL *p1,const REAL *p2,const REAL *p3,const REAL *p4, const REAL s) +{ + REAL s_squared = s * s; + REAL s_cubed = s_squared * s; + + REAL coefficient_p1 = -s_cubed + 2*s_squared - s; + REAL coefficient_p2 = 3 * s_cubed - 5 * s_squared + 2; + REAL coefficient_p3 = -3 * s_cubed +4 * s_squared + s; + REAL coefficient_p4 = s_cubed - s_squared; + + out_vector[0] = (coefficient_p1 * p1[0] + coefficient_p2 * p2[0] + coefficient_p3 * p3[0] + coefficient_p4 * p4[0])*0.5f; + out_vector[1] = (coefficient_p1 * p1[1] + coefficient_p2 * p2[1] + coefficient_p3 * p3[1] + coefficient_p4 * p4[1])*0.5f; + out_vector[2] = (coefficient_p1 * p1[2] + coefficient_p2 * p2[2] + coefficient_p3 * p3[2] + coefficient_p4 * p4[2])*0.5f; +} + +bool fm_intersectAABB(const REAL *bmin1,const REAL *bmax1,const REAL *bmin2,const REAL *bmax2) +{ + if ((bmin1[0] > bmax2[0]) || (bmin2[0] > bmax1[0])) return false; + if ((bmin1[1] > bmax2[1]) || (bmin2[1] > bmax1[1])) return false; + if ((bmin1[2] > bmax2[2]) || (bmin2[2] > bmax1[2])) return false; + return true; + +} + +bool fm_insideAABB(const REAL *obmin,const REAL *obmax,const REAL *tbmin,const REAL *tbmax) // test if bounding box tbmin/tmbax is fully inside obmin/obmax +{ + bool ret = false; + + if ( tbmax[0] <= obmax[0] && + tbmax[1] <= obmax[1] && + tbmax[2] <= obmax[2] && + tbmin[0] >= obmin[0] && + tbmin[1] >= obmin[1] && + tbmin[2] >= obmin[2] ) ret = true; + + return ret; +} + + +// Reference, from Stan Melax in Game Gems I +// Quaternion q; +// vector3 c = CrossProduct(v0,v1); +// REAL d = DotProduct(v0,v1); +// REAL s = (REAL)::sqrt((1+d)*2); +// q.x = c.x / s; +// q.y = c.y / s; +// q.z = c.z / s; +// q.w = s /2.0f; +// return q; +void fm_rotationArc(const REAL *v0,const REAL *v1,REAL *quat) +{ + REAL cross[3]; + + fm_cross(cross,v0,v1); + REAL d = fm_dot(v0,v1); + + if(d<=-1.0f) // 180 about x axis + { + quat[0] = 1.0f; + quat[1] = quat[2] = quat[3] =0.0f; + return; + } + else + { + REAL s = static_cast<REAL>(::sqrt((1+d)*2)); + REAL recip = 1.0f / s; + + quat[0] = cross[0] * recip; + quat[1] = cross[1] * recip; + quat[2] = cross[2] * recip; + quat[3] = s * 0.5f; + } +} + + +REAL fm_distancePointLineSegment(const REAL *Point,const REAL *LineStart,const REAL *LineEnd,REAL *intersection,LineSegmentType &type,REAL epsilon) +{ + REAL ret; + + REAL LineMag = fm_distance( LineEnd, LineStart ); + + if ( LineMag > 0 ) + { + REAL U = ( ( ( Point[0] - LineStart[0] ) * ( LineEnd[0] - LineStart[0] ) ) + ( ( Point[1] - LineStart[1] ) * ( LineEnd[1] - LineStart[1] ) ) + ( ( Point[2] - LineStart[2] ) * ( LineEnd[2] - LineStart[2] ) ) ) / ( LineMag * LineMag ); + if( U < 0.0f || U > 1.0f ) + { + REAL d1 = fm_distanceSquared(Point,LineStart); + REAL d2 = fm_distanceSquared(Point,LineEnd); + if ( d1 <= d2 ) + { + ret = static_cast<REAL>(::sqrt(d1)); + intersection[0] = LineStart[0]; + intersection[1] = LineStart[1]; + intersection[2] = LineStart[2]; + type = LS_START; + } + else + { + ret = static_cast<REAL>(::sqrt(d2)); + intersection[0] = LineEnd[0]; + intersection[1] = LineEnd[1]; + intersection[2] = LineEnd[2]; + type = LS_END; + } + } + else + { + intersection[0] = LineStart[0] + U * ( LineEnd[0] - LineStart[0] ); + intersection[1] = LineStart[1] + U * ( LineEnd[1] - LineStart[1] ); + intersection[2] = LineStart[2] + U * ( LineEnd[2] - LineStart[2] ); + + ret = fm_distance(Point,intersection); + + REAL d1 = fm_distanceSquared(intersection,LineStart); + REAL d2 = fm_distanceSquared(intersection,LineEnd); + REAL mag = (epsilon*2)*(epsilon*2); + + if ( d1 < mag ) // if less than 1/100th the total distance, treat is as the 'start' + { + type = LS_START; + } + else if ( d2 < mag ) + { + type = LS_END; + } + else + { + type = LS_MIDDLE; + } + + } + } + else + { + ret = LineMag; + intersection[0] = LineEnd[0]; + intersection[1] = LineEnd[1]; + intersection[2] = LineEnd[2]; + type = LS_END; + } + + return ret; +} + + +#ifndef BEST_FIT_PLANE_H + +#define BEST_FIT_PLANE_H + +template <class Type> class Eigen +{ +public: + + + void DecrSortEigenStuff(void) + { + Tridiagonal(); //diagonalize the matrix. + QLAlgorithm(); // + DecreasingSort(); + GuaranteeRotation(); + } + + void Tridiagonal(void) + { + Type fM00 = mElement[0][0]; + Type fM01 = mElement[0][1]; + Type fM02 = mElement[0][2]; + Type fM11 = mElement[1][1]; + Type fM12 = mElement[1][2]; + Type fM22 = mElement[2][2]; + + m_afDiag[0] = fM00; + m_afSubd[2] = 0; + if (fM02 != (Type)0.0) + { + Type fLength = static_cast<Type>(::sqrt(fM01*fM01+fM02*fM02)); + Type fInvLength = ((Type)1.0)/fLength; + fM01 *= fInvLength; + fM02 *= fInvLength; + Type fQ = ((Type)2.0)*fM01*fM12+fM02*(fM22-fM11); + m_afDiag[1] = fM11+fM02*fQ; + m_afDiag[2] = fM22-fM02*fQ; + m_afSubd[0] = fLength; + m_afSubd[1] = fM12-fM01*fQ; + mElement[0][0] = (Type)1.0; + mElement[0][1] = (Type)0.0; + mElement[0][2] = (Type)0.0; + mElement[1][0] = (Type)0.0; + mElement[1][1] = fM01; + mElement[1][2] = fM02; + mElement[2][0] = (Type)0.0; + mElement[2][1] = fM02; + mElement[2][2] = -fM01; + m_bIsRotation = false; + } + else + { + m_afDiag[1] = fM11; + m_afDiag[2] = fM22; + m_afSubd[0] = fM01; + m_afSubd[1] = fM12; + mElement[0][0] = (Type)1.0; + mElement[0][1] = (Type)0.0; + mElement[0][2] = (Type)0.0; + mElement[1][0] = (Type)0.0; + mElement[1][1] = (Type)1.0; + mElement[1][2] = (Type)0.0; + mElement[2][0] = (Type)0.0; + mElement[2][1] = (Type)0.0; + mElement[2][2] = (Type)1.0; + m_bIsRotation = true; + } + } + + bool QLAlgorithm(void) + { + const MiI32 iMaxIter = 32; + + for (MiI32 i0 = 0; i0 <3; i0++) + { + MiI32 i1; + for (i1 = 0; i1 < iMaxIter; i1++) + { + MiI32 i2; + for (i2 = i0; i2 <= (3-2); i2++) + { + Type fTmp = static_cast<Type>(fabs(m_afDiag[i2]) + fabs(m_afDiag[i2+1])); + if ( fabs(m_afSubd[i2]) + fTmp == fTmp ) + break; + } + if (i2 == i0) + { + break; + } + + Type fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((Type)2.0) * m_afSubd[i0]); + Type fR = static_cast<Type>(::sqrt(fG*fG+(Type)1.0)); + if (fG < (Type)0.0) + { + fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR); + } + else + { + fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR); + } + Type fSin = (Type)1.0, fCos = (Type)1.0, fP = (Type)0.0; + for (MiI32 i3 = i2-1; i3 >= i0; i3--) + { + Type fF = fSin*m_afSubd[i3]; + Type fB = fCos*m_afSubd[i3]; + if (fabs(fF) >= fabs(fG)) + { + fCos = fG/fF; + fR = static_cast<Type>(::sqrt(fCos*fCos+(Type)1.0)); + m_afSubd[i3+1] = fF*fR; + fSin = ((Type)1.0)/fR; + fCos *= fSin; + } + else + { + fSin = fF/fG; + fR = static_cast<Type>(::sqrt(fSin*fSin+(Type)1.0)); + m_afSubd[i3+1] = fG*fR; + fCos = ((Type)1.0)/fR; + fSin *= fCos; + } + fG = m_afDiag[i3+1]-fP; + fR = (m_afDiag[i3]-fG)*fSin+((Type)2.0)*fB*fCos; + fP = fSin*fR; + m_afDiag[i3+1] = fG+fP; + fG = fCos*fR-fB; + for (MiI32 i4 = 0; i4 < 3; i4++) + { + fF = mElement[i4][i3+1]; + mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF; + mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF; + } + } + m_afDiag[i0] -= fP; + m_afSubd[i0] = fG; + m_afSubd[i2] = (Type)0.0; + } + if (i1 == iMaxIter) + { + return false; + } + } + return true; + } + + void DecreasingSort(void) + { + //sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1] + for (MiI32 i0 = 0, i1; i0 <= 3-2; i0++) + { + // locate maximum eigenvalue + i1 = i0; + Type fMax = m_afDiag[i1]; + MiI32 i2; + for (i2 = i0+1; i2 < 3; i2++) + { + if (m_afDiag[i2] > fMax) + { + i1 = i2; + fMax = m_afDiag[i1]; + } + } + + if (i1 != i0) + { + // swap eigenvalues + m_afDiag[i1] = m_afDiag[i0]; + m_afDiag[i0] = fMax; + // swap eigenvectors + for (i2 = 0; i2 < 3; i2++) + { + Type fTmp = mElement[i2][i0]; + mElement[i2][i0] = mElement[i2][i1]; + mElement[i2][i1] = fTmp; + m_bIsRotation = !m_bIsRotation; + } + } + } + } + + + void GuaranteeRotation(void) + { + if (!m_bIsRotation) + { + // change sign on the first column + for (MiI32 iRow = 0; iRow <3; iRow++) + { + mElement[iRow][0] = -mElement[iRow][0]; + } + } + } + + Type mElement[3][3]; + Type m_afDiag[3]; + Type m_afSubd[3]; + bool m_bIsRotation; +}; + +#endif + +bool fm_computeBestFitPlane(MiU32 vcount, + const REAL *points, + MiU32 vstride, + const REAL *weights, + MiU32 wstride, + REAL *plane) +{ + bool ret = false; + + REAL kOrigin[3] = { 0, 0, 0 }; + + REAL wtotal = 0; + + { + const char *source = (const char *) points; + const char *wsource = (const char *) weights; + + for (MiU32 i=0; i<vcount; i++) + { + + const REAL *p = (const REAL *) source; + + REAL w = 1; + + if ( wsource ) + { + const REAL *ws = (const REAL *) wsource; + w = *ws; // + wsource+=wstride; + } + + kOrigin[0]+=p[0]*w; + kOrigin[1]+=p[1]*w; + kOrigin[2]+=p[2]*w; + + wtotal+=w; + + source+=vstride; + } + } + + REAL recip = 1.0f / wtotal; // reciprocol of total weighting + + kOrigin[0]*=recip; + kOrigin[1]*=recip; + kOrigin[2]*=recip; + + + REAL fSumXX=0; + REAL fSumXY=0; + REAL fSumXZ=0; + + REAL fSumYY=0; + REAL fSumYZ=0; + REAL fSumZZ=0; + + + { + const char *source = (const char *) points; + const char *wsource = (const char *) weights; + + for (MiU32 i=0; i<vcount; i++) + { + + const REAL *p = (const REAL *) source; + + REAL w = 1; + + if ( wsource ) + { + const REAL *ws = (const REAL *) wsource; + w = *ws; // + wsource+=wstride; + } + + REAL kDiff[3]; + + kDiff[0] = w*(p[0] - kOrigin[0]); // apply vertex weighting! + kDiff[1] = w*(p[1] - kOrigin[1]); + kDiff[2] = w*(p[2] - kOrigin[2]); + + fSumXX+= kDiff[0] * kDiff[0]; // sume of the squares of the differences. + fSumXY+= kDiff[0] * kDiff[1]; // sume of the squares of the differences. + fSumXZ+= kDiff[0] * kDiff[2]; // sume of the squares of the differences. + + fSumYY+= kDiff[1] * kDiff[1]; + fSumYZ+= kDiff[1] * kDiff[2]; + fSumZZ+= kDiff[2] * kDiff[2]; + + + source+=vstride; + } + } + + fSumXX *= recip; + fSumXY *= recip; + fSumXZ *= recip; + fSumYY *= recip; + fSumYZ *= recip; + fSumZZ *= recip; + + // setup the eigensolver + Eigen<REAL> kES; + + kES.mElement[0][0] = fSumXX; + kES.mElement[0][1] = fSumXY; + kES.mElement[0][2] = fSumXZ; + + kES.mElement[1][0] = fSumXY; + kES.mElement[1][1] = fSumYY; + kES.mElement[1][2] = fSumYZ; + + kES.mElement[2][0] = fSumXZ; + kES.mElement[2][1] = fSumYZ; + kES.mElement[2][2] = fSumZZ; + + // compute eigenstuff, smallest eigenvalue is in last position + kES.DecrSortEigenStuff(); + + REAL kNormal[3]; + + kNormal[0] = kES.mElement[0][2]; + kNormal[1] = kES.mElement[1][2]; + kNormal[2] = kES.mElement[2][2]; + + // the minimum energy + plane[0] = kNormal[0]; + plane[1] = kNormal[1]; + plane[2] = kNormal[2]; + + plane[3] = 0 - fm_dot(kNormal,kOrigin); + + ret = true; + + return ret; +} + + +bool fm_colinear(const REAL a1[3],const REAL a2[3],const REAL b1[3],const REAL b2[3],REAL epsilon) // true if these two line segments are co-linear. +{ + bool ret = false; + + REAL dir1[3]; + REAL dir2[3]; + + dir1[0] = (a2[0] - a1[0]); + dir1[1] = (a2[1] - a1[1]); + dir1[2] = (a2[2] - a1[2]); + + dir2[0] = (b2[0]-a1[0]) - (b1[0]-a1[0]); + dir2[1] = (b2[1]-a1[1]) - (b1[1]-a1[1]); + dir2[2] = (b2[2]-a2[2]) - (b1[2]-a2[2]); + + fm_normalize(dir1); + fm_normalize(dir2); + + REAL dot = fm_dot(dir1,dir2); + + if ( dot >= epsilon ) + { + ret = true; + } + + + return ret; +} + +bool fm_colinear(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) +{ + bool ret = false; + + REAL dir1[3]; + REAL dir2[3]; + + dir1[0] = p2[0] - p1[0]; + dir1[1] = p2[1] - p1[1]; + dir1[2] = p2[2] - p1[2]; + + dir2[0] = p3[0] - p2[0]; + dir2[1] = p3[1] - p2[1]; + dir2[2] = p3[2] - p2[2]; + + fm_normalize(dir1); + fm_normalize(dir2); + + REAL dot = fm_dot(dir1,dir2); + + if ( dot >= epsilon ) + { + ret = true; + } + + + return ret; +} + +void fm_initMinMax(const REAL *p,REAL *bmin,REAL *bmax) +{ + bmax[0] = bmin[0] = p[0]; + bmax[1] = bmin[1] = p[1]; + bmax[2] = bmin[2] = p[2]; +} + +IntersectResult fm_intersectLineSegments2d(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL *intersection) +{ + IntersectResult ret; + + REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); + REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); + REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); + if (denom == 0 ) + { + if(nume_a == 0 && nume_b == 0) + { + ret = IR_COINCIDENT; + } + else + { + ret = IR_PARALLEL; + } + } + else + { + + REAL recip = 1 / denom; + REAL ua = nume_a * recip; + REAL ub = nume_b * recip; + + if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) + { + // Get the intersection point. + intersection[0] = a1[0] + ua*(a2[0] - a1[0]); + intersection[1] = a1[1] + ua*(a2[1] - a1[1]); + ret = IR_DO_INTERSECT; + } + else + { + ret = IR_DONT_INTERSECT; + } + } + return ret; +} + +IntersectResult fm_intersectLineSegments2dTime(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL &t1,REAL &t2) +{ + IntersectResult ret; + + REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); + REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); + REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); + if (denom == 0 ) + { + if(nume_a == 0 && nume_b == 0) + { + ret = IR_COINCIDENT; + } + else + { + ret = IR_PARALLEL; + } + } + else + { + + REAL recip = 1 / denom; + REAL ua = nume_a * recip; + REAL ub = nume_b * recip; + + if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) + { + t1 = ua; + t2 = ub; + ret = IR_DO_INTERSECT; + } + else + { + ret = IR_DONT_INTERSECT; + } + } + return ret; +} + +//**** Plane Triangle Intersection + + + + + +// assumes that the points are on opposite sides of the plane! +void fm_intersectPointPlane(const REAL *p1,const REAL *p2,REAL *split,const REAL *plane) +{ + + REAL dp1 = fm_distToPlane(plane,p1); + + REAL dir[3]; + + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + + REAL dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2]; + REAL dot2 = dp1 - plane[3]; + + REAL t = -(plane[3] + dot2 ) / dot1; + + split[0] = (dir[0]*t)+p1[0]; + split[1] = (dir[1]*t)+p1[1]; + split[2] = (dir[2]*t)+p1[2]; + +} + +PlaneTriResult fm_getSidePlane(const REAL *p,const REAL *plane,REAL epsilon) +{ + PlaneTriResult ret = PTR_ON_PLANE; + + REAL d = fm_distToPlane(plane,p); + + if ( d < -epsilon || d > epsilon ) + { + if ( d > 0 ) + ret = PTR_FRONT; // it is 'in front' within the provided epsilon value. + else + ret = PTR_BACK; + } + + return ret; +} + + + +#ifndef PLANE_TRIANGLE_INTERSECTION_H + +#define PLANE_TRIANGLE_INTERSECTION_H + +#define MAXPTS 256 + +template <class Type> class point +{ +public: + + void set(const Type *p) + { + x = p[0]; + y = p[1]; + z = p[2]; + } + + Type x; + Type y; + Type z; +}; + +template <class Type> class plane +{ +public: + plane(const Type *p) + { + normal.x = p[0]; + normal.y = p[1]; + normal.z = p[2]; + D = p[3]; + } + + Type Classify_Point(const point<Type> &p) + { + return p.x*normal.x + p.y*normal.y + p.z*normal.z + D; + } + + point<Type> normal; + Type D; +}; + +template <class Type> class polygon +{ +public: + polygon(void) + { + mVcount = 0; + } + + polygon(const Type *p1,const Type *p2,const Type *p3) + { + mVcount = 3; + mVertices[0].set(p1); + mVertices[1].set(p2); + mVertices[2].set(p3); + } + + + MiI32 NumVertices(void) const { return mVcount; }; + + const point<Type>& Vertex(MiI32 index) + { + if ( index < 0 ) index+=mVcount; + return mVertices[index]; + }; + + + void set(const point<Type> *pts,MiI32 count) + { + for (MiI32 i=0; i<count; i++) + { + mVertices[i] = pts[i]; + } + mVcount = count; + } + + + void Split_Polygon(polygon<Type> *poly,plane<Type> *part, polygon<Type> &front, polygon<Type> &back) + { + MiI32 count = poly->NumVertices (); + MiI32 out_c = 0, in_c = 0; + point<Type> ptA, ptB,outpts[MAXPTS],inpts[MAXPTS]; + Type sideA, sideB; + ptA = poly->Vertex (count - 1); + sideA = part->Classify_Point (ptA); + for (MiI32 i = -1; ++i < count;) + { + ptB = poly->Vertex(i); + sideB = part->Classify_Point(ptB); + if (sideB > 0) + { + if (sideA < 0) + { + point<Type> v; + fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); + outpts[out_c++] = inpts[in_c++] = v; + } + outpts[out_c++] = ptB; + } + else if (sideB < 0) + { + if (sideA > 0) + { + point<Type> v; + fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); + outpts[out_c++] = inpts[in_c++] = v; + } + inpts[in_c++] = ptB; + } + else + outpts[out_c++] = inpts[in_c++] = ptB; + ptA = ptB; + sideA = sideB; + } + + front.set(&outpts[0], out_c); + back.set(&inpts[0], in_c); + } + + MiI32 mVcount; + point<Type> mVertices[MAXPTS]; +}; + + + +#endif + +static inline void add(const REAL *p,REAL *dest,MiU32 tstride,MiU32 &pcount) +{ + char *d = (char *) dest; + d = d + pcount*tstride; + dest = (REAL *) d; + dest[0] = p[0]; + dest[1] = p[1]; + dest[2] = p[2]; + pcount++; + assert( pcount <= 4 ); +} + + +PlaneTriResult fm_planeTriIntersection(const REAL *_plane, // the plane equation in Ax+By+Cz+D format + const REAL *triangle, // the source triangle. + MiU32 tstride, // stride in bytes of the input and output *vertices* + REAL epsilon, // the co-planar epsilon value. + REAL *front, // the triangle in front of the + MiU32 &fcount, // number of vertices in the 'front' triangle + REAL *back, // the triangle in back of the plane + MiU32 &bcount) // the number of vertices in the 'back' triangle. +{ + + fcount = 0; + bcount = 0; + + const char *tsource = (const char *) triangle; + + // get the three vertices of the triangle. + const REAL *p1 = (const REAL *) (tsource); + const REAL *p2 = (const REAL *) (tsource+tstride); + const REAL *p3 = (const REAL *) (tsource+tstride*2); + + + PlaneTriResult r1 = fm_getSidePlane(p1,_plane,epsilon); // compute the side of the plane each vertex is on + PlaneTriResult r2 = fm_getSidePlane(p2,_plane,epsilon); + PlaneTriResult r3 = fm_getSidePlane(p3,_plane,epsilon); + + // If any of the points lay right *on* the plane.... + if ( r1 == PTR_ON_PLANE || r2 == PTR_ON_PLANE || r3 == PTR_ON_PLANE ) + { + // If the triangle is completely co-planar, then just treat it as 'front' and return! + if ( r1 == PTR_ON_PLANE && r2 == PTR_ON_PLANE && r3 == PTR_ON_PLANE ) + { + add(p1,front,tstride,fcount); + add(p2,front,tstride,fcount); + add(p3,front,tstride,fcount); + return PTR_FRONT; + } + // Decide to place the co-planar points on the same side as the co-planar point. + PlaneTriResult r= PTR_ON_PLANE; + if ( r1 != PTR_ON_PLANE ) + r = r1; + else if ( r2 != PTR_ON_PLANE ) + r = r2; + else if ( r3 != PTR_ON_PLANE ) + r = r3; + + if ( r1 == PTR_ON_PLANE ) r1 = r; + if ( r2 == PTR_ON_PLANE ) r2 = r; + if ( r3 == PTR_ON_PLANE ) r3 = r; + + } + + if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane. + { + if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle. + { + add(p1,front,tstride,fcount); + add(p2,front,tstride,fcount); + add(p3,front,tstride,fcount); + } + else + { + add(p1,back,tstride,bcount); // if all three are in 'back' then copy to the 'back' output triangle. + add(p2,back,tstride,bcount); + add(p3,back,tstride,bcount); + } + return r1; // if all three points are on the same side of the plane return result + } + + + polygon<REAL> pi(p1,p2,p3); + polygon<REAL> pfront,pback; + + plane<REAL> part(_plane); + + pi.Split_Polygon(&pi,&part,pfront,pback); + + for (MiI32 i=0; i<pfront.mVcount; i++) + { + add( &pfront.mVertices[i].x, front, tstride, fcount ); + } + + for (MiI32 i=0; i<pback.mVcount; i++) + { + add( &pback.mVertices[i].x, back, tstride, bcount ); + } + + PlaneTriResult ret = PTR_SPLIT; + + if ( fcount < 3 ) fcount = 0; + if ( bcount < 3 ) bcount = 0; + + if ( fcount == 0 && bcount ) + ret = PTR_BACK; + + if ( bcount == 0 && fcount ) + ret = PTR_FRONT; + + + return ret; +} + +// computes the OBB for this set of points relative to this transform matrix. +void computeOBB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *sides,REAL *matrix) +{ + const char *src = (const char *) points; + + REAL bmin[3] = { 1e9, 1e9, 1e9 }; + REAL bmax[3] = { -1e9, -1e9, -1e9 }; + + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *) src; + REAL t[3]; + + fm_inverseRT(matrix, p, t ); // inverse rotate translate + + if ( t[0] < bmin[0] ) bmin[0] = t[0]; + if ( t[1] < bmin[1] ) bmin[1] = t[1]; + if ( t[2] < bmin[2] ) bmin[2] = t[2]; + + if ( t[0] > bmax[0] ) bmax[0] = t[0]; + if ( t[1] > bmax[1] ) bmax[1] = t[1]; + if ( t[2] > bmax[2] ) bmax[2] = t[2]; + + src+=pstride; + } + + REAL center[3]; + + sides[0] = bmax[0]-bmin[0]; + sides[1] = bmax[1]-bmin[1]; + sides[2] = bmax[2]-bmin[2]; + + center[0] = sides[0]*0.5f+bmin[0]; + center[1] = sides[1]*0.5f+bmin[1]; + center[2] = sides[2]*0.5f+bmin[2]; + + REAL ocenter[3]; + + fm_rotate(matrix,center,ocenter); + + matrix[12]+=ocenter[0]; + matrix[13]+=ocenter[1]; + matrix[14]+=ocenter[2]; + +} + +void fm_computeBestFitOBB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *sides,REAL *matrix,bool bruteForce) +{ + REAL plane[4]; + fm_computeBestFitPlane(vcount,points,pstride,0,0,plane); + fm_planeToMatrix(plane,matrix); + computeOBB( vcount, points, pstride, sides, matrix ); + + REAL refmatrix[16]; + memcpy(refmatrix,matrix,16*sizeof(REAL)); + + REAL volume = sides[0]*sides[1]*sides[2]; + if ( bruteForce ) + { + for (REAL a=10; a<180; a+=10) + { + REAL quat[4]; + fm_eulerToQuat(0,a*FM_DEG_TO_RAD,0,quat); + REAL temp[16]; + REAL pmatrix[16]; + fm_quatToMatrix(quat,temp); + fm_matrixMultiply(temp,refmatrix,pmatrix); + REAL psides[3]; + computeOBB( vcount, points, pstride, psides, pmatrix ); + REAL v = psides[0]*psides[1]*psides[2]; + if ( v < volume ) + { + volume = v; + memcpy(matrix,pmatrix,sizeof(REAL)*16); + sides[0] = psides[0]; + sides[1] = psides[1]; + sides[2] = psides[2]; + } + } + } +} + +void fm_computeBestFitOBB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *sides,REAL *pos,REAL *quat,bool bruteForce) +{ + REAL matrix[16]; + fm_computeBestFitOBB(vcount,points,pstride,sides,matrix,bruteForce); + fm_getTranslation(matrix,pos); + fm_matrixToQuat(matrix,quat); +} + +void fm_computeBestFitABB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *sides,REAL *pos) +{ + REAL bmin[3]; + REAL bmax[3]; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + const char *cp = (const char *) points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *) cp; + + if ( p[0] < bmin[0] ) bmin[0] = p[0]; + if ( p[1] < bmin[1] ) bmin[1] = p[1]; + if ( p[2] < bmin[2] ) bmin[2] = p[2]; + + if ( p[0] > bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + cp+=pstride; + } + + + sides[0] = bmax[0] - bmin[0]; + sides[1] = bmax[1] - bmin[1]; + sides[2] = bmax[2] - bmin[2]; + + pos[0] = bmin[0]+sides[0]*0.5f; + pos[1] = bmin[1]+sides[1]*0.5f; + pos[2] = bmin[2]+sides[2]*0.5f; + +} + + +void fm_planeToMatrix(const REAL *plane,REAL *matrix) // convert a plane equation to a 4x4 rotation matrix +{ + REAL ref[3] = { 0, 1, 0 }; + REAL quat[4]; + fm_rotationArc(ref,plane,quat); + fm_quatToMatrix(quat,matrix); + REAL origin[3] = { 0, -plane[3], 0 }; + REAL center[3]; + fm_transform(matrix,origin,center); + fm_setTranslation(center,matrix); +} + +void fm_planeToQuat(const REAL *plane,REAL *quat,REAL *pos) // convert a plane equation to a quaternion and translation +{ + REAL ref[3] = { 0, 1, 0 }; + REAL matrix[16]; + fm_rotationArc(ref,plane,quat); + fm_quatToMatrix(quat,matrix); + REAL origin[3] = { 0, plane[3], 0 }; + fm_transform(matrix,origin,pos); +} + +void fm_eulerMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) +{ + REAL quat[4]; + fm_eulerToQuat(ax,ay,az,quat); + fm_quatToMatrix(quat,matrix); +} + + +//********************************************************** +//********************************************************** +//**** Vertex Welding +//********************************************************** +//********************************************************** + +#ifndef VERTEX_INDEX_H + +#define VERTEX_INDEX_H + +namespace VERTEX_INDEX +{ + +class KdTreeNode; + +typedef STDNAME::vector< KdTreeNode * > KdTreeNodeVector; + +enum Axes +{ + X_AXIS = 0, + Y_AXIS = 1, + Z_AXIS = 2 +}; + +class KdTreeFindNode +{ +public: + KdTreeFindNode(void) + { + mNode = 0; + mDistance = 0; + } + KdTreeNode *mNode; + MiF64 mDistance; +}; + +class KdTreeInterface +{ +public: + virtual const MiF64 * getPositionDouble(MiU32 index) const = 0; + virtual const MiF32 * getPositionFloat(MiU32 index) const = 0; +}; + +class KdTreeNode +{ +public: + KdTreeNode(void) + { + mIndex = 0; + mLeft = 0; + mRight = 0; + } + + KdTreeNode(MiU32 index) + { + mIndex = index; + mLeft = 0; + mRight = 0; + }; + + ~KdTreeNode(void) + { + } + + + void addDouble(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) + { + const MiF64 *nodePosition = iface->getPositionDouble( node->mIndex ); + const MiF64 *position = iface->getPositionDouble( mIndex ); + switch ( dim ) + { + case X_AXIS: + if ( nodePosition[0] <= position[0] ) + { + if ( mLeft ) + mLeft->addDouble(node,Y_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,Y_AXIS,iface); + else + mRight = node; + } + break; + case Y_AXIS: + if ( nodePosition[1] <= position[1] ) + { + if ( mLeft ) + mLeft->addDouble(node,Z_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,Z_AXIS,iface); + else + mRight = node; + } + break; + case Z_AXIS: + if ( nodePosition[2] <= position[2] ) + { + if ( mLeft ) + mLeft->addDouble(node,X_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,X_AXIS,iface); + else + mRight = node; + } + break; + } + + } + + + void addFloat(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) + { + const MiF32 *nodePosition = iface->getPositionFloat( node->mIndex ); + const MiF32 *position = iface->getPositionFloat( mIndex ); + switch ( dim ) + { + case X_AXIS: + if ( nodePosition[0] <= position[0] ) + { + if ( mLeft ) + mLeft->addFloat(node,Y_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,Y_AXIS,iface); + else + mRight = node; + } + break; + case Y_AXIS: + if ( nodePosition[1] <= position[1] ) + { + if ( mLeft ) + mLeft->addFloat(node,Z_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,Z_AXIS,iface); + else + mRight = node; + } + break; + case Z_AXIS: + if ( nodePosition[2] <= position[2] ) + { + if ( mLeft ) + mLeft->addFloat(node,X_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,X_AXIS,iface); + else + mRight = node; + } + break; + } + + } + + + MiU32 getIndex(void) const { return mIndex; }; + + void search(Axes axis,const MiF64 *pos,MiF64 radius,MiU32 &count,MiU32 maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) + { + + const MiF64 *position = iface->getPositionDouble(mIndex); + + MiF64 dx = pos[0] - position[0]; + MiF64 dy = pos[1] - position[1]; + MiF64 dz = pos[2] - position[2]; + + KdTreeNode *search1 = 0; + KdTreeNode *search2 = 0; + + switch ( axis ) + { + case X_AXIS: + if ( dx <= 0 ) // JWR if we are to the left + { + search1 = mLeft; // JWR then search to the left + if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. + search2 = mRight; + } + else + { + search1 = mRight; // JWR ok, we go down the left tree + if ( dx < radius ) // JWR if the distance from the right is less than our search radius + search2 = mLeft; + } + axis = Y_AXIS; + break; + case Y_AXIS: + if ( dy <= 0 ) + { + search1 = mLeft; + if ( -dy < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dy < radius ) + search2 = mLeft; + } + axis = Z_AXIS; + break; + case Z_AXIS: + if ( dz <= 0 ) + { + search1 = mLeft; + if ( -dz < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dz < radius ) + search2 = mLeft; + } + axis = X_AXIS; + break; + } + + MiF64 r2 = radius*radius; + MiF64 m = dx*dx+dy*dy+dz*dz; + + if ( m < r2 ) + { + switch ( count ) + { + case 0: + found[count].mNode = this; + found[count].mDistance = m; + break; + case 1: + if ( m < found[0].mDistance ) + { + if ( maxObjects == 1 ) + { + found[0].mNode = this; + found[0].mDistance = m; + } + else + { + found[1] = found[0]; + found[0].mNode = this; + found[0].mDistance = m; + } + } + else if ( maxObjects > 1) + { + found[1].mNode = this; + found[1].mDistance = m; + } + break; + default: + { + bool inserted = false; + + for (MiU32 i=0; i<count; i++) + { + if ( m < found[i].mDistance ) // if this one is closer than a pre-existing one... + { + // insertion sort... + MiU32 scan = count; + if ( scan >= maxObjects ) scan=maxObjects-1; + for (MiU32 j=scan; j>i; j--) + { + found[j] = found[j-1]; + } + found[i].mNode = this; + found[i].mDistance = m; + inserted = true; + break; + } + } + + if ( !inserted && count < maxObjects ) + { + found[count].mNode = this; + found[count].mDistance = m; + } + } + break; + } + count++; + if ( count > maxObjects ) + { + count = maxObjects; + } + } + + + if ( search1 ) + search1->search( axis, pos,radius, count, maxObjects, found, iface); + + if ( search2 ) + search2->search( axis, pos,radius, count, maxObjects, found, iface); + + } + + void search(Axes axis,const MiF32 *pos,MiF32 radius,MiU32 &count,MiU32 maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) + { + + const MiF32 *position = iface->getPositionFloat(mIndex); + + MiF32 dx = pos[0] - position[0]; + MiF32 dy = pos[1] - position[1]; + MiF32 dz = pos[2] - position[2]; + + KdTreeNode *search1 = 0; + KdTreeNode *search2 = 0; + + switch ( axis ) + { + case X_AXIS: + if ( dx <= 0 ) // JWR if we are to the left + { + search1 = mLeft; // JWR then search to the left + if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. + search2 = mRight; + } + else + { + search1 = mRight; // JWR ok, we go down the left tree + if ( dx < radius ) // JWR if the distance from the right is less than our search radius + search2 = mLeft; + } + axis = Y_AXIS; + break; + case Y_AXIS: + if ( dy <= 0 ) + { + search1 = mLeft; + if ( -dy < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dy < radius ) + search2 = mLeft; + } + axis = Z_AXIS; + break; + case Z_AXIS: + if ( dz <= 0 ) + { + search1 = mLeft; + if ( -dz < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dz < radius ) + search2 = mLeft; + } + axis = X_AXIS; + break; + } + + MiF32 r2 = radius*radius; + MiF32 m = dx*dx+dy*dy+dz*dz; + + if ( m < r2 ) + { + switch ( count ) + { + case 0: + found[count].mNode = this; + found[count].mDistance = m; + break; + case 1: + if ( m < found[0].mDistance ) + { + if ( maxObjects == 1 ) + { + found[0].mNode = this; + found[0].mDistance = m; + } + else + { + found[1] = found[0]; + found[0].mNode = this; + found[0].mDistance = m; + } + } + else if ( maxObjects > 1) + { + found[1].mNode = this; + found[1].mDistance = m; + } + break; + default: + { + bool inserted = false; + + for (MiU32 i=0; i<count; i++) + { + if ( m < found[i].mDistance ) // if this one is closer than a pre-existing one... + { + // insertion sort... + MiU32 scan = count; + if ( scan >= maxObjects ) scan=maxObjects-1; + for (MiU32 j=scan; j>i; j--) + { + found[j] = found[j-1]; + } + found[i].mNode = this; + found[i].mDistance = m; + inserted = true; + break; + } + } + + if ( !inserted && count < maxObjects ) + { + found[count].mNode = this; + found[count].mDistance = m; + } + } + break; + } + count++; + if ( count > maxObjects ) + { + count = maxObjects; + } + } + + + if ( search1 ) + search1->search( axis, pos,radius, count, maxObjects, found, iface); + + if ( search2 ) + search2->search( axis, pos,radius, count, maxObjects, found, iface); + + } + +private: + + void setLeft(KdTreeNode *left) { mLeft = left; }; + void setRight(KdTreeNode *right) { mRight = right; }; + + KdTreeNode *getLeft(void) { return mLeft; } + KdTreeNode *getRight(void) { return mRight; } + + MiU32 mIndex; + KdTreeNode *mLeft; + KdTreeNode *mRight; +}; + + +#define MAX_BUNDLE_SIZE 1024 // 1024 nodes at a time, to minimize memory allocation and guarentee that pointers are persistent. + +class KdTreeNodeBundle : public MeshImportAllocated +{ +public: + + KdTreeNodeBundle(void) + { + mNext = 0; + mIndex = 0; + } + + bool isFull(void) const + { + return (bool)( mIndex == MAX_BUNDLE_SIZE ); + } + + KdTreeNode * getNextNode(void) + { + assert(mIndex<MAX_BUNDLE_SIZE); + KdTreeNode *ret = &mNodes[mIndex]; + mIndex++; + return ret; + } + + KdTreeNodeBundle *mNext; + MiU32 mIndex; + KdTreeNode mNodes[MAX_BUNDLE_SIZE]; +}; + + +typedef STDNAME::vector< MiF64 > DoubleVector; +typedef STDNAME::vector< MiF32 > FloatVector; + +class KdTree : public KdTreeInterface, public MeshImportAllocated +{ +public: + KdTree(void) + { + mRoot = 0; + mBundle = 0; + mVcount = 0; + mUseDouble = false; + } + + virtual ~KdTree(void) + { + reset(); + } + + const MiF64 * getPositionDouble(MiU32 index) const + { + assert( mUseDouble ); + assert ( index < mVcount ); + return &mVerticesDouble[index*3]; + } + + const MiF32 * getPositionFloat(MiU32 index) const + { + assert( !mUseDouble ); + assert ( index < mVcount ); + return &mVerticesFloat[index*3]; + } + + MiU32 search(const MiF64 *pos,MiF64 radius,MiU32 maxObjects,KdTreeFindNode *found) const + { + assert( mUseDouble ); + if ( !mRoot ) return 0; + MiU32 count = 0; + mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); + return count; + } + + MiU32 search(const MiF32 *pos,MiF32 radius,MiU32 maxObjects,KdTreeFindNode *found) const + { + assert( !mUseDouble ); + if ( !mRoot ) return 0; + MiU32 count = 0; + mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); + return count; + } + + void reset(void) + { + mRoot = 0; + mVerticesDouble.clear(); + mVerticesFloat.clear(); + KdTreeNodeBundle *bundle = mBundle; + while ( bundle ) + { + KdTreeNodeBundle *next = bundle->mNext; + delete bundle; + bundle = next; + } + mBundle = 0; + mVcount = 0; + } + + MiU32 add(MiF64 x,MiF64 y,MiF64 z) + { + assert(mUseDouble); + MiU32 ret = mVcount; + mVerticesDouble.push_back(x); + mVerticesDouble.push_back(y); + mVerticesDouble.push_back(z); + mVcount++; + KdTreeNode *node = getNewNode(ret); + if ( mRoot ) + { + mRoot->addDouble(node,X_AXIS,this); + } + else + { + mRoot = node; + } + return ret; + } + + MiU32 add(MiF32 x,MiF32 y,MiF32 z) + { + assert(!mUseDouble); + MiU32 ret = mVcount; + mVerticesFloat.push_back(x); + mVerticesFloat.push_back(y); + mVerticesFloat.push_back(z); + mVcount++; + KdTreeNode *node = getNewNode(ret); + if ( mRoot ) + { + mRoot->addFloat(node,X_AXIS,this); + } + else + { + mRoot = node; + } + return ret; + } + + KdTreeNode * getNewNode(MiU32 index) + { + if ( mBundle == 0 ) + { + mBundle = MI_NEW(KdTreeNodeBundle); + } + if ( mBundle->isFull() ) + { + KdTreeNodeBundle *bundle = MI_NEW(KdTreeNodeBundle); + mBundle->mNext = bundle; + mBundle = bundle; + } + KdTreeNode *node = mBundle->getNextNode(); + new ( node ) KdTreeNode(index); + return node; + } + + MiU32 getNearest(const MiF64 *pos,MiF64 radius,bool &_found) const // returns the nearest possible neighbor's index. + { + assert( mUseDouble ); + MiU32 ret = 0; + + _found = false; + KdTreeFindNode found[1]; + MiU32 count = search(pos,radius,1,found); + if ( count ) + { + KdTreeNode *node = found[0].mNode; + ret = node->getIndex(); + _found = true; + } + return ret; + } + + MiU32 getNearest(const MiF32 *pos,MiF32 radius,bool &_found) const // returns the nearest possible neighbor's index. + { + assert( !mUseDouble ); + MiU32 ret = 0; + + _found = false; + KdTreeFindNode found[1]; + MiU32 count = search(pos,radius,1,found); + if ( count ) + { + KdTreeNode *node = found[0].mNode; + ret = node->getIndex(); + _found = true; + } + return ret; + } + + const MiF64 * getVerticesDouble(void) const + { + assert( mUseDouble ); + const MiF64 *ret = 0; + if ( !mVerticesDouble.empty() ) + { + ret = &mVerticesDouble[0]; + } + return ret; + } + + const MiF32 * getVerticesFloat(void) const + { + assert( !mUseDouble ); + const MiF32 * ret = 0; + if ( !mVerticesFloat.empty() ) + { + ret = &mVerticesFloat[0]; + } + return ret; + } + + MiU32 getVcount(void) const { return mVcount; }; + + void setUseDouble(bool useDouble) + { + mUseDouble = useDouble; + } + +private: + bool mUseDouble; + KdTreeNode *mRoot; + KdTreeNodeBundle *mBundle; + MiU32 mVcount; + DoubleVector mVerticesDouble; + FloatVector mVerticesFloat; +}; + +}; // end of namespace VERTEX_INDEX + +class MyVertexIndex : public fm_VertexIndex, public MeshImportAllocated +{ +public: + MyVertexIndex(MiF64 granularity,bool snapToGrid) + { + mDoubleGranularity = granularity; + mFloatGranularity = (MiF32)granularity; + mSnapToGrid = snapToGrid; + mUseDouble = true; + mKdTree.setUseDouble(true); + } + + MyVertexIndex(MiF32 granularity,bool snapToGrid) + { + mDoubleGranularity = granularity; + mFloatGranularity = (MiF32)granularity; + mSnapToGrid = snapToGrid; + mUseDouble = false; + mKdTree.setUseDouble(false); + } + + virtual ~MyVertexIndex(void) + { + + } + + + MiF64 snapToGrid(MiF64 p) + { + MiF64 m = fmod(p,mDoubleGranularity); + p-=m; + return p; + } + + MiF32 snapToGrid(MiF32 p) + { + MiF32 m = fmodf(p,mFloatGranularity); + p-=m; + return p; + } + + MiU32 getIndex(const MiF32 *_p,bool &newPos) // get index for a vector MiF32 + { + MiU32 ret; + + if ( mUseDouble ) + { + MiF64 p[3]; + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + return getIndex(p,newPos); + } + + newPos = false; + + MiF32 p[3]; + + if ( mSnapToGrid ) + { + p[0] = snapToGrid(_p[0]); + p[1] = snapToGrid(_p[1]); + p[2] = snapToGrid(_p[2]); + } + else + { + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + } + + bool found; + ret = mKdTree.getNearest(p,mFloatGranularity,found); + if ( !found ) + { + newPos = true; + ret = mKdTree.add(p[0],p[1],p[2]); + } + + + return ret; + } + + MiU32 getIndex(const MiF64 *_p,bool &newPos) // get index for a vector MiF64 + { + MiU32 ret; + + if ( !mUseDouble ) + { + MiF32 p[3]; + p[0] = (MiF32)_p[0]; + p[1] = (MiF32)_p[1]; + p[2] = (MiF32)_p[2]; + return getIndex(p,newPos); + } + + newPos = false; + + MiF64 p[3]; + + if ( mSnapToGrid ) + { + p[0] = snapToGrid(_p[0]); + p[1] = snapToGrid(_p[1]); + p[2] = snapToGrid(_p[2]); + } + else + { + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + } + + bool found; + ret = mKdTree.getNearest(p,mDoubleGranularity,found); + if ( !found ) + { + newPos = true; + ret = mKdTree.add(p[0],p[1],p[2]); + } + + + return ret; + } + + const MiF32 * getVerticesFloat(void) const + { + const MiF32 * ret = 0; + + assert( !mUseDouble ); + + ret = mKdTree.getVerticesFloat(); + + return ret; + } + + const MiF64 * getVerticesDouble(void) const + { + const MiF64 * ret = 0; + + assert( mUseDouble ); + + ret = mKdTree.getVerticesDouble(); + + return ret; + } + + const MiF32 * getVertexFloat(MiU32 index) const + { + const MiF32 * ret = 0; + assert( !mUseDouble ); +#ifdef _DEBUG + MiU32 vcount = mKdTree.getVcount(); + assert( index < vcount ); +#endif + ret = mKdTree.getVerticesFloat(); + ret = &ret[index*3]; + return ret; + } + + const MiF64 * getVertexDouble(MiU32 index) const + { + const MiF64 * ret = 0; + assert( mUseDouble ); +#ifdef _DEBUG + MiU32 vcount = mKdTree.getVcount(); + assert( index < vcount ); +#endif + ret = mKdTree.getVerticesDouble(); + ret = &ret[index*3]; + + return ret; + } + + MiU32 getVcount(void) const + { + return mKdTree.getVcount(); + } + + bool isDouble(void) const + { + return mUseDouble; + } + + + bool saveAsObj(const char *fname,MiU32 tcount,MiU32 *indices) + { + bool ret = false; + + + FILE *fph = fopen(fname,"wb"); + if ( fph ) + { + ret = true; + + MiU32 vcount = getVcount(); + if ( mUseDouble ) + { + const MiF64 *v = getVerticesDouble(); + for (MiU32 i=0; i<vcount; i++) + { + fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", (MiF32)v[0], (MiF32)v[1], (MiF32)v[2] ); + v+=3; + } + } + else + { + const MiF32 *v = getVerticesFloat(); + for (MiU32 i=0; i<vcount; i++) + { + fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", v[0], v[1], v[2] ); + v+=3; + } + } + + for (MiU32 i=0; i<tcount; i++) + { + MiU32 i1 = *indices++; + MiU32 i2 = *indices++; + MiU32 i3 = *indices++; + fprintf(fph,"f %d %d %d\r\n", i1+1, i2+1, i3+1 ); + } + fclose(fph); + } + + return ret; + } + +private: + bool mUseDouble:1; + bool mSnapToGrid:1; + MiF64 mDoubleGranularity; + MiF32 mFloatGranularity; + VERTEX_INDEX::KdTree mKdTree; +}; + +fm_VertexIndex * fm_createVertexIndex(MiF64 granularity,bool snapToGrid) // create an indexed vertex system for doubles +{ + MyVertexIndex *ret = MI_NEW(MyVertexIndex)(granularity,snapToGrid); + return static_cast< fm_VertexIndex *>(ret); +} + +fm_VertexIndex * fm_createVertexIndex(MiF32 granularity,bool snapToGrid) // create an indexed vertext system for floats +{ + MyVertexIndex *ret = MI_NEW(MyVertexIndex)(granularity,snapToGrid); + return static_cast< fm_VertexIndex *>(ret); +} + +void fm_releaseVertexIndex(fm_VertexIndex *vindex) +{ + MyVertexIndex *m = static_cast< MyVertexIndex *>(vindex); + delete m; +} + +#endif // END OF VERTEX WELDING CODE + + +//********************************************************** +//********************************************************** +//**** LineSweep Line-Segment Intersection Code +//********************************************************** +//********************************************************** + +//#ifndef LINE_SWEEP_H +#if 0 + +#define LINE_SWEEP_H + +class fm_quickSort +{ +public: + void qsort(void **base,MiI32 num); // perform the qsort. +protected: + // -1 less, 0 equal, +1 greater. + virtual MiI32 compare(void **p1,void **p2) = 0; +private: + void inline swap(char **a,char **b); +}; + + +void fm_quickSort::swap(char **a,char **b) +{ + char *tmp; + + if ( a != b ) + { + tmp = *a; + *a++ = *b; + *b++ = tmp; + } +} + + +void fm_quickSort::qsort(void **b,MiI32 num) +{ + char *lo,*hi; + char *mid; + char *bottom, *top; + MiI32 size; + char *lostk[30], *histk[30]; + MiI32 stkptr; + char **base = (char **)b; + + if (num < 2 ) return; + + stkptr = 0; + + lo = (char *)base; + hi = (char *)base + sizeof(char **) * (num-1); + +nextone: + + size = (MiI32)(hi - lo) / sizeof(char**) + 1; + + mid = lo + (size / 2) * sizeof(char **); + swap((char **)mid,(char **)lo); + bottom = lo; + top = hi + sizeof(char **); + + for (;;) + { + do + { + bottom += sizeof(char **); + } while (bottom <= hi && compare((void **)bottom,(void **)lo) <= 0); + + do + { + top -= sizeof(char **); + } while (top > lo && compare((void **)top,(void **)lo) >= 0); + + if (top < bottom) break; + + swap((char **)bottom,(char **)top); + + } + + swap((char **)lo,(char **)top); + + if ( top - 1 - lo >= hi - bottom ) + { + if (lo + sizeof(char **) < top) + { + lostk[stkptr] = lo; + histk[stkptr] = top - sizeof(char **); + stkptr++; + } + if (bottom < hi) + { + lo = bottom; + goto nextone; + } + } + else + { + if ( bottom < hi ) + { + lostk[stkptr] = bottom; + histk[stkptr] = hi; + stkptr++; + } + if (lo + sizeof(char **) < top) + { + hi = top - sizeof(char **); + goto nextone; /* do small recursion */ + } + } + + stkptr--; + + if (stkptr >= 0) + { + lo = lostk[stkptr]; + hi = histk[stkptr]; + goto nextone; + } + return; +} + + +typedef STDNAME::vector< fm_LineSegment > LineSegmentVector; + +static inline void setMinMax(MiF64 &vmin,MiF64 &vmax,MiF64 v1,MiF64 v2) +{ + if ( v1 <= v2 ) + { + vmin = v1; + vmax = v2; + } + else + { + vmin = v2; + vmax = v1; + } +} + + +class Intersection +{ +public: + Intersection(void) + { + mIndex = 0; + mTime = 0; + } + Intersection(MiF64 time,const MiF64 *from,const MiF64 *to,fm_VertexIndex *vpool) + { + mTime = time; + MiF64 pos[3]; + pos[0] = (to[0]-from[0])*time+from[0]; + pos[1] = (to[1]-from[1])*time+from[1]; + pos[2] = (to[2]-from[2])*time+from[2]; + bool newPos; + mIndex = vpool->getIndex(pos,newPos); + } + + MiU32 mIndex; + MiF64 mTime; +}; + + +typedef STDNAME::vector< Intersection > IntersectionList; + +class MyLineSegment : public fm_LineSegment, public MeshImportAllocated +{ +public: + + void init(const fm_LineSegment &s,fm_VertexIndex *vpool,MiU32 x) + { + fm_LineSegment *dest = static_cast< fm_LineSegment *>(this); + *dest = s; + + mFlipped = false; + + const MiF64 *p1 = vpool->getVertexDouble(mE1); + const MiF64 *p2 = vpool->getVertexDouble(mE2); + + setMinMax(mMin[0],mMax[0],p1[0],p2[0]); + setMinMax(mMin[1],mMax[1],p1[1],p2[1]); + setMinMax(mMin[2],mMax[2],p1[2],p2[2]); + + if ( p1[x] <= p2[x] ) + { + mFrom[0] = p1[0]; + mFrom[1] = p1[1]; + mFrom[2] = p1[2]; + + mTo[0] = p2[0]; + mTo[1] = p2[1]; + mTo[2] = p2[2]; + } + else + { + mFrom[0] = p2[0]; + mFrom[1] = p2[1]; + mFrom[2] = p2[2]; + + mTo[0] = p1[0]; + mTo[1] = p1[1]; + mTo[2] = p1[2]; + + mFlipped = true; + + swap(mE1,mE2); + } + + } + + // we already know that the x-extent overlaps or we wouldn't be in this routine.. + void intersect(MyLineSegment *segment,MiU32 x,MiU32 y,MiU32 /* z */,fm_VertexIndex *vpool) + { + MiU32 count = 0; + + // if the two segments share any start/end points then they cannot intersect at all! + + if ( segment->mE1 == mE1 || segment->mE1 == mE2 ) count++; + if ( segment->mE2 == mE1 || segment->mE2 == mE2 ) count++; + + if ( count == 0 ) + { + if ( mMax[y] < segment->mMin[y] ) // no intersection... + { + + } + else if ( mMin[y] > segment->mMax[y] ) // no intersection + { + + } + else + { + + MiF64 a1[2]; + MiF64 a2[2]; + MiF64 b1[2]; + MiF64 b2[2]; + + a1[0] = mFrom[x]; + a1[1] = mFrom[y]; + + a2[0] = mTo[x]; + a2[1] = mTo[y]; + + b1[0] = segment->mFrom[x]; + b1[1] = segment->mFrom[y]; + + b2[0] = segment->mTo[x]; + b2[1] = segment->mTo[y]; + + + MiF64 t1,t2; + IntersectResult result = fm_intersectLineSegments2dTime(a1,a2,b1,b2,t1,t2); + + if ( result == IR_DO_INTERSECT ) + { + addIntersect(t1,vpool); + segment->addIntersect(t2,vpool); + } + + + } + } + } + + void addIntersect(MiF64 time,fm_VertexIndex *vpool) + { + Intersection intersect(time,mFrom,mTo,vpool); + + if ( mE1 == intersect.mIndex || mE2 == intersect.mIndex ) + { + //printf("Split too close to the beginning or the end of the line segment.\r\n"); + } + else + { + if ( mIntersections.empty() ) + { + mIntersections.push_back(intersect); + } + else + { + IntersectionList::iterator i; + for (i=mIntersections.begin(); i!=mIntersections.end(); ++i) + { + Intersection &it = (*i); + if ( it.mIndex == intersect.mIndex ) + { + //printf("Duplicate Intersection, throwing it away.\r\n"); + break; + } + else + { + if ( it.mTime > time ) + { +//*** TODO TODO TODO mIntersections.insert(i,intersect); + break; + } + } + } + if ( i==mIntersections.end() ) + { + mIntersections.push_back(intersect); + } + } + } + } + + void getResults(LineSegmentVector &results) + { + if ( mIntersections.empty() ) + { + fm_LineSegment seg(mE1,mE2); + if ( mFlipped ) + { + swap(seg.mE1,seg.mE2); + } + results.push_back(seg); + } + else + { + MiU32 prev = mE1; + IntersectionList::iterator i; + for (i=mIntersections.begin(); i!=mIntersections.end(); ++i) + { + Intersection &it = (*i); + fm_LineSegment seg(prev,it.mIndex); + if ( mFlipped ) + { + swap(seg.mE1,seg.mE2); + } + results.push_back(seg); + prev = it.mIndex; + } + fm_LineSegment seg(prev,mE2); + if ( mFlipped ) + { + swap(seg.mE1,seg.mE2); + } + results.push_back(seg); + } + } + + void swap(MiU32 &a,MiU32 &b) + { + MiU32 temp = a; + a = b; + b = temp; + } + + bool mFlipped; + MiF64 mFrom[3]; + MiF64 mTo[3]; + MiF64 mMin[3]; + MiF64 mMax[3]; + IntersectionList mIntersections; +}; + +typedef STDNAME::vector< MyLineSegment > MyLineSegmentVector; + +class MyLineSweep : public fm_LineSweep, public fm_quickSort, public MeshImportAllocated +{ +public: + virtual ~MyLineSweep(void) + { + + } + fm_LineSegment * performLineSweep(const fm_LineSegment *segments,MiU32 icount,const MiF64 *planeEquation,fm_VertexIndex *pool,MiU32 &scount) + { + fm_LineSegment *ret = 0; + + FM_Axis axis = fm_getDominantAxis(planeEquation); + switch ( axis ) + { + case FM_XAXIS: + mX = 1; + mY = 2; + mZ = 0; + break; + case FM_YAXIS: + mX = 0; + mY = 2; + mZ = 1; + break; + case FM_ZAXIS: + mX = 0; + mY = 1; + mZ = 2; + break; + } + + + mResults.clear(); + scount = 0; + + MyLineSegment *mls = MI_NEW(MyLineSegment)[icount]; + MyLineSegment **mptr = (MyLineSegment **)MI_ALLOC(sizeof(MyLineSegment *)*icount); + + for (MiU32 i=0; i<icount; i++) + { + mls[i].init(segments[i],pool,mX); + mptr[i] = &mls[i]; + } + + qsort((void **)mptr,(MiI32)icount); + + for (MiU32 i=0; i<icount; i++) + { + MyLineSegment *segment = mptr[i]; + MiF64 esegment = segment->mTo[mX]; + for (MiU32 j=i+1; j<icount; j++) + { + MyLineSegment *test = mptr[j]; + if ( test->mFrom[mX] >= esegment ) + { + break; + } + else + { + test->intersect(segment,mX,mY,mZ,pool); + } + } + } + + for (MiU32 i=0; i<icount; i++) + { + MyLineSegment *segment = mptr[i]; + segment->getResults(mResults); + } + + + delete []mls; + MI_FREE(mptr); + + if ( !mResults.empty() ) + { + scount = (MiU32)mResults.size(); + ret = &mResults[0]; + } + + return ret; + } + + MiI32 compare(void **p1,void **p2) + { + MiI32 ret = 0; + + MyLineSegment **m1 = (MyLineSegment **) p1; + MyLineSegment **m2 = (MyLineSegment **) p2; + + MyLineSegment *s1 = *m1; + MyLineSegment *s2 = *m2; + + if ( s1->mFrom[mX] < s2->mFrom[mX] ) + ret = -1; + else if ( s1->mFrom[mX] > s2->mFrom[mX] ) + ret = 1; + else if ( s1->mFrom[mY] < s2->mFrom[mY] ) + ret = -1; + else if ( s1->mFrom[mY] > s2->mFrom[mY] ) + ret = 1; + + return ret; + } + + MiU32 mX; // index for the x-axis + MiU32 mY; // index for the y-axis + MiU32 mZ; + fm_VertexIndex *mfm_VertexIndex; + LineSegmentVector mResults; +}; + + +fm_LineSweep * fm_createLineSweep(void) +{ + MyLineSweep *mls = MI_NEW(MyLineSweep); + return static_cast< fm_LineSweep *>(mls); +} + +void fm_releaseLineSweep(fm_LineSweep *sweep) +{ + MyLineSweep *mls = static_cast< MyLineSweep *>(sweep); + delete mls; +} + + + +#endif // End of LineSweep code + + + + +REAL fm_computeBestFitAABB(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *bmin,REAL *bmax) // returns the diagonal distance +{ + + const MiU8 *source = (const MiU8 *) points; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + + for (MiU32 i=1; i<vcount; i++) + { + source+=pstride; + const REAL *p = (const REAL *) source; + + if ( p[0] < bmin[0] ) bmin[0] = p[0]; + if ( p[1] < bmin[1] ) bmin[1] = p[1]; + if ( p[2] < bmin[2] ) bmin[2] = p[2]; + + if ( p[0] > bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + } + + REAL dx = bmax[0] - bmin[0]; + REAL dy = bmax[1] - bmin[1]; + REAL dz = bmax[2] - bmin[2]; + + return (REAL) ::sqrt( dx*dx + dy*dy + dz*dz ); + +} + + + +/* a = b - c */ +#define vector(a,b,c) \ + (a)[0] = (b)[0] - (c)[0]; \ + (a)[1] = (b)[1] - (c)[1]; \ + (a)[2] = (b)[2] - (c)[2]; + + + +#define innerProduct(v,q) \ + ((v)[0] * (q)[0] + \ + (v)[1] * (q)[1] + \ + (v)[2] * (q)[2]) + +#define crossProduct(a,b,c) \ + (a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \ + (a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \ + (a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1]; + + +bool fm_lineIntersectsTriangle(const REAL *rayStart,const REAL *rayEnd,const REAL *p1,const REAL *p2,const REAL *p3,REAL *sect) +{ + REAL dir[3]; + + dir[0] = rayEnd[0] - rayStart[0]; + dir[1] = rayEnd[1] - rayStart[1]; + dir[2] = rayEnd[2] - rayStart[2]; + + REAL d = (REAL)::sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); + REAL r = 1.0f / d; + + dir[0]*=r; + dir[1]*=r; + dir[2]*=r; + + + REAL t; + + bool ret = fm_rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t ); + + if ( ret ) + { + if ( t > d ) + { + sect[0] = rayStart[0] + dir[0]*t; + sect[1] = rayStart[1] + dir[1]*t; + sect[2] = rayStart[2] + dir[2]*t; + } + else + { + ret = false; + } + } + + return ret; +} + + + +bool fm_rayIntersectsTriangle(const REAL *p,const REAL *d,const REAL *v0,const REAL *v1,const REAL *v2,REAL &t) +{ + REAL e1[3],e2[3],h[3],s[3],q[3]; + REAL a,f,u,v; + + vector(e1,v1,v0); + vector(e2,v2,v0); + crossProduct(h,d,e2); + a = innerProduct(e1,h); + + if (a > -0.00001 && a < 0.00001) + return(false); + + f = 1/a; + vector(s,p,v0); + u = f * (innerProduct(s,h)); + + if (u < 0.0 || u > 1.0) + return(false); + + crossProduct(q,s,e1); + v = f * innerProduct(d,q); + if (v < 0.0 || u + v > 1.0) + return(false); + // at this stage we can compute t to find out where + // the intersection point is on the line + t = f * innerProduct(e2,q); + if (t > 0) // ray intersection + return(true); + else // this means that there is a line intersection + // but not a ray intersection + return (false); +} + + +inline REAL det(const REAL *p1,const REAL *p2,const REAL *p3) +{ + return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2]; +} + + +REAL fm_computeMeshVolume(const REAL *vertices,MiU32 tcount,const MiU32 *indices) +{ + REAL volume = 0; + + for (MiU32 i=0; i<tcount; i++,indices+=3) + { + const REAL *p1 = &vertices[ indices[0]*3 ]; + const REAL *p2 = &vertices[ indices[1]*3 ]; + const REAL *p3 = &vertices[ indices[2]*3 ]; + volume+=det(p1,p2,p3); // compute the volume of the tetrahedran relative to the origin. + } + + volume*=(1.0f/6.0f); + if ( volume < 0 ) + volume*=-1; + return volume; +} + + +const REAL * fm_getPoint(const REAL *points,MiU32 pstride,MiU32 index) +{ + const MiU8 *scan = (const MiU8 *)points; + scan+=(index*pstride); + return (REAL *)scan; +} + + +bool fm_insideTriangle(REAL Ax, REAL Ay, + REAL Bx, REAL By, + REAL Cx, REAL Cy, + REAL Mi, REAL Py) + +{ + REAL ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; + REAL cCROSSap, bCROSScp, aCROSSbp; + + ax = Cx - Bx; ay = Cy - By; + bx = Ax - Cx; by = Ay - Cy; + cx = Bx - Ax; cy = By - Ay; + apx= Mi - Ax; apy= Py - Ay; + bpx= Mi - Bx; bpy= Py - By; + cpx= Mi - Cx; cpy= Py - Cy; + + aCROSSbp = ax*bpy - ay*bpx; + cCROSSap = cx*apy - cy*apx; + bCROSScp = bx*cpy - by*cpx; + + return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); +} + + +REAL fm_areaPolygon2d(MiU32 pcount,const REAL *points,MiU32 pstride) +{ + MiI32 n = (MiI32)pcount; + + REAL A=0.0f; + for(MiI32 p=n-1,q=0; q<n; p=q++) + { + const REAL *p1 = fm_getPoint(points,pstride,(MiU32)p); + const REAL *p2 = fm_getPoint(points,pstride,(MiU32)q); + A+= p1[0]*p2[1] - p2[0]*p1[1]; + } + return A*0.5f; +} + + +bool fm_pointInsidePolygon2d(MiU32 pcount,const REAL *points,MiU32 pstride,const REAL *point,MiU32 xindex,MiU32 yindex) +{ + MiU32 j = pcount-1; + MiI32 oddNodes = 0; + + REAL x = point[xindex]; + REAL y = point[yindex]; + + for (MiU32 i=0; i<pcount; i++) + { + const REAL *p1 = fm_getPoint(points,pstride,i); + const REAL *p2 = fm_getPoint(points,pstride,j); + + REAL x1 = p1[xindex]; + REAL y1 = p1[yindex]; + + REAL x2 = p2[xindex]; + REAL y2 = p2[yindex]; + + if ( (y1 < y && y2 >= y) || (y2 < y && y1 >= y) ) + { + if (x1+(y-y1)/(y2-y1)*(x2-x1)<x) + { + oddNodes = 1-oddNodes; + } + } + j = i; + } + + return oddNodes ? true : false; +} + + +MiU32 fm_consolidatePolygon(MiU32 pcount,const REAL *points,MiU32 pstride,REAL *_dest,REAL epsilon) // collapses co-linear edges. +{ + MiU32 ret = 0; + + + if ( pcount >= 3 ) + { + const REAL *prev = fm_getPoint(points,pstride,pcount-1); + const REAL *current = points; + const REAL *next = fm_getPoint(points,pstride,1); + REAL *dest = _dest; + + for (MiU32 i=0; i<pcount; i++) + { + + next = (i+1)==pcount ? points : next; + + if ( !fm_colinear(prev,current,next,epsilon) ) + { + dest[0] = current[0]; + dest[1] = current[1]; + dest[2] = current[2]; + + dest+=3; + ret++; + } + + prev = current; + current+=3; + next+=3; + + } + } + + return ret; +} + + +#ifndef RECT3D_TEMPLATE + +#define RECT3D_TEMPLATE + +template <class T> class Rect3d +{ +public: + Rect3d(void) { }; + + Rect3d(const T *bmin,const T *bmax) + { + + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + + } + + void SetMin(const T *bmin) + { + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + } + + void SetMax(const T *bmax) + { + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + } + + void SetMin(T x,T y,T z) + { + mMin[0] = x; + mMin[1] = y; + mMin[2] = z; + } + + void SetMax(T x,T y,T z) + { + mMax[0] = x; + mMax[1] = y; + mMax[2] = z; + } + + T mMin[3]; + T mMax[3]; +}; + +#endif + +void splitRect(MiU32 axis, + const Rect3d<REAL> &source, + Rect3d<REAL> &b1, + Rect3d<REAL> &b2, + const REAL *midpoint) +{ + switch ( axis ) + { + case 0: + b1.SetMin(source.mMin); + b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] ); + + b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] ); + b2.SetMax(source.mMax); + + break; + case 1: + b1.SetMin(source.mMin); + b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] ); + + b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] ); + b2.SetMax(source.mMax); + + break; + case 2: + b1.SetMin(source.mMin); + b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] ); + + b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] ); + b2.SetMax(source.mMax); + + break; + } +} + +bool fm_computeSplitPlane(MiU32 vcount, + const REAL *vertices, + MiU32 /* tcount */, + const MiU32 * /* indices */, + REAL *plane) +{ + + REAL sides[3]; + REAL matrix[16]; + + fm_computeBestFitOBB( vcount, vertices, sizeof(REAL)*3, sides, matrix ); + + REAL bmax[3]; + REAL bmin[3]; + + bmax[0] = sides[0]*0.5f; + bmax[1] = sides[1]*0.5f; + bmax[2] = sides[2]*0.5f; + + bmin[0] = -bmax[0]; + bmin[1] = -bmax[1]; + bmin[2] = -bmax[2]; + + + REAL dx = sides[0]; + REAL dy = sides[1]; + REAL dz = sides[2]; + + + MiU32 axis = 0; + + if ( dy > dx ) + { + axis = 1; + } + + if ( dz > dx && dz > dy ) + { + axis = 2; + } + + REAL p1[3]; + REAL p2[3]; + REAL p3[3]; + + p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f; + p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f; + p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f; + + Rect3d<REAL> b(bmin,bmax); + + Rect3d<REAL> b1,b2; + + splitRect(axis,b,b1,b2,p1); + + + switch ( axis ) + { + case 0: + p2[1] = bmin[1]; + p2[2] = bmin[2]; + + if ( dz > dy ) + { + p3[1] = bmax[1]; + p3[2] = bmin[2]; + } + else + { + p3[1] = bmin[1]; + p3[2] = bmax[2]; + } + + break; + case 1: + p2[0] = bmin[0]; + p2[2] = bmin[2]; + + if ( dx > dz ) + { + p3[0] = bmax[0]; + p3[2] = bmin[2]; + } + else + { + p3[0] = bmin[0]; + p3[2] = bmax[2]; + } + + break; + case 2: + p2[0] = bmin[0]; + p2[1] = bmin[1]; + + if ( dx > dy ) + { + p3[0] = bmax[0]; + p3[1] = bmin[1]; + } + else + { + p3[0] = bmin[0]; + p3[1] = bmax[1]; + } + + break; + } + + REAL tp1[3]; + REAL tp2[3]; + REAL tp3[3]; + + fm_transform(matrix,p1,tp1); + fm_transform(matrix,p2,tp2); + fm_transform(matrix,p3,tp3); + + plane[3] = fm_computePlane(tp1,tp2,tp3,plane); + + return true; + +} + +#pragma warning(disable:4100) + +void fm_nearestPointInTriangle(const REAL * /*nearestPoint*/,const REAL * /*p1*/,const REAL * /*p2*/,const REAL * /*p3*/,REAL * /*nearest*/) +{ + +} + +static REAL Partial(const REAL *a,const REAL *p) +{ + return (a[0]*p[1]) - (p[0]*a[1]); +} + +REAL fm_areaTriangle(const REAL *p0,const REAL *p1,const REAL *p2) +{ + REAL A = Partial(p0,p1); + A+= Partial(p1,p2); + A+= Partial(p2,p0); + return A*0.5f; +} + +void fm_subtract(const REAL *A,const REAL *B,REAL *diff) // compute A-B and store the result in 'diff' +{ + diff[0] = A[0]-B[0]; + diff[1] = A[1]-B[1]; + diff[2] = A[2]-B[2]; +} + + +void fm_multiplyTransform(const REAL *pA,const REAL *pB,REAL *pM) +{ + + REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; + REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; + REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; + REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; + + REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; + REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; + REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; + REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; + + REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; + REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; + REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; + REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; + + REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; + REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; + REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; + REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; + + pM[0] = a; pM[1] = b; pM[2] = c; pM[3] = d; + + pM[4] = e; pM[5] = f; pM[6] = g; pM[7] = h; + + pM[8] = i; pM[9] = j; pM[10] = k; pM[11] = l; + + pM[12] = m; pM[13] = n; pM[14] = o; pM[15] = p; +} + +void fm_multiply(REAL *A,REAL scaler) +{ + A[0]*=scaler; + A[1]*=scaler; + A[2]*=scaler; +} + +void fm_add(const REAL *A,const REAL *B,REAL *sum) +{ + sum[0] = A[0]+B[0]; + sum[1] = A[1]+B[1]; + sum[2] = A[2]+B[2]; +} + +void fm_copy3(const REAL *source,REAL *dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; +} + + +MiU32 fm_copyUniqueVertices(MiU32 vcount,const REAL *input_vertices,REAL *output_vertices,MiU32 tcount,const MiU32 *input_indices,MiU32 *output_indices) +{ + MiU32 ret = 0; + + REAL *vertices = (REAL *)MI_ALLOC(sizeof(REAL)*vcount*3); + memcpy(vertices,input_vertices,sizeof(REAL)*vcount*3); + REAL *dest = output_vertices; + + MiU32 *reindex = (MiU32 *)MI_ALLOC(sizeof(MiU32)*vcount); + memset(reindex,0xFF,sizeof(MiU32)*vcount); + + MiU32 icount = tcount*3; + + for (MiU32 i=0; i<icount; i++) + { + MiU32 index = *input_indices++; + + assert( index < vcount ); + + if ( reindex[index] == 0xFFFFFFFF ) + { + *output_indices++ = ret; + reindex[index] = ret; + const REAL *pos = &vertices[index*3]; + dest[0] = pos[0]; + dest[1] = pos[1]; + dest[2] = pos[2]; + dest+=3; + ret++; + } + else + { + *output_indices++ = reindex[index]; + } + } + MI_FREE(vertices); + MI_FREE(reindex); + return ret; +} + +bool fm_isMeshCoplanar(MiU32 tcount,const MiU32 *indices,const REAL *vertices,bool doubleSided) // returns true if this collection of indexed triangles are co-planar! +{ + bool ret = true; + + if ( tcount > 0 ) + { + MiU32 i1 = indices[0]; + MiU32 i2 = indices[1]; + MiU32 i3 = indices[2]; + const REAL *p1 = &vertices[i1*3]; + const REAL *p2 = &vertices[i2*3]; + const REAL *p3 = &vertices[i3*3]; + REAL plane[4]; + plane[3] = fm_computePlane(p1,p2,p3,plane); + const MiU32 *scan = &indices[3]; + for (MiU32 i=1; i<tcount; i++) + { + i1 = *scan++; + i2 = *scan++; + i3 = *scan++; + p1 = &vertices[i1*3]; + p2 = &vertices[i2*3]; + p3 = &vertices[i3*3]; + REAL _plane[4]; + _plane[3] = fm_computePlane(p1,p2,p3,_plane); + if ( !fm_samePlane(plane,_plane,0.01f,0.001f,doubleSided) ) + { + ret = false; + break; + } + } + } + return ret; +} + + +bool fm_samePlane(const REAL p1[4],const REAL p2[4],REAL normalEpsilon,REAL dEpsilon,bool doubleSided) +{ + bool ret = false; + + REAL diff = (REAL) fabs(p1[3]-p2[3]); + if ( diff < dEpsilon ) // if the plane -d co-efficient is within our epsilon + { + REAL dot = fm_dot(p1,p2); // compute the dot-product of the vector normals. + if ( doubleSided ) dot = (REAL)fabs(dot); + REAL dmin = 1 - normalEpsilon; + REAL dmax = 1 + normalEpsilon; + if ( dot >= dmin && dot <= dmax ) + { + ret = true; // then the plane equation is for practical purposes identical. + } + } + + return ret; +} + + +void fm_initMinMax(REAL bmin[3],REAL bmax[3]) +{ + bmin[0] = FLT_MAX; + bmin[1] = FLT_MAX; + bmin[2] = FLT_MAX; + bmax[0] = FLT_MIN; + bmax[1] = FLT_MIN; + bmax[2] = FLT_MIN; +} + + +#ifndef TESSELATE_H + +#define TESSELATE_H + +typedef STDNAME::vector< MiU32 > UintVector; + +class Myfm_Tesselate : public fm_Tesselate, public MeshImportAllocated +{ +public: + virtual ~Myfm_Tesselate(void) + { + + } + + const MiU32 * tesselate(fm_VertexIndex *vindex,MiU32 tcount,const MiU32 *indices,MiF32 longEdge,MiU32 maxDepth,MiU32 &outcount) + { + const MiU32 *ret = 0; + + mMaxDepth = maxDepth; + mLongEdge = longEdge*longEdge; + mLongEdgeD = mLongEdge; + mVertices = vindex; + + if ( mVertices->isDouble() ) + { + MiU32 vcount = mVertices->getVcount(); + MiF64 *vertices = (MiF64 *)MI_ALLOC(sizeof(MiF64)*vcount*3); + memcpy(vertices,mVertices->getVerticesDouble(),sizeof(MiF64)*vcount*3); + + for (MiU32 i=0; i<tcount; i++) + { + MiU32 i1 = *indices++; + MiU32 i2 = *indices++; + MiU32 i3 = *indices++; + + const MiF64 *p1 = &vertices[i1*3]; + const MiF64 *p2 = &vertices[i2*3]; + const MiF64 *p3 = &vertices[i3*3]; + + tesselate(p1,p2,p3,0); + + } + MI_FREE(vertices); + } + else + { + MiU32 vcount = mVertices->getVcount(); + MiF32 *vertices = (MiF32 *)MI_ALLOC(sizeof(MiF32)*vcount*3); + memcpy(vertices,mVertices->getVerticesFloat(),sizeof(MiF32)*vcount*3); + + + for (MiU32 i=0; i<tcount; i++) + { + MiU32 i1 = *indices++; + MiU32 i2 = *indices++; + MiU32 i3 = *indices++; + + const MiF32 *p1 = &vertices[i1*3]; + const MiF32 *p2 = &vertices[i2*3]; + const MiF32 *p3 = &vertices[i3*3]; + + tesselate(p1,p2,p3,0); + + } + MI_FREE(vertices); + } + + outcount = (MiU32)(mIndices.size()/3); + ret = &mIndices[0]; + + + return ret; + } + + void tesselate(const MiF32 *p1,const MiF32 *p2,const MiF32 *p3,MiU32 recurse) + { + bool split = false; + MiF32 l1,l2,l3; + + l1 = l2 = l3 = 0; + + if ( recurse < mMaxDepth ) + { + l1 = fm_distanceSquared(p1,p2); + l2 = fm_distanceSquared(p2,p3); + l3 = fm_distanceSquared(p3,p1); + + if ( l1 > mLongEdge || l2 > mLongEdge || l3 > mLongEdge ) + split = true; + + } + + if ( split ) + { + MiU32 edge; + + if ( l1 >= l2 && l1 >= l3 ) + edge = 0; + else if ( l2 >= l1 && l2 >= l3 ) + edge = 1; + else + edge = 2; + + MiF32 splits[3]; + + switch ( edge ) + { + case 0: + { + fm_lerp(p1,p2,splits,0.5f); + tesselate(p1,splits,p3, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + case 1: + { + fm_lerp(p2,p3,splits,0.5f); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(p1,splits,p3, recurse+1 ); + } + break; + case 2: + { + fm_lerp(p3,p1,splits,0.5f); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + } + } + else + { + bool newp; + + MiU32 i1 = mVertices->getIndex(p1,newp); + MiU32 i2 = mVertices->getIndex(p2,newp); + MiU32 i3 = mVertices->getIndex(p3,newp); + + mIndices.push_back(i1); + mIndices.push_back(i2); + mIndices.push_back(i3); + } + + } + + void tesselate(const MiF64 *p1,const MiF64 *p2,const MiF64 *p3,MiU32 recurse) + { + bool split = false; + MiF64 l1,l2,l3; + + l1 = l2 = l3 = 0; + + if ( recurse < mMaxDepth ) + { + l1 = fm_distanceSquared(p1,p2); + l2 = fm_distanceSquared(p2,p3); + l3 = fm_distanceSquared(p3,p1); + + if ( l1 > mLongEdgeD || l2 > mLongEdgeD || l3 > mLongEdgeD ) + split = true; + + } + + if ( split ) + { + MiU32 edge; + + if ( l1 >= l2 && l1 >= l3 ) + edge = 0; + else if ( l2 >= l1 && l2 >= l3 ) + edge = 1; + else + edge = 2; + + MiF64 splits[3]; + + switch ( edge ) + { + case 0: + { + fm_lerp(p1,p2,splits,0.5); + tesselate(p1,splits,p3, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + case 1: + { + fm_lerp(p2,p3,splits,0.5); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(p1,splits,p3, recurse+1 ); + } + break; + case 2: + { + fm_lerp(p3,p1,splits,0.5); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + } + } + else + { + bool newp; + + MiU32 i1 = mVertices->getIndex(p1,newp); + MiU32 i2 = mVertices->getIndex(p2,newp); + MiU32 i3 = mVertices->getIndex(p3,newp); + + mIndices.push_back(i1); + mIndices.push_back(i2); + mIndices.push_back(i3); + } + + } + +private: + MiF32 mLongEdge; + MiF64 mLongEdgeD; + fm_VertexIndex *mVertices; + UintVector mIndices; + MiU32 mMaxDepth; +}; + +fm_Tesselate * fm_createTesselate(void) +{ + Myfm_Tesselate *m = MI_NEW(Myfm_Tesselate); + return static_cast< fm_Tesselate * >(m); +} + +void fm_releaseTesselate(fm_Tesselate *t) +{ + Myfm_Tesselate *m = static_cast< Myfm_Tesselate *>(t); + delete m; +} + +#endif + + +#ifndef RAY_ABB_INTERSECT + +#define RAY_ABB_INTERSECT + +//! Integer representation of a floating-point value. +#define IR(x) ((MiU32&)x) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** +* A method to compute a ray-AABB intersection. +* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 +* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) +* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) +* +* Hence this version is faster as well as more robust than the original one. +* +* Should work provided: +* 1) the integer representation of 0.0f is 0x00000000 +* 2) the sign bit of the MiF32 is the most significant one +* +* Report bugs: [email protected] +* +* \param aabb [in] the axis-aligned bounding box +* \param origin [in] ray origin +* \param dir [in] ray direction +* \param coord [out] impact coordinates +* \return true if ray intersects AABB +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define RAYAABB_EPSILON 0.00001f +bool fm_intersectRayAABB(const MiF32 MinB[3],const MiF32 MaxB[3],const MiF32 origin[3],const MiF32 dir[3],MiF32 coord[3]) +{ + bool Inside = true; + MiF32 MaxT[3]; + MaxT[0]=MaxT[1]=MaxT[2]=-1.0f; + + // Find candidate planes. + for(MiU32 i=0;i<3;i++) + { + if(origin[i] < MinB[i]) + { + coord[i] = MinB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i]; + } + else if(origin[i] > MaxB[i]) + { + coord[i] = MaxB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord[0] = origin[0]; + coord[1] = origin[1]; + coord[2] = origin[2]; + return true; + } + + // Get largest of the maxT's for final choice of intersection + MiU32 WhichPlane = 0; + if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; + if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + if(IR(MaxT[WhichPlane])&0x80000000) return false; + + for(MiU32 i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; +#ifdef RAYAABB_EPSILON + if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false; +#else + if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false; +#endif + } + } + return true; // ray hits box +} + +bool fm_intersectLineSegmentAABB(const MiF32 bmin[3],const MiF32 bmax[3],const MiF32 p1[3],const MiF32 p2[3],MiF32 intersect[3]) +{ + bool ret = false; + + MiF32 dir[3]; + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + MiF32 dist = fm_normalize(dir); + if ( dist > RAYAABB_EPSILON ) + { + ret = fm_intersectRayAABB(bmin,bmax,p1,dir,intersect); + if ( ret ) + { + MiF32 d = fm_distanceSquared(p1,intersect); + if ( d > (dist*dist) ) + { + ret = false; + } + } + } + return ret; +} + +#endif + +#ifndef OBB_TO_AABB + +#define OBB_TO_AABB + +#pragma warning(disable:4100) +void fm_OBBtoAABB(const MiF32 /*obmin*/[3],const MiF32 /*obmax*/[3],const MiF32 /*matrix*/[16],MiF32 /*abmin*/[3],MiF32 /*abmax*/[3]) +{ + assert(0); // not yet implemented. +} + + +const REAL * computePos(MiU32 index,const REAL *vertices,MiU32 vstride) +{ + const char *tmp = (const char *)vertices; + tmp+=(index*vstride); + return (const REAL*)tmp; +} + +void computeNormal(MiU32 index,REAL *normals,MiU32 nstride,const REAL *normal) +{ + char *tmp = (char *)normals; + tmp+=(index*nstride); + REAL *dest = (REAL *)tmp; + dest[0]+=normal[0]; + dest[1]+=normal[1]; + dest[2]+=normal[2]; +} + +void fm_computeMeanNormals(MiU32 vcount, // the number of vertices + const REAL *vertices, // the base address of the vertex position data. + MiU32 vstride, // the stride between position data. + REAL *normals, // the base address of the destination for mean vector normals + MiU32 nstride, // the stride between normals + MiU32 tcount, // the number of triangles + const MiU32 *indices) // the triangle indices +{ + + // Step #1 : Zero out the vertex normals + char *dest = (char *)normals; + for (MiU32 i=0; i<vcount; i++) + { + REAL *n = (REAL *)dest; + n[0] = 0; + n[1] = 0; + n[2] = 0; + dest+=nstride; + } + + // Step #2 : Compute the face normals and accumulate them + const MiU32 *scan = indices; + for (MiU32 i=0; i<tcount; i++) + { + + MiU32 i1 = *scan++; + MiU32 i2 = *scan++; + MiU32 i3 = *scan++; + + const REAL *p1 = computePos(i1,vertices,vstride); + const REAL *p2 = computePos(i2,vertices,vstride); + const REAL *p3 = computePos(i3,vertices,vstride); + + REAL normal[3]; + fm_computePlane(p3,p2,p1,normal); + + computeNormal(i1,normals,nstride,normal); + computeNormal(i2,normals,nstride,normal); + computeNormal(i3,normals,nstride,normal); + } + + + // Normalize the accumulated normals + dest = (char *)normals; + for (MiU32 i=0; i<vcount; i++) + { + REAL *n = (REAL *)dest; + fm_normalize(n); + dest+=nstride; + } + +} + +#endif + + +#define BIGNUMBER 100000000.0 /* hundred million */ + +static inline void Set(REAL *n,REAL x,REAL y,REAL z) +{ + n[0] = x; + n[1] = y; + n[2] = z; +}; + +static inline void Copy(REAL *dest,const REAL *source) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; +} + + +REAL fm_computeBestFitSphere(MiU32 vcount,const REAL *points,MiU32 pstride,REAL *center) +{ + REAL radius; + REAL radius2; + + REAL xmin[3]; + REAL xmax[3]; + REAL ymin[3]; + REAL ymax[3]; + REAL zmin[3]; + REAL zmax[3]; + REAL dia1[3]; + REAL dia2[3]; + + /* FIRST PASS: find 6 minima/maxima points */ + Set(xmin,BIGNUMBER,BIGNUMBER,BIGNUMBER); + Set(xmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); + Set(ymin,BIGNUMBER,BIGNUMBER,BIGNUMBER); + Set(ymax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); + Set(zmin,BIGNUMBER,BIGNUMBER,BIGNUMBER); + Set(zmax,-BIGNUMBER,-BIGNUMBER,-BIGNUMBER); + + { + const char *scan = (const char *)points; + + for (MiU32 i=0; i<vcount; i++) + { + const REAL *caller_p = (const REAL *)scan; + if (caller_p[0]<xmin[0]) + Copy(xmin,caller_p); /* New xminimum point */ + if (caller_p[0]>xmax[0]) + Copy(xmax,caller_p); + if (caller_p[1]<ymin[1]) + Copy(ymin,caller_p); + if (caller_p[1]>ymax[1]) + Copy(ymax,caller_p); + if (caller_p[2]<zmin[2]) + Copy(zmin,caller_p); + if (caller_p[2]>zmax[2]) + Copy(zmax,caller_p); + scan+=pstride; + } + } + + /* Set xspan = distance between the 2 points xmin & xmax (squared) */ + REAL dx = xmax[0] - xmin[0]; + REAL dy = xmax[1] - xmin[1]; + REAL dz = xmax[2] - xmin[2]; + REAL xspan = dx*dx + dy*dy + dz*dz; + +/* Same for y & z spans */ + dx = ymax[0] - ymin[0]; + dy = ymax[1] - ymin[1]; + dz = ymax[2] - ymin[2]; + REAL yspan = dx*dx + dy*dy + dz*dz; + + dx = zmax[0] - zmin[0]; + dy = zmax[1] - zmin[1]; + dz = zmax[2] - zmin[2]; + REAL zspan = dx*dx + dy*dy + dz*dz; + + /* Set points dia1 & dia2 to the maximally separated pair */ + Copy(dia1,xmin); + Copy(dia2,xmax); /* assume xspan biggest */ + REAL maxspan = xspan; + + if (yspan>maxspan) + { + maxspan = yspan; + Copy(dia1,ymin); + Copy(dia2,ymax); + } + + if (zspan>maxspan) + { + maxspan = zspan; + Copy(dia1,zmin); + Copy(dia2,zmax); + } + + + /* dia1,dia2 is a diameter of initial sphere */ + /* calc initial center */ + center[0] = (dia1[0]+dia2[0])*0.5f; + center[1] = (dia1[1]+dia2[1])*0.5f; + center[2] = (dia1[2]+dia2[2])*0.5f; + + /* calculate initial radius**2 and radius */ + + dx = dia2[0]-center[0]; /* x component of radius vector */ + dy = dia2[1]-center[1]; /* y component of radius vector */ + dz = dia2[2]-center[2]; /* z component of radius vector */ + + radius2 = dx*dx + dy*dy + dz*dz; + radius = REAL(::sqrt(radius2)); + + /* SECOND PASS: increment current sphere */ + { + const char *scan = (const char *)points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *caller_p = (const REAL *)scan; + dx = caller_p[0]-center[0]; + dy = caller_p[1]-center[1]; + dz = caller_p[2]-center[2]; + REAL old_to_p_sq = dx*dx + dy*dy + dz*dz; + if (old_to_p_sq > radius2) /* do r**2 test first */ + { /* this point is outside of current sphere */ + REAL old_to_p = REAL(::sqrt(old_to_p_sq)); + /* calc radius of new sphere */ + radius = (radius + old_to_p) * 0.5f; + radius2 = radius*radius; /* for next r**2 compare */ + REAL old_to_new = old_to_p - radius; + /* calc center of new sphere */ + REAL recip = 1.0f /old_to_p; + REAL cx = (radius*center[0] + old_to_new*caller_p[0]) * recip; + REAL cy = (radius*center[1] + old_to_new*caller_p[1]) * recip; + REAL cz = (radius*center[2] + old_to_new*caller_p[2]) * recip; + Set(center,cx,cy,cz); + scan+=pstride; + } + } + } + return radius; +} + + +void fm_computeBestFitCapsule(MiU32 vcount,const REAL *points,MiU32 pstride,REAL &radius,REAL &height,REAL matrix[16],bool bruteForce) +{ + REAL sides[3]; + REAL omatrix[16]; + fm_computeBestFitOBB(vcount,points,pstride,sides,omatrix,bruteForce); + + MiI32 axis = 0; + if ( sides[0] > sides[1] && sides[0] > sides[2] ) + axis = 0; + else if ( sides[1] > sides[0] && sides[1] > sides[2] ) + axis = 1; + else + axis = 2; + + REAL localTransform[16]; + + REAL maxDist = 0; + REAL maxLen = 0; + + switch ( axis ) + { + case 0: + { + fm_eulerMatrix(0,0,FM_PI/2,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const MiU8 *scan = (const MiU8 *)points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *)scan; + REAL t[3]; + fm_inverseRT(omatrix,p,t); + REAL dist = t[1]*t[1]+t[2]*t[2]; + if ( dist > maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[0]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[0]; + break; + case 1: + { + fm_eulerMatrix(0,FM_PI/2,0,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const MiU8 *scan = (const MiU8 *)points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *)scan; + REAL t[3]; + fm_inverseRT(omatrix,p,t); + REAL dist = t[0]*t[0]+t[2]*t[2]; + if ( dist > maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[1]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[1]; + break; + case 2: + { + fm_eulerMatrix(FM_PI/2,0,0,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const MiU8 *scan = (const MiU8 *)points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *)scan; + REAL t[3]; + fm_inverseRT(omatrix,p,t); + REAL dist = t[0]*t[0]+t[1]*t[1]; + if ( dist > maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[2]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[2]; + break; + } + radius = (REAL)::sqrt(maxDist); + height = (maxLen*2)-(radius*2); +} + + +//************* Triangulation + +#ifndef TRIANGULATE_H + +#define TRIANGULATE_H + +typedef MiU32 TU32; + +class TVec +{ +public: + TVec(MiF64 _x,MiF64 _y,MiF64 _z) { x = _x; y = _y; z = _z; }; + TVec(void) { }; + + MiF64 x; + MiF64 y; + MiF64 z; +}; + +typedef STDNAME::vector< TVec > TVecVector; +typedef STDNAME::vector< TU32 > TU32Vector; + +class CTriangulator +{ +public: + /// Default constructor + CTriangulator(); + + /// Default destructor + virtual ~CTriangulator(); + + /// Triangulates the contour + void triangulate(TU32Vector &indices); + + /// Returns the given point in the triangulator array + inline TVec get(const TU32 id) { return mPoints[id]; } + + virtual void reset(void) + { + mInputPoints.clear(); + mPoints.clear(); + mIndices.clear(); + } + + virtual void addPoint(MiF64 x,MiF64 y,MiF64 z) + { + TVec v(x,y,z); + // update bounding box... + if ( mInputPoints.empty() ) + { + mMin = v; + mMax = v; + } + else + { + if ( x < mMin.x ) mMin.x = x; + if ( y < mMin.y ) mMin.y = y; + if ( z < mMin.z ) mMin.z = z; + + if ( x > mMax.x ) mMax.x = x; + if ( y > mMax.y ) mMax.y = y; + if ( z > mMax.z ) mMax.z = z; + } + mInputPoints.push_back(v); + } + + // Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two most signficant axes + // Here we find the two longest axes and use them to triangulate. Inverse transforming them would introduce more doubleing point error and isn't worth it. + virtual MiU32 * triangulate(MiU32 &tcount,MiF64 epsilon) + { + MiU32 *ret = 0; + tcount = 0; + mEpsilon = epsilon; + + if ( !mInputPoints.empty() ) + { + mPoints.clear(); + + MiF64 dx = mMax.x - mMin.x; // locate the first, second and third longest edges and store them in i1, i2, i3 + MiF64 dy = mMax.y - mMin.y; + MiF64 dz = mMax.z - mMin.z; + + MiU32 i1,i2,i3; + + if ( dx > dy && dx > dz ) + { + i1 = 0; + if ( dy > dz ) + { + i2 = 1; + i3 = 2; + } + else + { + i2 = 2; + i3 = 1; + } + } + else if ( dy > dx && dy > dz ) + { + i1 = 1; + if ( dx > dz ) + { + i2 = 0; + i3 = 2; + } + else + { + i2 = 2; + i3 = 0; + } + } + else + { + i1 = 2; + if ( dx > dy ) + { + i2 = 0; + i3 = 1; + } + else + { + i2 = 1; + i3 = 0; + } + } + + MiU32 pcount = (MiU32)mInputPoints.size(); + const MiF64 *points = &mInputPoints[0].x; + for (MiU32 i=0; i<pcount; i++) + { + TVec v( points[i1], points[i2], points[i3] ); + mPoints.push_back(v); + points+=3; + } + + mIndices.clear(); + triangulate(mIndices); + tcount = (MiU32)mIndices.size()/3; + if ( tcount ) + { + ret = &mIndices[0]; + } + } + return ret; + } + + virtual const MiF64 * getPoint(MiU32 index) + { + return &mInputPoints[index].x; + } + + +private: + MiF64 mEpsilon; + TVec mMin; + TVec mMax; + TVecVector mInputPoints; + TVecVector mPoints; + TU32Vector mIndices; + + /// Tests if a point is inside the given triangle + bool _insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P); + + /// Returns the area of the contour + MiF64 _area(); + + bool _snip(MiI32 u, MiI32 v, MiI32 w, MiI32 n, MiI32 *V); + + /// Processes the triangulation + void _process(TU32Vector &indices); + +}; + +/// Default constructor +CTriangulator::CTriangulator(void) +{ +} + +/// Default destructor +CTriangulator::~CTriangulator() +{ +} + +/// Triangulates the contour +void CTriangulator::triangulate(TU32Vector &indices) +{ + _process(indices); +} + +/// Processes the triangulation +void CTriangulator::_process(TU32Vector &indices) +{ + const MiI32 n = (const MiI32)mPoints.size(); + if (n < 3) + return; + MiI32 *V = (MiI32 *)MI_ALLOC(sizeof(MiI32)*n); + + bool flipped = false; + + if (0.0f < _area()) + { + for (MiI32 v = 0; v < n; v++) + V[v] = v; + } + else + { + flipped = true; + for (MiI32 v = 0; v < n; v++) + V[v] = (n - 1) - v; + } + + MiI32 nv = n; + MiI32 count = 2 * nv; + for (MiI32 m = 0, v = nv - 1; nv > 2;) + { + if (0 >= (count--)) + return; + + MiI32 u = v; + if (nv <= u) + u = 0; + v = u + 1; + if (nv <= v) + v = 0; + MiI32 w = v + 1; + if (nv <= w) + w = 0; + + if (_snip(u, v, w, nv, V)) + { + MiI32 a, b, c, s, t; + a = V[u]; + b = V[v]; + c = V[w]; + if ( flipped ) + { + indices.push_back((MiU32)a); + indices.push_back((MiU32)b); + indices.push_back((MiU32)c); + } + else + { + indices.push_back((MiU32)c); + indices.push_back((MiU32)b); + indices.push_back((MiU32)a); + } + m++; + for (s = v, t = v + 1; t < nv; s++, t++) + V[s] = V[t]; + nv--; + count = 2 * nv; + } + } + + MI_FREE(V); +} + +/// Returns the area of the contour +MiF64 CTriangulator::_area() +{ + MiU32 n = mPoints.size(); + MiF64 A = 0.0f; + for (MiU32 p = n - 1, q = 0; q < n; p = q++) + { + const TVec &pval = mPoints[p]; + const TVec &qval = mPoints[q]; + A += pval.x * qval.y - qval.x * pval.y; + } + A*=0.5f; + return A; +} + +bool CTriangulator::_snip(MiI32 u, MiI32 v, MiI32 w, MiI32 n, MiI32 *V) +{ + MiI32 p; + + const TVec &A = mPoints[ (MiU32)V[(MiU32)u] ]; + const TVec &B = mPoints[ (MiU32)V[(MiU32)v] ]; + const TVec &C = mPoints[ (MiU32)V[(MiU32)w] ]; + + if (mEpsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))) ) + return false; + + for (p = 0; p < n; p++) + { + if ((p == u) || (p == v) || (p == w)) + continue; + const TVec &P = mPoints[ (MiU32)V[(MiU32)p] ]; + if (_insideTriangle(A, B, C, P)) + return false; + } + return true; +} + +/// Tests if a point is inside the given triangle +bool CTriangulator::_insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P) +{ + MiF64 ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; + MiF64 cCROSSap, bCROSScp, aCROSSbp; + + ax = C.x - B.x; ay = C.y - B.y; + bx = A.x - C.x; by = A.y - C.y; + cx = B.x - A.x; cy = B.y - A.y; + apx = P.x - A.x; apy = P.y - A.y; + bpx = P.x - B.x; bpy = P.y - B.y; + cpx = P.x - C.x; cpy = P.y - C.y; + + aCROSSbp = ax * bpy - ay * bpx; + cCROSSap = cx * apy - cy * apx; + bCROSScp = bx * cpy - by * cpx; + + return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); +} + +class Triangulate : public fm_Triangulate, public MeshImportAllocated +{ +public: + Triangulate(void) + { + mPointsFloat = 0; + mPointsDouble = 0; + } + + virtual ~Triangulate(void) + { + reset(); + } + void reset(void) + { + MI_FREE(mPointsFloat); + MI_FREE(mPointsDouble); + mPointsFloat = 0; + mPointsDouble = 0; + } + + virtual const MiF64 * triangulate3d(MiU32 pcount, + const MiF64 *_points, + MiU32 vstride, + MiU32 &tcount, + bool consolidate, + MiF64 epsilon) + { + reset(); + + MiF64 *points = (MiF64 *)MI_ALLOC(sizeof(MiF64)*pcount*3); + if ( consolidate ) + { + pcount = fm_consolidatePolygon(pcount,_points,vstride,points,1-epsilon); + } + else + { + MiF64 *dest = points; + for (MiU32 i=0; i<pcount; i++) + { + const MiF64 *src = fm_getPoint(_points,vstride,i); + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest+=3; + } + vstride = sizeof(MiF64)*3; + } + + if ( pcount >= 3 ) + { + CTriangulator ct; + for (MiU32 i=0; i<pcount; i++) + { + const MiF64 *src = fm_getPoint(points,vstride,i); + ct.addPoint( src[0], src[1], src[2] ); + } + MiU32 _tcount; + MiU32 *indices = ct.triangulate(_tcount,epsilon); + if ( indices ) + { + tcount = _tcount; + mPointsDouble = (MiF64 *)MI_ALLOC(sizeof(MiF64)*tcount*3*3); + MiF64 *dest = mPointsDouble; + for (MiU32 i=0; i<tcount; i++) + { + MiU32 i1 = indices[i*3+0]; + MiU32 i2 = indices[i*3+1]; + MiU32 i3 = indices[i*3+2]; + const MiF64 *p1 = ct.getPoint(i1); + const MiF64 *p2 = ct.getPoint(i2); + const MiF64 *p3 = ct.getPoint(i3); + + dest[0] = p1[0]; + dest[1] = p1[1]; + dest[2] = p1[2]; + + dest[3] = p2[0]; + dest[4] = p2[1]; + dest[5] = p2[2]; + + dest[6] = p3[0]; + dest[7] = p3[1]; + dest[8] = p3[2]; + dest+=9; + } + } + } + MI_FREE(points); + + return mPointsDouble; + } + + virtual const MiF32 * triangulate3d(MiU32 pcount, + const MiF32 *points, + MiU32 vstride, + MiU32 &tcount, + bool consolidate, + MiF32 epsilon) + { + reset(); + + MiF64 *temp = (MiF64 *)MI_ALLOC(sizeof(MiF64)*pcount*3); + MiF64 *dest = temp; + for (MiU32 i=0; i<pcount; i++) + { + const MiF32 *p = fm_getPoint(points,vstride,i); + dest[0] = p[0]; + dest[1] = p[1]; + dest[2] = p[2]; + dest+=3; + } + const MiF64 *results = triangulate3d(pcount,temp,sizeof(MiF64)*3,tcount,consolidate,epsilon); + if ( results ) + { + MiU32 fcount = tcount*3*3; + mPointsFloat = (MiF32 *)MI_ALLOC(sizeof(MiF32)*tcount*3*3); + for (MiU32 i=0; i<fcount; i++) + { + mPointsFloat[i] = (MiF32) results[i]; + } + MI_FREE(mPointsDouble); + mPointsDouble = 0; + } + MI_FREE(temp); + + return mPointsFloat; + } + +private: + MiF32 *mPointsFloat; + MiF64 *mPointsDouble; +}; + +fm_Triangulate * fm_createTriangulate(void) +{ + Triangulate *t = MI_NEW(Triangulate); + return static_cast< fm_Triangulate *>(t); +} + +void fm_releaseTriangulate(fm_Triangulate *t) +{ + Triangulate *tt = static_cast< Triangulate *>(t); + delete tt; +} + +#endif + +bool validDistance(const REAL *p1,const REAL *p2,REAL epsilon) +{ + bool ret = true; + + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + REAL dist = dx*dx+dy*dy+dz*dz; + if ( dist < (epsilon*epsilon) ) + { + ret = false; + } + return ret; +} + +bool fm_isValidTriangle(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) +{ + bool ret = false; + + if ( validDistance(p1,p2,epsilon) && + validDistance(p1,p3,epsilon) && + validDistance(p2,p3,epsilon) ) + { + + REAL area = fm_computeArea(p1,p2,p3); + if ( area > epsilon ) + { + REAL _vertices[3*3],vertices[64*3]; + + _vertices[0] = p1[0]; + _vertices[1] = p1[1]; + _vertices[2] = p1[2]; + + _vertices[3] = p2[0]; + _vertices[4] = p2[1]; + _vertices[5] = p2[2]; + + _vertices[6] = p3[0]; + _vertices[7] = p3[1]; + _vertices[8] = p3[2]; + + MiU32 pcount = fm_consolidatePolygon(3,_vertices,sizeof(REAL)*3,vertices,1-epsilon); + if ( pcount == 3 ) + { + ret = true; + } + } + } + return ret; +} + + +void fm_multiplyQuat(const REAL *left,const REAL *right,REAL *quat) +{ + REAL a,b,c,d; + + a = left[3]*right[3] - left[0]*right[0] - left[1]*right[1] - left[2]*right[2]; + b = left[3]*right[0] + right[3]*left[0] + left[1]*right[2] - right[1]*left[2]; + c = left[3]*right[1] + right[3]*left[1] + left[2]*right[0] - right[2]*left[0]; + d = left[3]*right[2] + right[3]*left[2] + left[0]*right[1] - right[0]*left[1]; + + quat[3] = a; + quat[0] = b; + quat[1] = c; + quat[2] = d; +} + +bool fm_computeCentroid(MiU32 vcount, // number of input data points + const REAL *points, // starting address of points array. + MiU32 vstride, // stride between input points. + REAL *center) + +{ + bool ret = false; + if ( vcount ) + { + center[0] = 0; + center[1] = 0; + center[2] = 0; + const char *scan = (const char *)points; + for (MiU32 i=0; i<vcount; i++) + { + const REAL *p = (const REAL *)scan; + center[0]+=p[0]; + center[1]+=p[1]; + center[2]+=p[2]; + scan+=vstride; + } + REAL recip = 1.0f / (REAL)vcount; + center[0]*=recip; + center[1]*=recip; + center[2]*=recip; + ret = true; + } + return ret; +} + +#ifndef TEMPLATE_VEC3 +#define TEMPLATE_VEC3 +template <class Type> class Vec3 +{ +public: + Vec3(void) + { + + } + Vec3(Type _x,Type _y,Type _z) + { + x = _x; + y = _y; + z = _z; + } + Type x; + Type y; + Type z; +}; +#endif + +void fm_transformAABB(const REAL bmin[3],const REAL bmax[3],const REAL matrix[16],REAL tbmin[3],REAL tbmax[3]) +{ + Vec3<REAL> box[8]; + box[0] = Vec3< REAL >( bmin[0], bmin[1], bmin[2] ); + box[1] = Vec3< REAL >( bmax[0], bmin[1], bmin[2] ); + box[2] = Vec3< REAL >( bmax[0], bmax[1], bmin[2] ); + box[3] = Vec3< REAL >( bmin[0], bmax[1], bmin[2] ); + box[4] = Vec3< REAL >( bmin[0], bmin[1], bmax[2] ); + box[5] = Vec3< REAL >( bmax[0], bmin[1], bmax[2] ); + box[6] = Vec3< REAL >( bmax[0], bmax[1], bmax[2] ); + box[7] = Vec3< REAL >( bmin[0], bmax[1], bmax[2] ); + // transform all 8 corners of the box and then recompute a new AABB + for (unsigned int i=0; i<8; i++) + { + Vec3< REAL > &p = box[i]; + fm_transform(matrix,&p.x,&p.x); + if ( i == 0 ) + { + tbmin[0] = tbmax[0] = p.x; + tbmin[1] = tbmax[1] = p.y; + tbmin[2] = tbmax[2] = p.z; + } + else + { + if ( p.x < tbmin[0] ) tbmin[0] = p.x; + if ( p.y < tbmin[1] ) tbmin[1] = p.y; + if ( p.z < tbmin[2] ) tbmin[2] = p.z; + if ( p.x > tbmax[0] ) tbmax[0] = p.x; + if ( p.y > tbmax[1] ) tbmax[1] = p.y; + if ( p.z > tbmax[2] ) tbmax[2] = p.z; + } + } +} + +};
\ No newline at end of file diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiInparser.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiInparser.cpp new file mode 100644 index 00000000..89a2ed62 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiInparser.cpp @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#pragma warning(disable:4996) + +#include "MiInparser.h" + +/** @file inparser.cpp + * @brief Parse ASCII text, in place, very quickly. + * + * This class provides for high speed in-place (destructive) parsing of an ASCII text file. + * This class will either load an ASCII text file from disk, or can be constructed with a pointer to + * a piece of ASCII text in memory. It can only be called once, and the contents are destroyed. + * To speed the process of parsing, it simply builds pointers to the original ascii data and replaces the + * seperators with a zero byte to indicate end of string. It performs callbacks to parse each line, in argc/argv format, + * offering the option to cancel the parsing process at any time. + * + * + * By default the only valid seperator is whitespace. It will not treat commas or any other symbol as a separator. + * However, you can specify up to 32 'hard' seperators, such as a comma, equal sign, etc. and these will act as valid + * seperators and come back as part of the argc/argv data list. + * + * To use the parser simply inherit the pure virtual base class 'InPlaceParserInterface'. Define the method 'ParseLine'. + * When you invoke the Parse method on the InPlaceParser class, you will get an ARGC - ARGV style callback for each line + * in the source file. If you return 'false' at any time, it will abort parsing. The entire thing is stack based, so you + * can recursively call multiple parser instances. + * + * It is important to note. Since this parser is 'in place' it writes 'zero bytes' (EOS marker) on top of the whitespace. + * While it can handle text in quotes, it does not handle escape sequences. This is a limitation which could be resolved. + * There is a hard coded maximum limit of 512 arguments per line. + * + * Here is the full example usage: + * + * InPlaceParser ipp("parse_me.txt"); + * + * ipp.Parse(this); + * + * That's it, and you will receive an ARGC - ARGV callback for every line in the file. + * + * If you want to parse some text in memory of your own. (It *MUST* be terminated by a zero byte, and lines seperated by carriage return + * or line-feed. You will receive an assertion if it does not. If you specify the source data than *you* are responsible for that memory + * and must de-allocate it yourself. If the data was loaded from a file on disk, then it is automatically de-allocated by the InPlaceParser. + * + * You can also construct the InPlaceParser without passing any data, so you can simply pass it a line of data at a time yourself. The + * line of data should be zero-byte terminated. +*/ + +//================================================================================== + +namespace mimp +{ + +void InPlaceParser::SetFile(const char *fname) +{ + if ( mMyAlloc ) + { + MI_FREE(mData); + } + mData = 0; + mLen = 0; + mMyAlloc = false; + + FILE *fph = fopen(fname,"rb"); + if ( fph ) + { + fseek(fph,0L,SEEK_END); + mLen = ftell(fph); + fseek(fph,0L,SEEK_SET); + + if ( mLen ) + { + mData = (char *) MI_ALLOC(sizeof(char)*(mLen+1)); + MiI32 read = (MiI32)fread(mData,(size_t)mLen,1,fph); + if ( !read ) + { + MI_FREE(mData); + mData = 0; + } + else + { + mData[mLen] = 0; // zero byte terminate end of file marker. + mMyAlloc = true; + } + } + fclose(fph); + } +} + +//================================================================================== +InPlaceParser::~InPlaceParser(void) +{ + if ( mMyAlloc ) + { + MI_FREE(mData); + } +} + +//================================================================================== +bool InPlaceParser::IsHard(char c) +{ + return mHard[(unsigned char)c] == ST_HARD; +} + +//================================================================================== +char * InPlaceParser::AddHard(MiI32 &argc,const char **argv,char *foo) +{ + while ( IsHard(*foo) ) + { + const char *hard = &mHardString[*foo*2]; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + ++foo; + } + return foo; +} + +//================================================================================== +bool InPlaceParser::IsWhiteSpace(char c) +{ + return mHard[(unsigned char)c] == ST_SOFT; +} + +//================================================================================== +char * InPlaceParser::SkipSpaces(char *foo) +{ + while ( !EOS(*foo) && IsWhiteSpace(*foo) ) + ++foo; + return foo; +} + +//================================================================================== +bool InPlaceParser::IsNonSeparator(char c) +{ + return ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ); +} + +//================================================================================== +MiI32 InPlaceParser::ProcessLine(MiI32 lineno,char *line,InPlaceParserInterface *callback) +{ + MiI32 ret = 0; + + const char *argv[MAXARGS]; + MiI32 argc = 0; + + char *foo = line; + + while ( !EOS(*foo) && argc < MAXARGS ) + { + foo = SkipSpaces(foo); // skip any leading spaces + + if ( EOS(*foo) ) + break; + + if ( *foo == mQuoteChar ) // if it is an open quote + { + ++foo; + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + while ( !EOS(*foo) && *foo != mQuoteChar ) + ++foo; + if ( !EOS(*foo) ) + { + *foo = 0; // replace close quote with zero byte EOS + ++foo; + } + } + else + { + foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces + + if ( IsNonSeparator(*foo) ) // add non-hard argument. + { + bool quote = false; + if ( *foo == mQuoteChar ) + { + ++foo; + quote = true; + } + + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + + if ( quote ) + { + while (*foo && *foo != mQuoteChar ) + ++foo; + if ( *foo ) + *foo = 32; + } + + // continue..until we hit an eos .. + while ( !EOS(*foo) ) // until we hit EOS + { + if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit + { + *foo = 0; + ++foo; + break; + } + else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument + { + const char *hard = &mHardString[*foo*2]; + *foo = 0; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + ++foo; + break; + } + ++foo; + } // end of while loop... + } + } + } + + if ( argc ) + { + ret = callback->ParseLine(lineno, argc, argv ); + } + + return ret; +} + + +MiI32 InPlaceParser::Parse(const char *str,InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason +{ + MiI32 ret = 0; + + mLen = (MiI32)strlen(str); + if ( mLen ) + { + mData = (char *)MI_ALLOC((MiU32)mLen+1); + strcpy(mData,str); + mMyAlloc = true; + ret = Parse(callback); + } + return ret; +} + +//================================================================================== +// returns true if entire file was parsed, false if it aborted for some reason +//================================================================================== +MiI32 InPlaceParser::Parse(InPlaceParserInterface *callback) +{ + MiI32 ret = 0; + MI_ASSERT( callback ); + if ( mData ) + { + MiI32 lineno = 0; + + char *foo = mData; + char *begin = foo; + + while ( *foo ) + { + if ( isLineFeed(*foo) ) + { + ++lineno; + *foo = 0; + if ( *begin ) // if there is any data to parse at all... + { + bool snarfed = callback->preParseLine(lineno,begin); + if ( !snarfed ) + { + MiI32 v = ProcessLine(lineno,begin,callback); + if ( v ) + ret = v; + } + } + + ++foo; + if ( *foo == 10 ) + ++foo; // skip line feed, if it is in the carraige-return line-feed format... + begin = foo; + } + else + { + ++foo; + } + } + + lineno++; // lasst line. + + MiI32 v = ProcessLine(lineno,begin,callback); + if ( v ) + ret = v; + } + return ret; +} + +//================================================================================== +void InPlaceParser::DefaultSymbols(void) +{ + SetHardSeparator(','); + SetHardSeparator('('); + SetHardSeparator(')'); + SetHardSeparator('='); + SetHardSeparator('['); + SetHardSeparator(']'); + SetHardSeparator('{'); + SetHardSeparator('}'); + SetCommentSymbol('#'); +} + +//================================================================================== +// convert source string into an arg list, this is a destructive parse. +//================================================================================== +const char ** InPlaceParser::GetArglist(char *line,MiI32 &count) +{ + const char **ret = 0; + + MiI32 argc = 0; + + char *foo = line; + + while ( !EOS(*foo) && argc < MAXARGS ) + { + foo = SkipSpaces(foo); // skip any leading spaces + + if ( EOS(*foo) ) + break; + + if ( *foo == mQuoteChar ) // if it is an open quote + { + ++foo; + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + while ( !EOS(*foo) && *foo != mQuoteChar ) + ++foo; + if ( !EOS(*foo) ) + { + *foo = 0; // replace close quote with zero byte EOS + ++foo; + } + } + else + { + foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces + + if ( IsNonSeparator(*foo) ) // add non-hard argument. + { + bool quote = false; + if ( *foo == mQuoteChar ) + { + ++foo; + quote = true; + } + + if ( argc < MAXARGS ) + { + argv[argc++] = foo; + } + + if ( quote ) + { + while (*foo && *foo != mQuoteChar ) + ++foo; + if ( *foo ) + *foo = 32; + } + + // continue..until we hit an eos .. + while ( !EOS(*foo) ) // until we hit EOS + { + if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit + { + *foo = 0; + ++foo; + break; + } + else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument + { + const char *hard = &mHardString[*foo*2]; + *foo = 0; + if ( argc < MAXARGS ) + { + argv[argc++] = hard; + } + ++foo; + break; + } + ++foo; + } // end of while loop... + } + } + } + + count = argc; + if ( argc ) + { + ret = argv; + } + + return ret; +} + + +};
\ No newline at end of file diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiMapSet.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiMapSet.cpp new file mode 100644 index 00000000..51b5c5f8 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiMapSet.cpp @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +/* +Copyright (C) 2009-2010 Electronic Arts, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/////////////////////////////////////////////////////////////////////////////// +// Written by Paul Pedriana. +// +// Refactored to be compliant with the PhysX data types by John W. Ratcliff +// on March 23, 2011 +////////////////////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////// +// The tree insert and erase functions below are based on the original +// HP STL tree functions. Use of these functions was been approved by +// EA legal on November 4, 2005 and the approval documentation is available +// from the EASTL maintainer or from the EA legal deparatment on request. +// +// Copyright (c) 1994 +// Hewlett-Packard Company +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appear in all copies and +// that both that copyright notice and this permission notice appear +// in supporting documentation. Hewlett-Packard Company makes no +// representations about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +/////////////////////////////////////////////////////////////////////////////// +#include "MiPlatformConfig.h" +#include "MiMapSetInternal.h" + +namespace mimp +{ + // Forward declarations + rbtree_node_base* RBTreeRotateLeft(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot); + rbtree_node_base* RBTreeRotateRight(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot); + + + + /// RBTreeIncrement + /// Returns the next item in a sorted red-black tree. + /// + rbtree_node_base* RBTreeIncrement(const rbtree_node_base* pNode) + { + if(pNode->mpNodeRight) + { + pNode = pNode->mpNodeRight; + + while(pNode->mpNodeLeft) + pNode = pNode->mpNodeLeft; + } + else + { + rbtree_node_base* pNodeTemp = pNode->mpNodeParent; + + while(pNode == pNodeTemp->mpNodeRight) + { + pNode = pNodeTemp; + pNodeTemp = pNodeTemp->mpNodeParent; + } + + if(pNode->mpNodeRight != pNodeTemp) + pNode = pNodeTemp; + } + + return const_cast<rbtree_node_base*>(pNode); + } + + + + /// RBTreeIncrement + /// Returns the previous item in a sorted red-black tree. + /// + rbtree_node_base* RBTreeDecrement(const rbtree_node_base* pNode) + { + if((pNode->mpNodeParent->mpNodeParent == pNode) && (pNode->mColor == kRBTreeColorRed)) + return pNode->mpNodeRight; + else if(pNode->mpNodeLeft) + { + rbtree_node_base* pNodeTemp = pNode->mpNodeLeft; + + while(pNodeTemp->mpNodeRight) + pNodeTemp = pNodeTemp->mpNodeRight; + + return pNodeTemp; + } + + rbtree_node_base* pNodeTemp = pNode->mpNodeParent; + + while(pNode == pNodeTemp->mpNodeLeft) + { + pNode = pNodeTemp; + pNodeTemp = pNodeTemp->mpNodeParent; + } + + return const_cast<rbtree_node_base*>(pNodeTemp); + } + + + + /// RBTreeGetBlackCount + /// Counts the number of black nodes in an red-black tree, from pNode down to the given bottom node. + /// We don't count red nodes because red-black trees don't really care about + /// red node counts; it is black node counts that are significant in the + /// maintenance of a balanced tree. + /// + size_t RBTreeGetBlackCount(const rbtree_node_base* pNodeTop, const rbtree_node_base* pNodeBottom) + { + size_t nCount = 0; + + for(; pNodeBottom; pNodeBottom = pNodeBottom->mpNodeParent) + { + if(pNodeBottom->mColor == kRBTreeColorBlack) + ++nCount; + + if(pNodeBottom == pNodeTop) + break; + } + + return nCount; + } + + + /// RBTreeRotateLeft + /// Does a left rotation about the given node. + /// If you want to understand tree rotation, any book on algorithms will + /// discussion the topic in good detail. + rbtree_node_base* RBTreeRotateLeft(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot) + { + rbtree_node_base* const pNodeTemp = pNode->mpNodeRight; + + pNode->mpNodeRight = pNodeTemp->mpNodeLeft; + + if(pNodeTemp->mpNodeLeft) + pNodeTemp->mpNodeLeft->mpNodeParent = pNode; + pNodeTemp->mpNodeParent = pNode->mpNodeParent; + + if(pNode == pNodeRoot) + pNodeRoot = pNodeTemp; + else if(pNode == pNode->mpNodeParent->mpNodeLeft) + pNode->mpNodeParent->mpNodeLeft = pNodeTemp; + else + pNode->mpNodeParent->mpNodeRight = pNodeTemp; + + pNodeTemp->mpNodeLeft = pNode; + pNode->mpNodeParent = pNodeTemp; + + return pNodeRoot; + } + + + + /// RBTreeRotateRight + /// Does a right rotation about the given node. + /// If you want to understand tree rotation, any book on algorithms will + /// discussion the topic in good detail. + rbtree_node_base* RBTreeRotateRight(rbtree_node_base* pNode, rbtree_node_base* pNodeRoot) + { + rbtree_node_base* const pNodeTemp = pNode->mpNodeLeft; + + pNode->mpNodeLeft = pNodeTemp->mpNodeRight; + + if(pNodeTemp->mpNodeRight) + pNodeTemp->mpNodeRight->mpNodeParent = pNode; + pNodeTemp->mpNodeParent = pNode->mpNodeParent; + + if(pNode == pNodeRoot) + pNodeRoot = pNodeTemp; + else if(pNode == pNode->mpNodeParent->mpNodeRight) + pNode->mpNodeParent->mpNodeRight = pNodeTemp; + else + pNode->mpNodeParent->mpNodeLeft = pNodeTemp; + + pNodeTemp->mpNodeRight = pNode; + pNode->mpNodeParent = pNodeTemp; + + return pNodeRoot; + } + + + + + /// RBTreeInsert + /// Insert a node into the tree and rebalance the tree as a result of the + /// disturbance the node introduced. + /// + void RBTreeInsert(rbtree_node_base* pNode, + rbtree_node_base* pNodeParent, + rbtree_node_base* pNodeAnchor, + RBTreeSide insertionSide) + { + rbtree_node_base*& pNodeRootRef = pNodeAnchor->mpNodeParent; + + // Initialize fields in new node to insert. + pNode->mpNodeParent = pNodeParent; + pNode->mpNodeRight = NULL; + pNode->mpNodeLeft = NULL; + pNode->mColor = kRBTreeColorRed; + + // Insert the node. + if(insertionSide == kRBTreeSideLeft) + { + pNodeParent->mpNodeLeft = pNode; // Also makes (leftmost = pNode) when (pNodeParent == pNodeAnchor) + + if(pNodeParent == pNodeAnchor) + { + pNodeAnchor->mpNodeParent = pNode; + pNodeAnchor->mpNodeRight = pNode; + } + else if(pNodeParent == pNodeAnchor->mpNodeLeft) + pNodeAnchor->mpNodeLeft = pNode; // Maintain leftmost pointing to min node + } + else + { + pNodeParent->mpNodeRight = pNode; + + if(pNodeParent == pNodeAnchor->mpNodeRight) + pNodeAnchor->mpNodeRight = pNode; // Maintain rightmost pointing to max node + } + + // Rebalance the tree. + while((pNode != pNodeRootRef) && (pNode->mpNodeParent->mColor == kRBTreeColorRed)) + { + rbtree_node_base* const pNodeParentParent = pNode->mpNodeParent->mpNodeParent; + + if(pNode->mpNodeParent == pNodeParentParent->mpNodeLeft) + { + rbtree_node_base* const pNodeTemp = pNodeParentParent->mpNodeRight; + + if(pNodeTemp && (pNodeTemp->mColor == kRBTreeColorRed)) + { + pNode->mpNodeParent->mColor = kRBTreeColorBlack; + pNodeTemp->mColor = kRBTreeColorBlack; + pNodeParentParent->mColor = kRBTreeColorRed; + pNode = pNodeParentParent; + } + else + { + if(pNode == pNode->mpNodeParent->mpNodeRight) + { + pNode = pNode->mpNodeParent; + pNodeRootRef = RBTreeRotateLeft(pNode, pNodeRootRef); + } + + pNode->mpNodeParent->mColor = kRBTreeColorBlack; + pNodeParentParent->mColor = kRBTreeColorRed; + pNodeRootRef = RBTreeRotateRight(pNodeParentParent, pNodeRootRef); + } + } + else + { + rbtree_node_base* const pNodeTemp = pNodeParentParent->mpNodeLeft; + + if(pNodeTemp && (pNodeTemp->mColor == kRBTreeColorRed)) + { + pNode->mpNodeParent->mColor = kRBTreeColorBlack; + pNodeTemp->mColor = kRBTreeColorBlack; + pNodeParentParent->mColor = kRBTreeColorRed; + pNode = pNodeParentParent; + } + else + { + if(pNode == pNode->mpNodeParent->mpNodeLeft) + { + pNode = pNode->mpNodeParent; + pNodeRootRef = RBTreeRotateRight(pNode, pNodeRootRef); + } + + pNode->mpNodeParent->mColor = kRBTreeColorBlack; + pNodeParentParent->mColor = kRBTreeColorRed; + pNodeRootRef = RBTreeRotateLeft(pNodeParentParent, pNodeRootRef); + } + } + } + + pNodeRootRef->mColor = kRBTreeColorBlack; + + } // RBTreeInsert + + + + + /// RBTreeErase + /// Erase a node from the tree. + /// + void RBTreeErase(rbtree_node_base* pNode, rbtree_node_base* pNodeAnchor) + { + rbtree_node_base*& pNodeRootRef = pNodeAnchor->mpNodeParent; + rbtree_node_base*& pNodeLeftmostRef = pNodeAnchor->mpNodeLeft; + rbtree_node_base*& pNodeRightmostRef = pNodeAnchor->mpNodeRight; + rbtree_node_base* pNodeSuccessor = pNode; + rbtree_node_base* pNodeChild = NULL; + rbtree_node_base* pNodeChildParent = NULL; + + if(pNodeSuccessor->mpNodeLeft == NULL) // pNode has at most one non-NULL child. + pNodeChild = pNodeSuccessor->mpNodeRight; // pNodeChild might be null. + else if(pNodeSuccessor->mpNodeRight == NULL) // pNode has exactly one non-NULL child. + pNodeChild = pNodeSuccessor->mpNodeLeft; // pNodeChild is not null. + else + { + // pNode has two non-null children. Set pNodeSuccessor to pNode's successor. pNodeChild might be NULL. + pNodeSuccessor = pNodeSuccessor->mpNodeRight; + + while(pNodeSuccessor->mpNodeLeft) + pNodeSuccessor = pNodeSuccessor->mpNodeLeft; + + pNodeChild = pNodeSuccessor->mpNodeRight; + } + + // Here we remove pNode from the tree and fix up the node pointers appropriately around it. + if(pNodeSuccessor == pNode) // If pNode was a leaf node (had both NULL children)... + { + pNodeChildParent = pNodeSuccessor->mpNodeParent; // Assign pNodeReplacement's parent. + + if(pNodeChild) + pNodeChild->mpNodeParent = pNodeSuccessor->mpNodeParent; + + if(pNode == pNodeRootRef) // If the node being deleted is the root node... + pNodeRootRef = pNodeChild; // Set the new root node to be the pNodeReplacement. + else + { + if(pNode == pNode->mpNodeParent->mpNodeLeft) // If pNode is a left node... + pNode->mpNodeParent->mpNodeLeft = pNodeChild; // Make pNode's replacement node be on the same side. + else + pNode->mpNodeParent->mpNodeRight = pNodeChild; + // Now pNode is disconnected from the bottom of the tree (recall that in this pathway pNode was determined to be a leaf). + } + + if(pNode == pNodeLeftmostRef) // If pNode is the tree begin() node... + { + // Because pNode is the tree begin(), pNode->mpNodeLeft must be NULL. + // Here we assign the new begin() (first node). + if(pNode->mpNodeRight) + pNodeLeftmostRef = RBTreeGetMinChild(pNodeChild); + else + pNodeLeftmostRef = pNode->mpNodeParent; // This makes (pNodeLeftmostRef == end()) if (pNode == root node) + } + + if(pNode == pNodeRightmostRef) // If pNode is the tree last (rbegin()) node... + { + // Because pNode is the tree rbegin(), pNode->mpNodeRight must be NULL. + // Here we assign the new rbegin() (last node) + if(pNode->mpNodeLeft) + pNodeRightmostRef = RBTreeGetMaxChild(pNodeChild); + else // pNodeChild == pNode->mpNodeLeft + pNodeRightmostRef = pNode->mpNodeParent; // makes pNodeRightmostRef == &mAnchor if pNode == pNodeRootRef + } + } + else // else (pNodeSuccessor != pNode) + { + // Relink pNodeSuccessor in place of pNode. pNodeSuccessor is pNode's successor. + // We specifically set pNodeSuccessor to be on the right child side of pNode, so fix up the left child side. + pNode->mpNodeLeft->mpNodeParent = pNodeSuccessor; + pNodeSuccessor->mpNodeLeft = pNode->mpNodeLeft; + + if(pNodeSuccessor == pNode->mpNodeRight) // If pNode's successor was at the bottom of the tree... (yes that's effectively what this statement means) + pNodeChildParent = pNodeSuccessor; // Assign pNodeReplacement's parent. + else + { + pNodeChildParent = pNodeSuccessor->mpNodeParent; + + if(pNodeChild) + pNodeChild->mpNodeParent = pNodeChildParent; + + pNodeChildParent->mpNodeLeft = pNodeChild; + + pNodeSuccessor->mpNodeRight = pNode->mpNodeRight; + pNode->mpNodeRight->mpNodeParent = pNodeSuccessor; + } + + if(pNode == pNodeRootRef) + pNodeRootRef = pNodeSuccessor; + else if(pNode == pNode->mpNodeParent->mpNodeLeft) + pNode->mpNodeParent->mpNodeLeft = pNodeSuccessor; + else + pNode->mpNodeParent->mpNodeRight = pNodeSuccessor; + + // Now pNode is disconnected from the tree. + + pNodeSuccessor->mpNodeParent = pNode->mpNodeParent; + mimp::swap(pNodeSuccessor->mColor, pNode->mColor); + } + + // Here we do tree balancing as per the conventional red-black tree algorithm. + if(pNode->mColor == kRBTreeColorBlack) + { + while((pNodeChild != pNodeRootRef) && ((pNodeChild == NULL) || (pNodeChild->mColor == kRBTreeColorBlack))) + { + if(pNodeChild == pNodeChildParent->mpNodeLeft) + { + rbtree_node_base* pNodeTemp = pNodeChildParent->mpNodeRight; + + if(pNodeTemp->mColor == kRBTreeColorRed) + { + pNodeTemp->mColor = kRBTreeColorBlack; + pNodeChildParent->mColor = kRBTreeColorRed; + pNodeRootRef = RBTreeRotateLeft(pNodeChildParent, pNodeRootRef); + pNodeTemp = pNodeChildParent->mpNodeRight; + } + + if(((pNodeTemp->mpNodeLeft == NULL) || (pNodeTemp->mpNodeLeft->mColor == kRBTreeColorBlack)) && + ((pNodeTemp->mpNodeRight == NULL) || (pNodeTemp->mpNodeRight->mColor == kRBTreeColorBlack))) + { + pNodeTemp->mColor = kRBTreeColorRed; + pNodeChild = pNodeChildParent; + pNodeChildParent = pNodeChildParent->mpNodeParent; + } + else + { + if((pNodeTemp->mpNodeRight == NULL) || (pNodeTemp->mpNodeRight->mColor == kRBTreeColorBlack)) + { + pNodeTemp->mpNodeLeft->mColor = kRBTreeColorBlack; + pNodeTemp->mColor = kRBTreeColorRed; + pNodeRootRef = RBTreeRotateRight(pNodeTemp, pNodeRootRef); + pNodeTemp = pNodeChildParent->mpNodeRight; + } + + pNodeTemp->mColor = pNodeChildParent->mColor; + pNodeChildParent->mColor = kRBTreeColorBlack; + + if(pNodeTemp->mpNodeRight) + pNodeTemp->mpNodeRight->mColor = kRBTreeColorBlack; + + pNodeRootRef = RBTreeRotateLeft(pNodeChildParent, pNodeRootRef); + break; + } + } + else + { + // The following is the same as above, with mpNodeRight <-> mpNodeLeft. + rbtree_node_base* pNodeTemp = pNodeChildParent->mpNodeLeft; + + if(pNodeTemp->mColor == kRBTreeColorRed) + { + pNodeTemp->mColor = kRBTreeColorBlack; + pNodeChildParent->mColor = kRBTreeColorRed; + + pNodeRootRef = RBTreeRotateRight(pNodeChildParent, pNodeRootRef); + pNodeTemp = pNodeChildParent->mpNodeLeft; + } + + if(((pNodeTemp->mpNodeRight == NULL) || (pNodeTemp->mpNodeRight->mColor == kRBTreeColorBlack)) && + ((pNodeTemp->mpNodeLeft == NULL) || (pNodeTemp->mpNodeLeft->mColor == kRBTreeColorBlack))) + { + pNodeTemp->mColor = kRBTreeColorRed; + pNodeChild = pNodeChildParent; + pNodeChildParent = pNodeChildParent->mpNodeParent; + } + else + { + if((pNodeTemp->mpNodeLeft == NULL) || (pNodeTemp->mpNodeLeft->mColor == kRBTreeColorBlack)) + { + pNodeTemp->mpNodeRight->mColor = kRBTreeColorBlack; + pNodeTemp->mColor = kRBTreeColorRed; + + pNodeRootRef = RBTreeRotateLeft(pNodeTemp, pNodeRootRef); + pNodeTemp = pNodeChildParent->mpNodeLeft; + } + + pNodeTemp->mColor = pNodeChildParent->mColor; + pNodeChildParent->mColor = kRBTreeColorBlack; + + if(pNodeTemp->mpNodeLeft) + pNodeTemp->mpNodeLeft->mColor = kRBTreeColorBlack; + + pNodeRootRef = RBTreeRotateRight(pNodeChildParent, pNodeRootRef); + break; + } + } + } + + if(pNodeChild) + pNodeChild->mColor = kRBTreeColorBlack; + } + + } // RBTreeErase + + +} // namespace mimp + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiStringDictionary.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiStringDictionary.cpp new file mode 100644 index 00000000..b7b691a5 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiStringDictionary.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +#include "MiStringDictionary.h" +#pragma warning(disable:4555) + +namespace mimp +{ + +StringDict *gStringDict=0; + +const char *nullstring = "null"; +const char *emptystring = ""; + +const StringRef StringRef::Null = SGET( nullstring ); +const StringRef StringRef::Empty = SGET( emptystring ); + +const StringRef StringRef::EmptyInitializer() +{ + return SGET( emptystring ); +} + +}; diff --git a/APEX_1.4/shared/general/meshimport/src/utils/MiSutil.cpp b/APEX_1.4/shared/general/meshimport/src/utils/MiSutil.cpp new file mode 100644 index 00000000..036da159 --- /dev/null +++ b/APEX_1.4/shared/general/meshimport/src/utils/MiSutil.cpp @@ -0,0 +1,784 @@ +/* + * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +#pragma warning(disable:4996) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#include "MiInparser.h" +#include "MiSutil.h" + +namespace mimp +{ + +static char ToLower(char c) +{ + if ( c >= 'A' && c <= 'Z' ) c+=32; + return c; +} + +char *stristr(const char *str,const char *key) // case insensitive str str +{ + MI_ASSERT( strlen(str) < 2048 ); + MI_ASSERT( strlen(key) < 2048 ); + char istr[2048]; + char ikey[2048]; + strncpy(istr,str,2048); + strncpy(ikey,key,2048); + MESH_IMPORT_STRING::strlwr(istr); + MESH_IMPORT_STRING::strlwr(ikey); + + char *foo = strstr(istr,ikey); + if ( foo ) + { + MiU32 loc = (MiU32)(foo - istr); + foo = (char *)str+loc; + } + + return foo; +} + +bool isstristr(const char *str,const char *key) // bool true/false based on case insenstive strstr +{ + bool ret = false; + const char *found = strstr(str,key); + if ( found ) ret = true; + return ret; +} + +MiU32 GetHex(MiU8 c) +{ + MiU32 v = 0; + c = (MiU8)ToLower((char)c); + if ( c >= '0' && c <= '9' ) + v = MiU32(c-'0'); + else + { + if ( c >= 'a' && c <= 'f' ) + { + v = MiU32(10 + c-'a'); + } + } + return v; +} + +MiU8 GetHEX1(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + ret = (GetHex((MiU8)foo[0])<<4) | GetHex((MiU8)foo[1]); + + if ( endptr ) + { + *endptr = foo+2; + } + + return (MiU8) ret; +} + + +MiU16 GetHEX2(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + ret = (GetHex((MiU8)foo[0])<<12) | (GetHex((MiU8)foo[1])<<8) | (GetHex((MiU8)foo[2])<<4) | GetHex((MiU8)foo[3]); + + if ( endptr ) + { + *endptr = foo+4; + } + + return (MiU16) ret; +} + +MiU32 GetHEX4(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + for (MiI32 i=0; i<8; i++) + { + ret = (ret<<4) | GetHex((MiU8)foo[i]); + } + + if ( endptr ) + { + *endptr = foo+8; + } + + return ret; +} + +MiU32 GetHEX(const char *foo,const char **endptr) +{ + MiU32 ret = 0; + + while ( *foo ) + { + MiU8 c = (MiU8)ToLower( *foo ); + MiU32 v = 0; + if ( c >= '0' && c <= '9' ) + v = MiU32(c-'0'); + else + { + if ( c >= 'a' && c <= 'f' ) + { + v = MiU32(10 + c-'a'); + } + else + break; + } + ret = (ret<<4)|v; + foo++; + } + + if ( endptr ) *endptr = foo; + + return ret; +} + + +bool IsWhitespace(char c) +{ + if ( c == ' ' || c == 9 || c == 13 || c == 10 || c == ',' ) return true; + return false; +} + + +const char * SkipWhitespace(const char *str) +{ + while ( *str && IsWhitespace(*str) ) str++; + return str; +} + +#define MAXNUM 32 + +MiF32 GetFloatValue(const char *str,const char **next) +{ + MiF32 ret = 0; + + if ( next ) *next = 0; + + str = SkipWhitespace(str); + + char dest[MAXNUM]; + char *dst = dest; + const char *hex = 0; + + for (MiI32 i=0; i<(MAXNUM-1); i++) + { + char c = *str; + if ( c == 0 || IsWhitespace(c) ) + { + if ( next ) *next = str; + break; + } + else if ( c == '$' ) + { + hex = str+1; + } + *dst++ = ToLower(c); + str++; + } + + *dst = 0; + + if ( hex ) + { + MiU32 iv = GetHEX(hex,0); + MiF32 *v = (MiF32 *)&iv; + ret = *v; + } + else if ( dest[0] == 'f' ) + { + if ( strcmp(dest,"fltmax") == 0 || strcmp(dest,"fmax") == 0 ) + { + ret = FLT_MAX; + } + else if ( strcmp(dest,"fltmin") == 0 || strcmp(dest,"fmin") == 0 ) + { + ret = FLT_MIN; + } + } + else if ( dest[0] == 't' ) // t or 'true' is treated as the value '1'. + { + ret = 1; + } + else + { + ret = (MiF32)atof(dest); + } + return ret; +} + +MiI32 GetIntValue(const char *str,const char **next) +{ + MiI32 ret = 0; + + if ( next ) *next = 0; + + str = SkipWhitespace(str); + + char dest[MAXNUM]; + char *dst = dest; + + for (MiI32 i=0; i<(MAXNUM-1); i++) + { + char c = *str; + if ( c == 0 || IsWhitespace(c) ) + { + if ( next ) *next = str; + break; + } + *dst++ = c; + str++; + } + + *dst = 0; + + ret = atoi(dest); + + return ret; +} + + +bool CharToWide(const char *source,wchar_t *dest,MiI32 maxlen) +{ + bool ret = false; + + ret = true; + mbstowcs(dest, source, (size_t)maxlen ); + + return ret; +} + +bool WideToChar(const wchar_t *source,char *dest,MiI32 maxlen) +{ + bool ret = false; + + ret = true; + wcstombs(dest, source, (size_t)maxlen ); + + return ret; +} + + + +const char * GetTrueFalse(MiU32 state) +{ + if ( state ) return "true"; + return "false"; +}; + + +const char * FloatString(MiF32 v,bool binary) +{ + static char data[64*16]; + static MiI32 index=0; + + char *ret = &data[index*64]; + index++; + if (index == 16 ) index = 0; + + if ( !MESH_IMPORT_INTRINSICS::isFinite(v) ) + { + MI_ALWAYS_ASSERT(); + strcpy(ret,"0"); // not a valid number! + } +/*** + else if ( v == FLT_MAX ) + { + strcpy(ret,"fltmax"); + } + else if ( v == FLT_MIN ) + { + strcpy(ret,"fltmin"); + } +***/ + else if ( v == 1 ) + { + strcpy(ret,"1"); + } + else if ( v == 0 ) + { + strcpy(ret,"0"); + } + else if ( v == - 1 ) + { + strcpy(ret,"-1"); + } + else + { + if ( binary ) + { + MiU32 *iv = (MiU32 *) &v; + MESH_IMPORT_STRING::snprintf(ret,64,"%.4f$%x", v, *iv ); + } + else + { + MESH_IMPORT_STRING::snprintf(ret,64,"%.9f", v ); + const char *dot = strstr(ret,"."); + if ( dot ) + { + MiI32 len = (MiI32)strlen(ret); + char *foo = &ret[len-1]; + while ( *foo == '0' ) foo--; + if ( *foo == '.' ) + *foo = 0; + else + foo[1] = 0; + } + } + } + + return ret; +} + + +char * NextSep(char *str,char &c) +{ + while ( *str && *str != ',' && *str != ')' ) + { + str++; + } + c = *str; + return str; +} + +MiI32 GetUserArgs(const char *us,const char *key,const char **args) +{ + MiI32 ret = 0; + static char arglist[2048]; + strcpy(arglist,us); + + char keyword[512]; + MESH_IMPORT_STRING::snprintf(keyword,512,"%s(", key ); + char *found = strstr(arglist,keyword); + if ( found ) + { + found = strstr(found,"("); + found++; + args[ret] = found; + ret++; + static bool bstate = true; + while ( bstate ) + { + char c; + found = NextSep(found,c); + if ( found ) + { + *found = 0; + if ( c == ',' ) + { + found++; + args[ret] = found; + ret++; + } + else + { + break; + } + } + } + } + return ret; +} + +bool GetUserSetting(const char *us,const char *key,MiI32 &v) +{ + bool ret = false; + + const char *argv[256]; + + MiI32 argc = GetUserArgs(us,key,argv); + if ( argc ) + { + v = atoi( argv[0] ); + ret = true; + } + return ret; +} + +bool GetUserSetting(const char *us,const char *key,const char * &v) +{ + bool ret = false; + + const char *argv[256]; + MiI32 argc = GetUserArgs(us,key,argv); + if ( argc ) + { + v = argv[0]; + ret = true; + } + return ret; +} + +const char ** GetArgs(char *str,MiI32 &count) // destructable parser, stomps EOS markers on the input string! +{ + InPlaceParser ipp; + + return ipp.GetArglist(str,count); +} + +const char * GetRootName(const char *fname) +{ + static char scratch[512]; + + const char *source = fname; + + const char *start = fname; + + while ( *source ) + { + if ( *source == '/' || *source == '\\' ) + { + start = source+1; + } + source++; + } + + strcpy(scratch,start); + + char *dot = strrchr( scratch, '.' ); + + if ( dot ) + { + *dot = 0; + } + + return scratch; +} + +bool IsTrueFalse(const char *c) +{ + bool ret = false; + + if ( MESH_IMPORT_STRING::stricmp(c,"true") == 0 || MESH_IMPORT_STRING::stricmp(c,"1") == 0 ) ret = true; + + return ret; +} + + +bool IsDirectory(const char *fname,char *path,char *basename,char *postfix) +{ + bool ret = false; + + strcpy(path,fname); + strcpy(basename,fname); + + char *foo = path; + char *last = 0; + + while ( *foo ) + { + if ( *foo == '\\' || *foo == '/' ) last = foo; + foo++; + } + + if ( last ) + { + strcpy(basename,last+1); + *last = 0; + ret = true; + } + + const char *scan = fname; + + static bool bstate = true; + while ( bstate ) + { + const char *dot = strstr(scan,"."); + if ( dot == 0 ) + break; + scan = dot+1; + } + + strcpy(postfix,scan); + MESH_IMPORT_STRING::strlwr(postfix); + + return ret; +} + +bool hasSpace(const char *str) // true if the string contains a space +{ + bool ret = false; + + while ( *str ) + { + char c = *str++; + if ( c == 32 || c == 9 ) + { + ret = true; + break; + } + } + return ret; +} + + +const char * lastDot(const char *src) +{ + const char *ret = 0; + + const char *dot = strchr(src,'.'); + while ( dot ) + { + ret = dot; + dot = strchr(dot+1,'.'); + } + return ret; +} + + +const char * lastChar(const char *src,char c) +{ + const char *ret = 0; + + const char *dot = (const char *)strchr(src,c); + while ( dot ) + { + ret = dot; + dot = (const char *)strchr(dot+1,c); + } + return ret; +} + + +const char * lastSlash(const char *src) // last forward or backward slash character, null if none found. +{ + const char *ret = 0; + + const char *dot = strchr(src,'\\'); + if ( dot == 0 ) + dot = strchr(src,'/'); + while ( dot ) + { + ret = dot; + dot = strchr(ret+1,'\\'); + if ( dot == 0 ) + dot = strchr(ret+1,'/'); + } + return ret; +} + + +const char *fstring(MiF32 v) +{ + static char data[64 *16]; + static MiI32 index = 0; + + char *ret = &data[index *64]; + index++; + if (index == 16) + { + index = 0; + } + + if (v == FLT_MIN) + { + return "-INF"; + } + // collada notation for FLT_MIN and FLT_MAX + if (v == FLT_MAX) + { + return "INF"; + } + + if (v == 1) + { + strcpy(ret, "1"); + } + else if (v == 0) + { + strcpy(ret, "0"); + } + else if (v == - 1) + { + strcpy(ret, "-1"); + } + else + { + MESH_IMPORT_STRING::snprintf(ret,16, "%.9f", v); + const char *dot = strstr(ret, "."); + if (dot) + { + MiI32 len = (MiI32)strlen(ret); + char *foo = &ret[len - 1]; + while (*foo == '0') + { + foo--; + } + if (*foo == '.') + { + *foo = 0; + } + else + { + foo[1] = 0; + } + } + } + + return ret; +} + + +#define MAXNUMERIC 32 // JWR support up to 16 32 character long numeric formated strings +#define MAXFNUM 16 + +static char gFormat[MAXNUMERIC*MAXFNUM]; +static MiI32 gIndex=0; + +const char * formatNumber(MiI32 number) // JWR format this integer into a fancy comma delimited string +{ + char * dest = &gFormat[gIndex*MAXNUMERIC]; + gIndex++; + if ( gIndex == MAXFNUM ) gIndex = 0; + + char scratch[512]; + +#if defined (LINUX_GENERIC) || defined(LINUX) || defined(__CELLOS_LV2__) || defined(__APPLE__) || defined(ANDROID) || PX_PS4 || PX_LINUX_FAMILY + snprintf(scratch, 10, "%d", number); +#else + itoa(number,scratch,10); +#endif + + char *str = dest; + MiU32 len = (MiU32)strlen(scratch); + for (MiU32 i=0; i<len; i++) + { + MiI32 place = ((MiI32)len-1)-(MiI32)i; + *str++ = scratch[i]; + if ( place && (place%3) == 0 ) *str++ = ','; + } + *str = 0; + + return dest; +} + + +bool fqnMatch(const char *n1,const char *n2) // returns true if two fully specified file names are 'the same' but ignores case sensitivty and treats either a forward or backslash as the same character. +{ + bool ret = true; + + while ( *n1 ) + { + char c1 = *n1++; + char c2 = *n2++; + if ( c1 >= 'A' && c1 <= 'Z' ) c1+=32; + if ( c2 >= 'A' && c2 <= 'Z' ) c2+=32; + if ( c1 == '\\' ) c1 = '/'; + if ( c2 == '\\' ) c2 = '/'; + if ( c1 != c2 ) + { + ret = false; + break; + } + } + if ( ret ) + { + if ( *n2 ) ret = false; + } + + return ret; + +} + + +bool getBool(const char *str) +{ + bool ret = false; + + if ( MESH_IMPORT_STRING::stricmp(str,"true") == 0 || strcmp(str,"1") == 0 || MESH_IMPORT_STRING::stricmp(str,"yes") == 0 ) ret = true; + + return ret; +} + + +bool needsQuote(const char *str) // if this string needs quotes around it (spaces, commas, #, etc) +{ + bool ret = false; + + if ( str ) + { + while ( *str ) + { + char c = *str++; + if ( c == ',' || c == '#' || c == 32 || c == 9 ) + { + ret = true; + break; + } + } + } + return ret; +} + +void normalizeFQN(const wchar_t *source,wchar_t *dest) +{ + char scratch[512]; + WideToChar(source,scratch,512); + char temp[512]; + normalizeFQN(scratch,temp); + CharToWide(temp,dest,512); +} + +void normalizeFQN(const char *source,char *dest) +{ + if ( source && strlen(source ) ) + { + while ( *source ) + { + char c = *source++; + if ( c == '\\' ) c = '/'; + if ( c >= 'A' && c <= 'Z' ) c+=32; + *dest++ = c; + } + *dest = 0; + } + else + { + *dest = 0; + } +} + + + +bool endsWith(const char *str,const char *ends,bool caseSensitive) +{ + bool ret = false; + + MiI32 l1 = (MiI32) strlen(str); + MiI32 l2 = (MiI32) strlen(ends); + if ( l1 >= l2 ) + { + MiI32 diff = l1-l2; + const char *echeck = &str[diff]; + if ( caseSensitive ) + { + if ( strcmp(echeck,ends) == 0 ) + { + ret = true; + } + } + else + { + if ( MESH_IMPORT_STRING::stricmp(echeck,ends) == 0 ) + { + ret = true; + } + } + } + return ret; +} + +}; |