aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/shared/general/meshimport/src
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/meshimport/src
downloadphysx-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')
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.cpp664
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportAPX.h26
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.cpp634
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportDynamicSystem.h27
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.cpp414
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportEZB.h28
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.cpp573
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportFBX.h26
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.cpp314
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/ExportPOVRay.h26
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImport.cpp2569
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.cpp1533
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/MeshImportBuilder.h45
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.cpp132
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImport/VtxWeld.h123
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.cpp1271
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImportEzm/ImportEzm.h26
-rw-r--r--APEX_1.4/shared/general/meshimport/src/MeshImportEzm/MeshImportEzm.cpp209
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiAsc2Bin.cpp388
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiFastXML.cpp801
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiFileInterface.cpp629
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.cpp27
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiFloatMath.inl5648
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiInparser.cpp421
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiMapSet.cpp539
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiStringDictionary.cpp37
-rw-r--r--APEX_1.4/shared/general/meshimport/src/utils/MiSutil.cpp784
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;
+}
+
+};