Преглед изворни кода

Merge remote-tracking branch 'official/master' into contrib

Conflicts:
	code/ColladaParser.cpp
	include/assimp/config.h
Léo Terziman пре 10 година
родитељ
комит
60d58901a5
64 измењених фајлова са 14010 додато и 1562 уклоњено
  1. 5 1
      .gitignore
  2. 11 2
      .travis.yml
  3. 2 0
      CMakeLists.txt
  4. 5 0
      CREDITS
  5. 2 2
      code/3DSExporter.cpp
  6. 1 1
      code/AssbinExporter.cpp
  7. 1 1
      code/AssxmlExporter.cpp
  8. 17 1
      code/BlenderIntermediate.h
  9. 10 7
      code/BlenderLoader.cpp
  10. 2 0
      code/BlobIOSystem.h
  11. 3 0
      code/C4DImporter.cpp
  12. 26 3
      code/CMakeLists.txt
  13. 1 1
      code/ColladaExporter.cpp
  14. 6 4
      code/ColladaParser.cpp
  15. 128 15
      code/Exporter.cpp
  16. 13 0
      code/GenericProperty.h
  17. 2 2
      code/IFCCurve.cpp
  18. 6 3
      code/IFCLoader.cpp
  19. 1 1
      code/IFCUtil.cpp
  20. 53 47
      code/ImporterRegistry.cpp
  21. 1 1
      code/ObjExporter.cpp
  22. 518 518
      code/ObjFileImporter.cpp
  23. 37 37
      code/ObjFileImporter.h
  24. 486 486
      code/ObjFileParser.cpp
  25. 59 59
      code/ObjFileParser.h
  26. 50 50
      code/OgreImporter.h
  27. 691 0
      code/OpenGEXImporter.cpp
  28. 158 0
      code/OpenGEXImporter.h
  29. 265 0
      code/OpenGEXStructs.h
  30. 2 2
      code/PlyExporter.cpp
  31. 46 27
      code/PlyLoader.cpp
  32. 2 2
      code/STLExporter.cpp
  33. 28 9
      code/XFileExporter.cpp
  34. 8 2
      code/XFileExporter.h
  35. 64 0
      contrib/openddlparser/CMakeLists.txt
  36. 111 0
      contrib/openddlparser/README.md
  37. 184 0
      contrib/openddlparser/code/DDLNode.cpp
  38. 900 0
      contrib/openddlparser/code/OpenDDLParser.cpp
  39. 256 0
      contrib/openddlparser/code/Value.cpp
  40. 90 0
      contrib/openddlparser/include/openddlparser/DDLNode.h
  41. 170 0
      contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
  42. 131 0
      contrib/openddlparser/include/openddlparser/OpenDDLParser.h
  43. 249 0
      contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
  44. 97 0
      contrib/openddlparser/include/openddlparser/Value.h
  45. 46 46
      include/assimp/Compiler/pushpack1.h
  46. 185 9
      include/assimp/Exporter.hpp
  47. 11 2
      include/assimp/config.h
  48. 53 44
      port/jassimp/build.xml
  49. 13 0
      port/jassimp/jassimp-native/Android.mk
  50. 59 25
      port/jassimp/jassimp-native/src/jassimp.cpp
  51. 0 33
      test/RunSingleUnitTestSuite.bat
  52. 0 94
      test/RunUnitTestSuite.bat
  53. BIN
      test/models-nonbsd/FBX/2013_BINARY/anims_with_full_rotations_between_keys.fbx
  54. 754 0
      test/models-nonbsd/PLY/ant-half.ply
  55. 165 0
      test/models-nonbsd/PLY/ant-half.ply.license
  56. BIN
      test/models/BLEND/BlenderDefault_271.blend
  57. 7561 0
      test/models/Collada/anims_with_full_rotations_between_keys.DAE
  58. 95 0
      test/models/OpenGEX/Example.ogex
  59. 13 16
      test/regression/run.py
  60. 1 1
      test/regression/settings.py
  61. 1 1
      tools/assimp_cmd/CMakeLists.txt
  62. 23 7
      tools/assimp_cmd/CompareDump.cpp
  63. 124 0
      workspaces/Android-NDK/jni/Android.mk
  64. 8 0
      workspaces/Android-NDK/jni/Application.mk

+ 5 - 1
.gitignore

@@ -10,7 +10,7 @@ build
 # Output
 bin/
 lib/
-contrib/
+
 
 # Generated
 assimp.pc
@@ -54,3 +54,7 @@ tools/assimp_view/assimp_viewer.vcxproj.user
 
 # Unix editor backups
 *~
+test/gtest/src/gtest-stamp/gtest-gitinfo.txt
+test/gtest/src/gtest-stamp/gtest-gitclone-lastrun.txt
+Assimp.opensdf
+contrib/zlib/CTestTestfile.cmake

+ 11 - 2
.travis.yml

@@ -1,8 +1,15 @@
 before_install:
   - sudo apt-get install cmake python3
+  - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
+
+branches:
+  only:
+    - master
 
 env:
-    matrix:
+  global:
+    - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
+  matrix:
     - LINUX=1 TRAVIS_NO_EXPORT=YES
     - LINUX=1 TRAVIS_NO_EXPORT=NO
     - LINUX=1 TRAVIS_STATIC_BUILD=ON
@@ -11,6 +18,7 @@ env:
     - WINDOWS=1 TRAVIS_NO_EXPORT=NO
     - WINDOWS=1 TRAVIS_STATIC_BUILD=ON
     - WINDOWS=1 TRAVIS_STATIC_BUILD=OFF
+    - ANDROID=1
 
 language: cpp
 
@@ -20,8 +28,10 @@ compiler:
 
 install:
   - if [ $WINDOWS ]; then travis_retry sudo apt-get install -q -y gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64; fi 
+  - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
 
 script:
+  - if [ $ANDROID ]; then ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni ; fi
   - cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD
   - make
   - sudo make install
@@ -34,4 +44,3 @@ script:
   - echo "=========================================================="
   - echo "REGRESSION TEST FAILS (results/run_regression_suite_failures.csv)"
   - cat ../results/run_regression_suite_failures.csv
-

+ 2 - 0
CMakeLists.txt

@@ -11,6 +11,8 @@ set (PROJECT_VERSION "${ASSIMP_VERSION}")
 
 set(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources")
 
+add_definitions( -DOPENDDL_NO_USE_CPP11 )
+
 # Get the current working branch
 execute_process(
     COMMAND git rev-parse --abbrev-ref HEAD

+ 5 - 0
CREDITS

@@ -151,3 +151,8 @@ Ogre Binary format support
 
 - Filip Wasil, Tieto Poland Sp. z o.o.
 Android JNI asset extraction support
+
+- Richard Steffen
+Contributed X File exporter
+Contributed ExportProperties interface
+

+ 2 - 2
code/3DSExporter.cpp

@@ -144,7 +144,7 @@ namespace {
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
-void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	boost::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
 	if(!outfile) {
@@ -188,8 +188,8 @@ Discreet3DSExporter:: Discreet3DSExporter(boost::shared_ptr<IOStream> outfile, c
 
 	{
 		ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH);
-		WriteMeshes();
 		WriteMaterials();
+		WriteMeshes();
 
 		{
 			ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE);

+ 1 - 1
code/AssbinExporter.cpp

@@ -754,7 +754,7 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
 		}
 	};
 
-void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	AssbinExport exporter;
 	exporter.WriteBinaryDump( pFile, pIOSystem, pScene );

+ 1 - 1
code/AssxmlExporter.cpp

@@ -621,7 +621,7 @@ void WriteDump(const aiScene* scene, IOStream* io, bool shortened)
 
 } // end of namespace AssxmlExport
 
-void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	IOStream * out = pIOSystem->Open( pFile, "wt" );
 	if (!out) return;

+ 17 - 1
code/BlenderIntermediate.h

@@ -118,6 +118,16 @@ namespace Blender {
 #ifdef _MSC_VER
 #	pragma warning(disable:4351)
 #endif
+
+	struct ObjectCompare {
+		bool operator() (const Object* left, const Object* right) const {
+			return strcmp(left->id.name, right->id.name) == -1;
+		}
+	};
+
+	// When keeping objects in sets, sort them by their name.
+	typedef std::set<const Object*, ObjectCompare> ObjectSet;
+
 	// --------------------------------------------------------------------
 	/** ConversionData acts as intermediate storage location for
 	 *  the various ConvertXXX routines in BlenderImporter.*/
@@ -130,7 +140,13 @@ namespace Blender {
 			, db(db)
 		{}
 
-		std::set<const Object*> objects;
+		struct ObjectCompare {
+			bool operator() (const Object* left, const Object* right) const {
+				return strcmp(left->id.name, right->id.name) == -1;
+			}
+		};
+
+		ObjectSet objects;
 
 		TempArray <std::vector, aiMesh> meshes;
 		TempArray <std::vector, aiCamera> cameras;

+ 10 - 7
code/BlenderLoader.cpp

@@ -559,24 +559,26 @@ void BlenderImporter::BuildMaterials(ConversionData& conv_data)
 		if (mesh->mMaterialIndex == static_cast<unsigned int>( -1 )) {
 
 			if (index == static_cast<unsigned int>( -1 )) {
-
-				// ok, we need to add a dedicated default material for some poor material-less meshes
+				// Setup a default material.
 				boost::shared_ptr<Material> p(new Material());
+				ai_assert(::strlen(AI_DEFAULT_MATERIAL_NAME) < sizeof(p->id.name)-2);
 				strcpy( p->id.name+2, AI_DEFAULT_MATERIAL_NAME );
 
+				// Note: MSVC11 does not zero-initialize Material here, although it should.
+				// Thus all relevant fields should be explicitly initialized. We cannot add
+				// a default constructor to Material since the DNA codegen does not support
+				// parsing it.
 				p->r = p->g = p->b = 0.6f;
 				p->specr = p->specg = p->specb = 0.6f;
 				p->ambr = p->ambg = p->ambb = 0.0f;
 				p->mirr = p->mirg = p->mirb = 0.0f;
 				p->emit = 0.f;
 				p->alpha = 0.f;
-
-				// XXX add more / or add default c'tor to Material
+				p->har = 0;
 
 				index = static_cast<unsigned int>( conv_data.materials_raw.size() );
 				conv_data.materials_raw.push_back(p);
-
-				LogInfo("Adding default material ...");
+				LogInfo("Adding default material");
 			}
 			mesh->mMaterialIndex = index;
 		}
@@ -591,6 +593,7 @@ void BlenderImporter::BuildMaterials(ConversionData& conv_data)
 	
 		aiMaterial* mout = new aiMaterial();
 		conv_data.materials->push_back(mout);
+		// For any new material field handled here, the default material above must be updated with an appropriate default value.
 
 		// set material name
 		aiString name = aiString(mat->id.name+2); // skip over the name prefix 'MA'
@@ -1044,7 +1047,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
 aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, ConversionData& conv_data, const aiMatrix4x4& parentTransform)
 {
 	std::deque<const Object*> children;
-	for(std::set<const Object*>::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) {
+	for(ObjectSet::iterator it = conv_data.objects.begin(); it != conv_data.objects.end() ;) {
 		const Object* object = *it;
 		if (object->parent == obj) {
 			children.push_back(object);

+ 2 - 0
code/BlobIOSystem.h

@@ -120,9 +120,11 @@ public:
 		{
 		case aiOrigin_CUR:
 			cursor += pOffset;
+			break;
 
 		case aiOrigin_END:
 			cursor = file_size - pOffset;
+			break;
 
 		case aiOrigin_SET:
 			cursor = pOffset;

+ 3 - 0
code/C4DImporter.cpp

@@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of the Cinema4D importer class.
  */
 #include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
 
 // no #ifdefing here, Cinema4D support is carried out in a branch of assimp
 // where it is turned on in the CMake settings. 
@@ -639,3 +640,5 @@ unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
 	ai_assert((*it).second < mat_count);
 	return (*it).second;
 }
+
+#endif // ASSIMP_BUILD_NO_C4D_IMPORTER

+ 26 - 3
code/CMakeLists.txt

@@ -265,8 +265,6 @@ SET( LWS_SRCS
 )
 SOURCE_GROUP( LWS FILES ${LWS_SRCS})
 
-
-
 SET( MD2_SRCS
 	MD2FileData.h
 	MD2Loader.cpp
@@ -360,6 +358,13 @@ SET( Ogre_SRCS
 )
 SOURCE_GROUP( Ogre FILES ${Ogre_SRCS})
 
+SET( OpenGEX_SRCS
+    OpenGEXImporter.cpp
+    OpenGEXImporter.h
+    OpenGEXStructs.h
+)
+SOURCE_GROUP( OpenGEX FILES ${OpenGEX_SRCS})
+
 SET( Ply_SRCS
 	PlyLoader.cpp
 	PlyLoader.h
@@ -635,6 +640,17 @@ SET( unzip_SRCS
 )
 SOURCE_GROUP( unzip FILES ${unzip_SRCS})
 
+SET ( openddl_parser_SRCS
+    ../contrib/openddlparser/code/OpenDDLParser.cpp
+    ../contrib/openddlparser/code/DDLNode.cpp
+    ../contrib/openddlparser/code/Value.cpp
+    ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
+    ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
+    ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
+    ../contrib/openddlparser/include/openddlparser/DDLNode.h
+    ../contrib/openddlparser/include/openddlparser/Value.h
+)
+SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
 
 # VC2010 fixes
 if(MSVC10)
@@ -690,6 +706,7 @@ SET( assimp_src
 	${OFFFormat_SRCS}
 	${Obj_SRCS}
 	${Ogre_SRCS}
+    ${OpenGEX_SRCS}
 	${Ply_SRCS}
 	${Q3D_SRCS}
 	${Q3BSP_SRCS}
@@ -714,6 +731,7 @@ SET( assimp_src
 	${unzip_compile_SRCS}
 	${Poly2Tri_SRCS}
 	${Clipper_SRCS}
+    ${openddl_parser_SRCS}
 	# Necessary to show the headers in the project when using the VC++ generator:
 	${Boost_SRCS}
 
@@ -725,6 +743,11 @@ SET( assimp_src
 	# Moreover it's a drag to recompile assimp entirely each time a modification is made to one of the included header, which is definitely counter-productive.)
 	AssimpPCH.cpp
 )
+add_definitions( -DOPENDDLPARSER_BUILD )
+
+INCLUDE_DIRECTORIES( 
+    ../contrib/openddlparser/include
+)
 
 IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 	SET( assimp_src ${assimp_src} ${C4D_SRCS})
@@ -735,7 +758,7 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
 ADD_LIBRARY( assimp ${assimp_src} )
 
-TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES})
+TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} )
 
 if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
 	set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI)

+ 1 - 1
code/ColladaExporter.cpp

@@ -59,7 +59,7 @@ namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
-void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	std::string path = "";
 	std::string file = pFile;

+ 6 - 4
code/ColladaParser.cpp

@@ -1989,10 +1989,12 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
 			break;
 		}
 	}
-
-	// small sanity check
-	if (primType != Prim_TriFans && primType != Prim_TriStrips)
-		ai_assert(actualPrimitives == numPrimitives)
+
+#ifdef ASSIMP_BUILD_DEBUG  
+	if (primType != Prim_TriFans && primType != Prim_TriStrips) {
+		ai_assert(actualPrimitives == numPrimitives);
+	}
+#endif
 
 	// only when we're done reading all <p> tags (and thus know the final vertex count) can we commit the submesh
 	subgroup.mNumFaces = actualPrimitives;

+ 128 - 15
code/Exporter.cpp

@@ -72,16 +72,16 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
 // ------------------------------------------------------------------------------------------------
 // Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
 // do not use const, because some exporter need to convert the scene temporary
-void ExportSceneCollada(const char*,IOSystem*, const aiScene*);
-void ExportSceneXFile(const char*,IOSystem*, const aiScene*); 
-void ExportSceneObj(const char*,IOSystem*, const aiScene*);
-void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
-void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*);
-void ExportScenePly(const char*,IOSystem*, const aiScene*);
-void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*);
-void ExportScene3DS(const char*, IOSystem*, const aiScene*);
-void ExportSceneAssbin(const char*, IOSystem*, const aiScene*);
-void ExportSceneAssxml(const char*, IOSystem*, const aiScene*);
+void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*); 
+void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 
 // ------------------------------------------------------------------------------------------------
 // global array of all export formats which Assimp supports in its current build
@@ -91,7 +91,7 @@ Exporter::ExportFormatEntry gExporters[] =
 	Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
 #endif
 
-#ifndef ASSIMP_BUILD_NO_FXILE_EXPORTER
+#ifndef ASSIMP_BUILD_NO_XFILE_EXPORTER
 	Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
 		aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
 #endif
@@ -226,7 +226,7 @@ bool Exporter :: IsDefaultIOHandler() const
 
 
 // ------------------------------------------------------------------------------------------------
-const aiExportDataBlob* Exporter :: ExportToBlob(  const aiScene* pScene, const char* pFormatId, unsigned int )
+const aiExportDataBlob* Exporter :: ExportToBlob(  const aiScene* pScene, const char* pFormatId, unsigned int, const ExportProperties* pProperties)
 {
 	if (pimpl->blob) {
 		delete pimpl->blob;
@@ -282,7 +282,7 @@ bool IsVerboseFormat(const aiScene* pScene)
 
 
 // ------------------------------------------------------------------------------------------------
-aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing )
+aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties)
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
@@ -290,7 +290,7 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const
 	// format. They will likely not be aware that there is a flag in the scene to indicate
 	// this, however. To avoid surprises and bug reports, we check for duplicates in
 	// meshes upfront.
-	const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
+	const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);	
 
 	pimpl->mError = "";
 	for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
@@ -397,7 +397,8 @@ aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const
 					proc.Execute(scenecopy.get());
 				}
 
-				exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get());
+				ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
+				exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
 			}
 			catch (DeadlyExportError& err) {
 				pimpl->mError = err.what();
@@ -492,4 +493,116 @@ void Exporter :: UnregisterExporter(const char* id)
 	}
 }
 
+ExportProperties :: ExportProperties() {}
+
+ExportProperties::ExportProperties(const ExportProperties &other)
+	 : mIntProperties(other.mIntProperties),
+   mFloatProperties(other.mFloatProperties),
+   mStringProperties(other.mStringProperties),
+   mMatrixProperties(other.mMatrixProperties)
+{
+	
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void ExportProperties :: SetPropertyInteger(const char* szName, int iValue, 
+	bool* bWasExisting /*= NULL*/)
+{
+	SetGenericProperty<int>(mIntProperties, szName,iValue,bWasExisting);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void ExportProperties :: SetPropertyFloat(const char* szName, float iValue, 
+	bool* bWasExisting /*= NULL*/)
+{
+	SetGenericProperty<float>(mFloatProperties, szName,iValue,bWasExisting);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void ExportProperties :: SetPropertyString(const char* szName, const std::string& value, 
+	bool* bWasExisting /*= NULL*/)
+{
+	SetGenericProperty<std::string>(mStringProperties, szName,value,bWasExisting);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void ExportProperties :: SetPropertyMatrix(const char* szName, const aiMatrix4x4& value, 
+	bool* bWasExisting /*= NULL*/)
+{
+	SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value,bWasExisting);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a configuration property
+int ExportProperties :: GetPropertyInteger(const char* szName, 
+	int iErrorReturn /*= 0xffffffff*/) const
+{
+	return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a configuration property
+float ExportProperties :: GetPropertyFloat(const char* szName, 
+	float iErrorReturn /*= 10e10*/) const
+{
+	return GetGenericProperty<float>(mFloatProperties,szName,iErrorReturn);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a configuration property
+const std::string ExportProperties :: GetPropertyString(const char* szName, 
+	const std::string& iErrorReturn /*= ""*/) const
+{
+	return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+const aiMatrix4x4 ExportProperties :: GetPropertyMatrix(const char* szName, 
+	const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
+{
+	return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+bool ExportProperties :: HasPropertyInteger(const char* szName) const
+{
+	return HasGenericProperty<int>(mIntProperties, szName);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+bool ExportProperties :: HasPropertyBool(const char* szName) const
+{
+	return HasGenericProperty<int>(mIntProperties, szName);
+};
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+bool ExportProperties :: HasPropertyFloat(const char* szName) const
+{
+	return HasGenericProperty<float>(mFloatProperties, szName);
+};
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+bool ExportProperties :: HasPropertyString(const char* szName) const
+{
+	return HasGenericProperty<std::string>(mStringProperties, szName);
+};
+
+// ------------------------------------------------------------------------------------------------
+// Has a configuration property
+bool ExportProperties :: HasPropertyMatrix(const char* szName) const
+{
+	return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
+};
+
+
 #endif // !ASSIMP_BUILD_NO_EXPORT

+ 13 - 0
code/GenericProperty.h

@@ -108,5 +108,18 @@ inline void SetGenericPropertyPtr(std::map< unsigned int, T* >& list,
 		*bWasExisting = true;
 }
 
+// ------------------------------------------------------------------------------------------------
+template <class T>
+inline const bool HasGenericProperty(const std::map< unsigned int, T >& list, 
+	const char* szName)
+{
+	ai_assert(NULL != szName);
+	const uint32_t hash = SuperFastHash(szName);
+
+	typename std::map<unsigned int, T>::const_iterator it = list.find(hash);
+	if (it == list.end()) return false;
+	
+	return true;
+}
 
 #endif // !! AI_GENERIC_PROPERTY_H_INCLUDED

+ 2 - 2
code/IFCCurve.cpp

@@ -648,10 +648,10 @@ void Curve :: SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
 	ai_assert(InRange(a) && InRange(b));
 
 	const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b));
-	out.verts.reserve( out.verts.size() + cnt );
+	out.verts.reserve( out.verts.size() + cnt + 1);
 
 	IfcFloat p = a, delta = (b-a)/cnt;
-	for(size_t i = 0; i < cnt; ++i, p += delta) {
+	for(size_t i = 0; i <= cnt; ++i, p += delta) {
 		out.verts.push_back(Eval(p));
 	}
 }

+ 6 - 3
code/IFCLoader.cpp

@@ -677,10 +677,11 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
 	const STEP::DB::RefMap& refs = conv.db.GetRefs();
 
 	// skip over space and annotation nodes - usually, these have no meaning in Assimp's context
+	bool skipGeometry = false;
 	if(conv.settings.skipSpaceRepresentations) {
 		if(const IfcSpace* const space = el.ToPtr<IfcSpace>()) {
 			IFCImporter::LogDebug("skipping IfcSpace entity due to importer settings");
-			return NULL;
+			skipGeometry = true;
 		}
 	}
 
@@ -850,8 +851,10 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
 			conv.apply_openings = &openings;
 		}
 
-		ProcessProductRepresentation(el,nd.get(),subnodes,conv);
-		conv.apply_openings = conv.collect_openings = NULL;
+		if (!skipGeometry) {
+		  ProcessProductRepresentation(el,nd.get(),subnodes,conv);
+		  conv.apply_openings = conv.collect_openings = NULL;
+		}
 
 		if (subnodes.size()) {
 			nd->mChildren = new aiNode*[subnodes.size()]();

+ 1 - 1
code/IFCUtil.cpp

@@ -236,7 +236,7 @@ IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
 
 struct CompareVector
 {
-	bool operator () (const IfcVector3& a, const IfcVector3& b)
+	bool operator () (const IfcVector3& a, const IfcVector3& b) const
 	{
 		IfcVector3 d = a - b;
 		IfcFloat eps = 1e-6;

+ 53 - 47
code/ImporterRegistry.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2015, assimp team
 
 All rights reserved.
 
@@ -142,6 +142,9 @@ corresponding preprocessor flag to selectively disable formats.
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 #	include "OgreImporter.h"
 #endif
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+#   include "OpenGEXImporter.h"
+#endif
 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
 #	include "MS3DLoader.h"
 #endif
@@ -179,132 +182,135 @@ namespace Assimp {
 // ------------------------------------------------------------------------------------------------
 void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 {
-	// ----------------------------------------------------------------------------
-	// Add an instance of each worker class here
-	// (register_new_importers_here)
-	// ----------------------------------------------------------------------------
-	out.reserve(64);
+    // ----------------------------------------------------------------------------
+    // Add an instance of each worker class here
+    // (register_new_importers_here)
+    // ----------------------------------------------------------------------------
+    out.reserve(64);
 #if (!defined ASSIMP_BUILD_NO_X_IMPORTER)
-	out.push_back( new XFileImporter());
+    out.push_back( new XFileImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER)
-	out.push_back( new ObjFileImporter());
+    out.push_back( new ObjFileImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
-	out.push_back( new Discreet3DSImporter());
+    out.push_back( new Discreet3DSImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
-	out.push_back( new MD3Importer());
+    out.push_back( new MD3Importer());
 #endif
 #if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER)
-	out.push_back( new MD2Importer());
+    out.push_back( new MD2Importer());
 #endif
 #if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER)
-	out.push_back( new PLYImporter());
+    out.push_back( new PLYImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER)
-	out.push_back( new MDLImporter());
+    out.push_back( new MDLImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER)
-	out.push_back( new ASEImporter());
+    out.push_back( new ASEImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER)
-	out.push_back( new HMPImporter());
+    out.push_back( new HMPImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER)
-	out.push_back( new SMDImporter());
+    out.push_back( new SMDImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER)
-	out.push_back( new MDCImporter());
+    out.push_back( new MDCImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER)
-	out.push_back( new MD5Importer());
+    out.push_back( new MD5Importer());
 #endif
 #if (!defined ASSIMP_BUILD_NO_STL_IMPORTER)
-	out.push_back( new STLImporter());
+    out.push_back( new STLImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER)
-	out.push_back( new LWOImporter());
+    out.push_back( new LWOImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER)
-	out.push_back( new DXFImporter());
+    out.push_back( new DXFImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER)
-	out.push_back( new NFFImporter());
+    out.push_back( new NFFImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER)
-	out.push_back( new RAWImporter());
+    out.push_back( new RAWImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER)
-	out.push_back( new OFFImporter());
+    out.push_back( new OFFImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_AC_IMPORTER)
-	out.push_back( new AC3DImporter());
+    out.push_back( new AC3DImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER)
-	out.push_back( new BVHLoader());
+    out.push_back( new BVHLoader());
 #endif
 #if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER)
-	out.push_back( new IRRMeshImporter());
+    out.push_back( new IRRMeshImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER)
-	out.push_back( new IRRImporter());
+    out.push_back( new IRRImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER)
-	out.push_back( new Q3DImporter());
+    out.push_back( new Q3DImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER)
-	out.push_back( new B3DImporter());
+    out.push_back( new B3DImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER)
-	out.push_back( new ColladaLoader());
+    out.push_back( new ColladaLoader());
 #endif
 #if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER)
-	out.push_back( new TerragenImporter());
+    out.push_back( new TerragenImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER)
-	out.push_back( new CSMImporter());
+    out.push_back( new CSMImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_3D_IMPORTER)
-	out.push_back( new UnrealImporter());
+    out.push_back( new UnrealImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
-	out.push_back( new LWSImporter());
+    out.push_back( new LWSImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER)
-	out.push_back( new Ogre::OgreImporter());
+    out.push_back( new Ogre::OgreImporter());
+#endif
+#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER )
+    out.push_back( new OpenGEX::OpenGEXImporter() );
 #endif
 #if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER)
-	out.push_back( new MS3DImporter());
+    out.push_back( new MS3DImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_COB_IMPORTER)
-	out.push_back( new COBImporter());
+    out.push_back( new COBImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
-	out.push_back( new BlenderImporter());
+    out.push_back( new BlenderImporter());
 #endif
 #if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
-	out.push_back( new Q3BSPFileImporter() );
+    out.push_back( new Q3BSPFileImporter() );
 #endif
 #if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER)
-	out.push_back( new NDOImporter() );
+    out.push_back( new NDOImporter() );
 #endif
 #if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER)
-	out.push_back( new IFCImporter() );
+    out.push_back( new IFCImporter() );
 #endif
 #if ( !defined ASSIMP_BUILD_NO_XGL_IMPORTER )
-	out.push_back( new XGLImporter() );
+    out.push_back( new XGLImporter() );
 #endif
 #if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER )
-	out.push_back( new FBXImporter() );
+    out.push_back( new FBXImporter() );
 #endif
 #if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
-	out.push_back( new AssbinImporter() );
+    out.push_back( new AssbinImporter() );
 #endif
 
 #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
-	out.push_back( new C4DImporter() );
+    out.push_back( new C4DImporter() );
 #endif
 }
 
-}
+} // namespace Assimp

+ 1 - 1
code/ObjExporter.cpp

@@ -51,7 +51,7 @@ namespace Assimp	{
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
-void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	// invoke the exporter 
 	ObjExporter exporter(pFile, pScene);

+ 518 - 518
code/ObjFileImporter.cpp

@@ -48,16 +48,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjFileData.h"
 
 static const aiImporterDesc desc = {
-	"Wavefront Object Importer",
-	"",
-	"",
-	"surfaces not supported",
-	aiImporterFlags_SupportTextFlavour,
-	0,
-	0,
-	0,
-	0,
-	"obj"
+    "Wavefront Object Importer",
+    "",
+    "",
+    "surfaces not supported",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "obj"
 };
 
 static const unsigned int ObjMinSize = 16;
@@ -69,99 +69,99 @@ using namespace std;
 // ------------------------------------------------------------------------------------------------
 //	Default constructor
 ObjFileImporter::ObjFileImporter() :
-	m_Buffer(),	
-	m_pRootObject( NULL ),
-	m_strAbsPath( "" )
+    m_Buffer(),	
+    m_pRootObject( NULL ),
+    m_strAbsPath( "" )
 {
     DefaultIOSystem io;
-	m_strAbsPath = io.getOsSeparator();
+    m_strAbsPath = io.getOsSeparator();
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Destructor.
 ObjFileImporter::~ObjFileImporter()
 {
-	delete m_pRootObject;
-	m_pRootObject = NULL;
+    delete m_pRootObject;
+    m_pRootObject = NULL;
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Returns true, if file is an obj file.
 bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem*  pIOHandler , bool checkSig ) const
 {
-	if(!checkSig) //Check File Extension
-	{
-		return SimpleExtensionCheck(pFile,"obj");
-	}
-	else //Check file Header
-	{
-		static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
-		return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 );
-	}
+    if(!checkSig) //Check File Extension
+    {
+        return SimpleExtensionCheck(pFile,"obj");
+    }
+    else //Check file Header
+    {
+        static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
+        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 );
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 const aiImporterDesc* ObjFileImporter::GetInfo () const
 {
-	return &desc;
+    return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Obj-file import implementation
 void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
 {    
-	// Read file into memory
-	const std::string mode = "rb";
-	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
+    // Read file into memory
+    const std::string mode = "rb";
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
     if( !file.get() ) {
         throw DeadlyImportError( "Failed to open file " + pFile + "." );
     }
 
-	// Get the file-size and validate it, throwing an exception when fails
-	size_t fileSize = file->FileSize();
+    // Get the file-size and validate it, throwing an exception when fails
+    size_t fileSize = file->FileSize();
     if( fileSize < ObjMinSize ) {
-		throw DeadlyImportError( "OBJ-file is too small.");
+        throw DeadlyImportError( "OBJ-file is too small.");
+    }
+
+    // Allocate buffer and read file into it
+    TextFileToBuffer(file.get(),m_Buffer);
+
+    // Get the model name
+    std::string  strModelName;
+    std::string::size_type pos = pFile.find_last_of( "\\/" );
+    if ( pos != std::string::npos )	
+    {
+        strModelName = pFile.substr(pos+1, pFile.size() - pos - 1);
     }
+    else
+    {
+        strModelName = pFile;
+    }
+
+    // process all '\'
+    std::vector<char> ::iterator iter = m_Buffer.begin();
+    while (iter != m_Buffer.end())
+    {
+        if (*iter == '\\')
+        {
+            // remove '\'
+            iter = m_Buffer.erase(iter);
+            // remove next character
+            while (*iter == '\r' || *iter == '\n')
+                iter = m_Buffer.erase(iter);
+        }
+        else
+            ++iter;
+    }
+
+    // parse the file into a temporary representation
+    ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
+
+    // And create the proper return structures out of it
+    CreateDataFromImport(parser.GetModel(), pScene);
 
-	// Allocate buffer and read file into it
-	TextFileToBuffer(file.get(),m_Buffer);
-
-	// Get the model name
-	std::string  strModelName;
-	std::string::size_type pos = pFile.find_last_of( "\\/" );
-	if ( pos != std::string::npos )	
-	{
-		strModelName = pFile.substr(pos+1, pFile.size() - pos - 1);
-	}
-	else
-	{
-		strModelName = pFile;
-	}
-
-	// process all '\'
-	std::vector<char> ::iterator iter = m_Buffer.begin();
-	while (iter != m_Buffer.end())
-	{
-		if (*iter == '\\')
-		{
-			// remove '\'
-			iter = m_Buffer.erase(iter);
-			// remove next character
-			while (*iter == '\r' || *iter == '\n')
-				iter = m_Buffer.erase(iter);
-		}
-		else
-			++iter;
-	}
-
-	// parse the file into a temporary representation
-	ObjFileParser parser(m_Buffer, strModelName, pIOHandler);
-
-	// And create the proper return structures out of it
-	CreateDataFromImport(parser.GetModel(), pScene);
-
-	// Clean up allocated storage for the next import 
-	m_Buffer.clear();
+    // Clean up allocated storage for the next import 
+    m_Buffer.clear();
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -170,98 +170,98 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
     if( 0L == pModel ) {
         return;
     }
-		
-	// Create the root node of the scene
-	pScene->mRootNode = new aiNode;
-	if ( !pModel->m_ModelName.empty() )
-	{
-		// Set the name of the scene
-		pScene->mRootNode->mName.Set(pModel->m_ModelName);
-	}
-	else
-	{
-		// This is a fatal error, so break down the application
-		ai_assert(false);
-	} 
-
-	// Create nodes for the whole scene	
-	std::vector<aiMesh*> MeshArray;
-	for (size_t index = 0; index < pModel->m_Objects.size(); index++)
-	{
-		createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
-	}
-
-	// Create mesh pointer buffer for this scene
-	if (pScene->mNumMeshes > 0)
-	{
-		pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
-		for (size_t index =0; index < MeshArray.size(); index++)
-		{
-			pScene->mMeshes [ index ] = MeshArray[ index ];
-		}
-	}
-
-	// Create all materials
-	createMaterials( pModel, pScene );
+        
+    // Create the root node of the scene
+    pScene->mRootNode = new aiNode;
+    if ( !pModel->m_ModelName.empty() )
+    {
+        // Set the name of the scene
+        pScene->mRootNode->mName.Set(pModel->m_ModelName);
+    }
+    else
+    {
+        // This is a fatal error, so break down the application
+        ai_assert(false);
+    } 
+
+    // Create nodes for the whole scene	
+    std::vector<aiMesh*> MeshArray;
+    for (size_t index = 0; index < pModel->m_Objects.size(); index++)
+    {
+        createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
+    }
+
+    // Create mesh pointer buffer for this scene
+    if (pScene->mNumMeshes > 0)
+    {
+        pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
+        for (size_t index =0; index < MeshArray.size(); index++)
+        {
+            pScene->mMeshes [ index ] = MeshArray[ index ];
+        }
+    }
+
+    // Create all materials
+    createMaterials( pModel, pScene );
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Creates all nodes of the model
 aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pObject, 
-									 aiNode *pParent, aiScene* pScene, 
-									 std::vector<aiMesh*> &MeshArray )
+                                     aiNode *pParent, aiScene* pScene, 
+                                     std::vector<aiMesh*> &MeshArray )
 {
-	ai_assert( NULL != pModel );
+    ai_assert( NULL != pModel );
     if( NULL == pObject ) {
         return NULL;
     }
-	
-	// Store older mesh size to be able to computes mesh offsets for new mesh instances
-	const size_t oldMeshSize = MeshArray.size();
-	aiNode *pNode = new aiNode;
-
-	pNode->mName = pObject->m_strObjName;
-	
-	// If we have a parent node, store it
+    
+    // Store older mesh size to be able to computes mesh offsets for new mesh instances
+    const size_t oldMeshSize = MeshArray.size();
+    aiNode *pNode = new aiNode;
+
+    pNode->mName = pObject->m_strObjName;
+    
+    // If we have a parent node, store it
     if( pParent != NULL ) {
         appendChildToParentNode( pParent, pNode );
     }
 
-	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
-	{
-		unsigned int meshId = pObject->m_Meshes[ i ];
-		aiMesh *pMesh = createTopology( pModel, pObject, meshId );	
+    for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
+    {
+        unsigned int meshId = pObject->m_Meshes[ i ];
+        aiMesh *pMesh = createTopology( pModel, pObject, meshId );	
         if( pMesh && pMesh->mNumFaces > 0 ) {
-			MeshArray.push_back( pMesh );
-		}
-	}
-
-	// Create all nodes from the sub-objects stored in the current object
-	if ( !pObject->m_SubObjects.empty() )
-	{
-		size_t numChilds = pObject->m_SubObjects.size();
-		pNode->mNumChildren = static_cast<unsigned int>( numChilds );
-		pNode->mChildren = new aiNode*[ numChilds ];
-		pNode->mNumMeshes = 1;
-		pNode->mMeshes = new unsigned int[ 1 ];
-	}
-
-	// Set mesh instances into scene- and node-instances
-	const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
-	if ( meshSizeDiff > 0 )
-	{
-		pNode->mMeshes = new unsigned int[ meshSizeDiff ];
-		pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
-		size_t index = 0;
-		for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
-		{
-			pNode->mMeshes[ index ] = pScene->mNumMeshes;
-			pScene->mNumMeshes++;
-			index++;
-		}
-	}
-	
-	return pNode;
+            MeshArray.push_back( pMesh );
+        }
+    }
+
+    // Create all nodes from the sub-objects stored in the current object
+    if ( !pObject->m_SubObjects.empty() )
+    {
+        size_t numChilds = pObject->m_SubObjects.size();
+        pNode->mNumChildren = static_cast<unsigned int>( numChilds );
+        pNode->mChildren = new aiNode*[ numChilds ];
+        pNode->mNumMeshes = 1;
+        pNode->mMeshes = new unsigned int[ 1 ];
+    }
+
+    // Set mesh instances into scene- and node-instances
+    const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
+    if ( meshSizeDiff > 0 )
+    {
+        pNode->mMeshes = new unsigned int[ meshSizeDiff ];
+        pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
+        size_t index = 0;
+        for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
+        {
+            pNode->mMeshes[ index ] = pScene->mNumMeshes;
+            pScene->mNumMeshes++;
+            index++;
+        }
+    }
+    
+    return pNode;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -269,83 +269,83 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData, 
                                          unsigned int uiMeshIndex )
 {
-	// Checking preconditions
-	ai_assert( NULL != pModel );
+    // Checking preconditions
+    ai_assert( NULL != pModel );
     if( NULL == pData ) {
         return NULL;
     }
 
-	// Create faces
-	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
+    // Create faces
+    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
     if( !pObjMesh ) {
         return NULL;
     }
     ai_assert( NULL != pObjMesh );
     aiMesh* pMesh = new aiMesh;
-	for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
-	{
-		ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
+    for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
+    {
+        ObjFile::Face *const inp = pObjMesh->m_Faces[ index ];
         ai_assert( NULL != inp  );
 
-		if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
-			pMesh->mNumFaces += inp->m_pVertices->size() - 1;
-			pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
-		} else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
-			pMesh->mNumFaces += inp->m_pVertices->size();
-			pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
-		} else {
-			++pMesh->mNumFaces;
-			if (inp->m_pVertices->size() > 3) {
-				pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
-			} else {
-				pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
-			}
-		}
-	}
-
-	unsigned int uiIdxCount( 0u );
-	if ( pMesh->mNumFaces > 0 )
-	{
-		pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
-		if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
-		{
-			pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
-		}
-
-		unsigned int outIndex( 0 );
-
-		// Copy all data from all stored meshes
-		for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
-		{
-			ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
-			if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
-				for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
-					aiFace& f = pMesh->mFaces[ outIndex++ ];
-					uiIdxCount += f.mNumIndices = 2;
-					f.mIndices = new unsigned int[2];
-				}
-				continue;
-			}
-			else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
-				for(size_t i = 0; i < inp->m_pVertices->size(); ++i) {
-					aiFace& f = pMesh->mFaces[ outIndex++ ];
-					uiIdxCount += f.mNumIndices = 1;
-					f.mIndices = new unsigned int[1];
-				}
-				continue;
-			}
-
-			aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
-			const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size();
-			uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
-			if (pFace->mNumIndices > 0) {
-				pFace->mIndices = new unsigned int[ uiNumIndices ];			
-			}
-		}
-	}
-
-	// Create mesh vertices
-	createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount);
+        if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+            pMesh->mNumFaces += inp->m_pVertices->size() - 1;
+            pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
+        } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+            pMesh->mNumFaces += inp->m_pVertices->size();
+            pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
+        } else {
+            ++pMesh->mNumFaces;
+            if (inp->m_pVertices->size() > 3) {
+                pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
+            } else {
+                pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+            }
+        }
+    }
+
+    unsigned int uiIdxCount( 0u );
+    if ( pMesh->mNumFaces > 0 )
+    {
+        pMesh->mFaces = new aiFace[ pMesh->mNumFaces ];
+        if ( pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial )
+        {
+            pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
+        }
+
+        unsigned int outIndex( 0 );
+
+        // Copy all data from all stored meshes
+        for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++)
+        {
+            ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
+            if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+                for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
+                    aiFace& f = pMesh->mFaces[ outIndex++ ];
+                    uiIdxCount += f.mNumIndices = 2;
+                    f.mIndices = new unsigned int[2];
+                }
+                continue;
+            }
+            else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+                for(size_t i = 0; i < inp->m_pVertices->size(); ++i) {
+                    aiFace& f = pMesh->mFaces[ outIndex++ ];
+                    uiIdxCount += f.mNumIndices = 1;
+                    f.mIndices = new unsigned int[1];
+                }
+                continue;
+            }
+
+            aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
+            const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size();
+            uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
+            if (pFace->mNumIndices > 0) {
+                pFace->mIndices = new unsigned int[ uiNumIndices ];			
+            }
+        }
+    }
+
+    // Create mesh vertices
+    createVertexArray(pModel, pData, uiMeshIndex, pMesh, uiIdxCount);
 
     return pMesh;
 }
@@ -353,335 +353,335 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
 // ------------------------------------------------------------------------------------------------
 //	Creates a vertex array
 void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, 
-										const ObjFile::Object* pCurrentObject, 
-										unsigned int uiMeshIndex,
-										aiMesh* pMesh,
-										unsigned int uiIdxCount)
+                                        const ObjFile::Object* pCurrentObject, 
+                                        unsigned int uiMeshIndex,
+                                        aiMesh* pMesh,
+                                        unsigned int uiIdxCount)
 {
-	// Checking preconditions
-	ai_assert( NULL != pCurrentObject );
-	
-	// Break, if no faces are stored in object
-	if ( pCurrentObject->m_Meshes.empty() )
-		return;
-
-	// Get current mesh
-	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
-	if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1)
-		return;
-
-	// Copy vertices of this mesh instance
-	pMesh->mNumVertices = uiIdxCount;
-	pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
-	
-	// Allocate buffer for normal vectors
-	if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals )
-		pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
-	
-	// Allocate buffer for texture coordinates
-	if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] )
-	{
-		pMesh->mNumUVComponents[ 0 ] = 2;
-		pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ];
-	}
-	
-	// Copy vertices, normals and textures into aiMesh instance
-	unsigned int newIndex = 0, outIndex = 0;
-	for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ )
-	{
-		// Get source face
-		ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ]; 
-
-		// Copy all index arrays
-		for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ )
-		{
-			const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex );
-			if ( vertex >= pModel->m_Vertices.size() ) 
-				throw DeadlyImportError( "OBJ: vertex index out of range" );
-			
-			pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
-			
-			// Copy all normals 
-			if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size())
-			{
-				const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex );
-				if ( normal >= pModel->m_Normals.size() )
-					throw DeadlyImportError("OBJ: vertex normal index out of range");
-
-				pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ];
-			}
-			
-			// Copy all texture coordinates
-			if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size())
-			{
-				const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex );
-				ai_assert( tex < pModel->m_TextureCoord.size() );
-					
-				if ( tex >= pModel->m_TextureCoord.size() )
-					throw DeadlyImportError("OBJ: texture coordinate index out of range");
-
-				const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ];
+    // Checking preconditions
+    ai_assert( NULL != pCurrentObject );
+    
+    // Break, if no faces are stored in object
+    if ( pCurrentObject->m_Meshes.empty() )
+        return;
+
+    // Get current mesh
+    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
+    if ( NULL == pObjMesh || pObjMesh->m_uiNumIndices < 1)
+        return;
+
+    // Copy vertices of this mesh instance
+    pMesh->mNumVertices = uiIdxCount;
+    pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
+    
+    // Allocate buffer for normal vectors
+    if ( !pModel->m_Normals.empty() && pObjMesh->m_hasNormals )
+        pMesh->mNormals = new aiVector3D[ pMesh->mNumVertices ];
+    
+    // Allocate buffer for texture coordinates
+    if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] )
+    {
+        pMesh->mNumUVComponents[ 0 ] = 2;
+        pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ];
+    }
+    
+    // Copy vertices, normals and textures into aiMesh instance
+    unsigned int newIndex = 0, outIndex = 0;
+    for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ )
+    {
+        // Get source face
+        ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ]; 
+
+        // Copy all index arrays
+        for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ )
+        {
+            const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex );
+            if ( vertex >= pModel->m_Vertices.size() ) 
+                throw DeadlyImportError( "OBJ: vertex index out of range" );
+            
+            pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
+            
+            // Copy all normals 
+            if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size())
+            {
+                const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex );
+                if ( normal >= pModel->m_Normals.size() )
+                    throw DeadlyImportError("OBJ: vertex normal index out of range");
+
+                pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ];
+            }
+            
+            // Copy all texture coordinates
+            if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size())
+            {
+                const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex );
+                ai_assert( tex < pModel->m_TextureCoord.size() );
+                    
+                if ( tex >= pModel->m_TextureCoord.size() )
+                    throw DeadlyImportError("OBJ: texture coordinate index out of range");
+
+                const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ];
                 pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
-			}
-
-			ai_assert( pMesh->mNumVertices > newIndex );
-
-			// Get destination face
-			aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
-
-			const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 ); 
-			if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) 
-			{
-				pDestFace->mIndices[ outVertexIndex ] = newIndex;
-				outVertexIndex++;
-			}
-
-			if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) 
-			{
-				outIndex++;
-				outVertexIndex = 0;
-			}
-			else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) 
-			{
-				outVertexIndex = 0;
-
-				if(!last) 
-					outIndex++;
-
-				if (vertexIndex) {
-					if(!last) {
-						pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
-						if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) {
-							pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
-						}
-						if ( !pModel->m_TextureCoord.empty() ) {
-							for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) {
-								pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ];
-							}
-						}
-						++newIndex;
-					}
-
-					pDestFace[-1].mIndices[1] = newIndex;
-				}
-			}
-			else if (last) {
-				outIndex++;
-			}
-			++newIndex;
-		}
-	}	
+            }
+
+            ai_assert( pMesh->mNumVertices > newIndex );
+
+            // Get destination face
+            aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
+
+            const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 ); 
+            if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) 
+            {
+                pDestFace->mIndices[ outVertexIndex ] = newIndex;
+                outVertexIndex++;
+            }
+
+            if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) 
+            {
+                outIndex++;
+                outVertexIndex = 0;
+            }
+            else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) 
+            {
+                outVertexIndex = 0;
+
+                if(!last) 
+                    outIndex++;
+
+                if (vertexIndex) {
+                    if(!last) {
+                        pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
+                        if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) {
+                            pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
+                        }
+                        if ( !pModel->m_TextureCoord.empty() ) {
+                            for ( size_t i=0; i < pMesh->GetNumUVChannels(); i++ ) {
+                                pMesh->mTextureCoords[ i ][ newIndex+1 ] = pMesh->mTextureCoords[ i ][ newIndex ];
+                            }
+                        }
+                        ++newIndex;
+                    }
+
+                    pDestFace[-1].mIndices[1] = newIndex;
+                }
+            }
+            else if (last) {
+                outIndex++;
+            }
+            ++newIndex;
+        }
+    }	
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Counts all stored meshes 
 void ObjFileImporter::countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes)
 {
-	iNumMeshes = 0;
-	if ( rObjects.empty() )	
-		return;
-
-	iNumMeshes += static_cast<unsigned int>( rObjects.size() );
-	for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
-		it != rObjects.end(); 
-		++it)
-	{
-		if (!(*it)->m_SubObjects.empty())
-		{
-			countObjects((*it)->m_SubObjects, iNumMeshes);
-		}
-	}
+    iNumMeshes = 0;
+    if ( rObjects.empty() )	
+        return;
+
+    iNumMeshes += static_cast<unsigned int>( rObjects.size() );
+    for (std::vector<ObjFile::Object*>::const_iterator it = rObjects.begin();
+        it != rObjects.end(); 
+        ++it)
+    {
+        if (!(*it)->m_SubObjects.empty())
+        {
+            countObjects((*it)->m_SubObjects, iNumMeshes);
+        }
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 //	 Add clamp mode property to material if necessary 
 void ObjFileImporter::addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode)
 {
-	ai_assert( NULL != mat);
-	mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0));
-	mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0));
+    ai_assert( NULL != mat);
+    mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, 0));
+    mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, 0));
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Creates the material 
 void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pScene )
 {
-	ai_assert( NULL != pScene );
-	if ( NULL == pScene )
-		return;
-
-	const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size();
-	pScene->mNumMaterials = 0;
-	if ( pModel->m_MaterialLib.empty() ) {
-		DefaultLogger::get()->debug("OBJ: no materials specified");
-		return;
-	}
-	
-	pScene->mMaterials = new aiMaterial*[ numMaterials ];
-	for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ )
-	{		
-		// Store material name
-		std::map<std::string, ObjFile::Material*>::const_iterator it;
-		it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
-		
-		// No material found, use the default material
-		if ( pModel->m_MaterialMap.end() == it )
-			continue;
-
-		aiMaterial* mat = new aiMaterial;
-		ObjFile::Material *pCurrentMaterial = (*it).second;
-		mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
-
-		// convert illumination model
-		int sm = 0;
-		switch (pCurrentMaterial->illumination_model) 
-		{
-		case 0:
-			sm = aiShadingMode_NoShading;
-			break;
-		case 1:
-			sm = aiShadingMode_Gouraud;
-			break;
-		case 2:
-			sm = aiShadingMode_Phong;
-			break;
-		default:
-			sm = aiShadingMode_Gouraud;
-			DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)");
-		}
-	
-		mat->AddProperty<int>( &sm, 1, AI_MATKEY_SHADING_MODEL);
-
-		// multiplying the specular exponent with 2 seems to yield better results
-		pCurrentMaterial->shineness *= 4.f;
-
-		// Adding material colors
-		mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
-		mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
-		mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
-		mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE );
-		mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
-		mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
-
-		// Adding refraction index
-		mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI );
-
-		// Adding textures
-		if ( 0 != pCurrentMaterial->texture.length ) 
-		{
-			mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureAmbient.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureEmissive.length )
-			mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
-
-		if ( 0 != pCurrentMaterial->textureSpecular.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureBump.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureNormal.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureDisp.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureOpacity.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
-			}
-		}
-
-		if ( 0 != pCurrentMaterial->textureSpecularity.length )
-		{
-			mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
-			if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType])
-			{
-				addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
-			}
-		}
-		
-		// Store material property info in material array in scene
-		pScene->mMaterials[ pScene->mNumMaterials ] = mat;
-		pScene->mNumMaterials++;
-	}
-	
-	// Test number of created materials.
-	ai_assert( pScene->mNumMaterials == numMaterials );
+    ai_assert( NULL != pScene );
+    if ( NULL == pScene )
+        return;
+
+    const unsigned int numMaterials = (unsigned int) pModel->m_MaterialLib.size();
+    pScene->mNumMaterials = 0;
+    if ( pModel->m_MaterialLib.empty() ) {
+        DefaultLogger::get()->debug("OBJ: no materials specified");
+        return;
+    }
+    
+    pScene->mMaterials = new aiMaterial*[ numMaterials ];
+    for ( unsigned int matIndex = 0; matIndex < numMaterials; matIndex++ )
+    {		
+        // Store material name
+        std::map<std::string, ObjFile::Material*>::const_iterator it;
+        it = pModel->m_MaterialMap.find( pModel->m_MaterialLib[ matIndex ] );
+        
+        // No material found, use the default material
+        if ( pModel->m_MaterialMap.end() == it )
+            continue;
+
+        aiMaterial* mat = new aiMaterial;
+        ObjFile::Material *pCurrentMaterial = (*it).second;
+        mat->AddProperty( &pCurrentMaterial->MaterialName, AI_MATKEY_NAME );
+
+        // convert illumination model
+        int sm = 0;
+        switch (pCurrentMaterial->illumination_model) 
+        {
+        case 0:
+            sm = aiShadingMode_NoShading;
+            break;
+        case 1:
+            sm = aiShadingMode_Gouraud;
+            break;
+        case 2:
+            sm = aiShadingMode_Phong;
+            break;
+        default:
+            sm = aiShadingMode_Gouraud;
+            DefaultLogger::get()->error("OBJ: unexpected illumination model (0-2 recognized)");
+        }
+    
+        mat->AddProperty<int>( &sm, 1, AI_MATKEY_SHADING_MODEL);
+
+        // multiplying the specular exponent with 2 seems to yield better results
+        pCurrentMaterial->shineness *= 4.f;
+
+        // Adding material colors
+        mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
+        mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+        mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
+        mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE );
+        mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
+        mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
+
+        // Adding refraction index
+        mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI );
+
+        // Adding textures
+        if ( 0 != pCurrentMaterial->texture.length ) 
+        {
+            mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureAmbient.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureEmissive.length )
+            mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
+
+        if ( 0 != pCurrentMaterial->textureSpecular.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureBump.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureNormal.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureDisp.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureOpacity.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
+            }
+        }
+
+        if ( 0 != pCurrentMaterial->textureSpecularity.length )
+        {
+            mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
+            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType])
+            {
+                addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
+            }
+        }
+        
+        // Store material property info in material array in scene
+        pScene->mMaterials[ pScene->mNumMaterials ] = mat;
+        pScene->mNumMaterials++;
+    }
+    
+    // Test number of created materials.
+    ai_assert( pScene->mNumMaterials == numMaterials );
 }
 
 // ------------------------------------------------------------------------------------------------
 //	Appends this node to the parent node
 void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
 {
-	// Checking preconditions
-	ai_assert( NULL != pParent );
-	ai_assert( NULL != pChild );
-
-	// Assign parent to child
-	pChild->mParent = pParent;
-	
-	// If already children was assigned to the parent node, store them in a 
-	std::vector<aiNode*> temp;
-	if (pParent->mChildren != NULL)
-	{
-		ai_assert( 0 != pParent->mNumChildren );
-		for (size_t index = 0; index < pParent->mNumChildren; index++)
-		{
-			temp.push_back(pParent->mChildren [ index ] );
-		}
-		delete [] pParent->mChildren;
-	}
-	
-	// Copy node instances into parent node
-	pParent->mNumChildren++;
-	pParent->mChildren = new aiNode*[ pParent->mNumChildren ];
-	for (size_t index = 0; index < pParent->mNumChildren-1; index++)
-	{
-		pParent->mChildren[ index ] = temp [ index ];
-	}
-	pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
+    // Checking preconditions
+    ai_assert( NULL != pParent );
+    ai_assert( NULL != pChild );
+
+    // Assign parent to child
+    pChild->mParent = pParent;
+    
+    // If already children was assigned to the parent node, store them in a 
+    std::vector<aiNode*> temp;
+    if (pParent->mChildren != NULL)
+    {
+        ai_assert( 0 != pParent->mNumChildren );
+        for (size_t index = 0; index < pParent->mNumChildren; index++)
+        {
+            temp.push_back(pParent->mChildren [ index ] );
+        }
+        delete [] pParent->mChildren;
+    }
+    
+    // Copy node instances into parent node
+    pParent->mNumChildren++;
+    pParent->mChildren = new aiNode*[ pParent->mNumChildren ];
+    for (size_t index = 0; index < pParent->mNumChildren-1; index++)
+    {
+        pParent->mChildren[ index ] = temp [ index ];
+    }
+    pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 37 - 37
code/ObjFileImporter.h

@@ -64,57 +64,57 @@ struct Model;
 class ObjFileImporter : public BaseImporter
 {	
 public:
-	///	\brief	Default constructor
-	ObjFileImporter();
+    ///	\brief	Default constructor
+    ObjFileImporter();
 
-	///	\brief	Destructor
-	~ObjFileImporter();
+    ///	\brief	Destructor
+    ~ObjFileImporter();
 
 public:
-	/// \brief	Returns whether the class can handle the format of the given file. 
-	/// \remark	See BaseImporter::CanRead() for details.
-	bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
+    /// \brief	Returns whether the class can handle the format of the given file. 
+    /// \remark	See BaseImporter::CanRead() for details.
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
 private:
 
-	//! \brief	Appends the supported extension.
-	const aiImporterDesc* GetInfo () const;
+    //! \brief	Appends the supported extension.
+    const aiImporterDesc* GetInfo () const;
 
-	//!	\brief	File import implementation.
-	void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
-	
-	//!	\brief	Create the data from imported content.
-	void CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene);
-	
-	//!	\brief	Creates all nodes stored in imported content.
-	aiNode *createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pData,
-		aiNode *pParent, aiScene* pScene, std::vector<aiMesh*> &MeshArray);
+    //!	\brief	File import implementation.
+    void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+    
+    //!	\brief	Create the data from imported content.
+    void CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene);
+    
+    //!	\brief	Creates all nodes stored in imported content.
+    aiNode *createNodes(const ObjFile::Model* pModel, const ObjFile::Object* pData,
+        aiNode *pParent, aiScene* pScene, std::vector<aiMesh*> &MeshArray);
 
-	//!	\brief	Creates topology data like faces and meshes for the geometry.
+    //!	\brief	Creates topology data like faces and meshes for the geometry.
     aiMesh *createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData,
-		unsigned int uiMeshIndex );	
-	
-	//!	\brief	Creates vertices from model.
-	void createVertexArray(const ObjFile::Model* pModel, const ObjFile::Object* pCurrentObject,
-		unsigned int uiMeshIndex, aiMesh* pMesh,unsigned int uiIdxCount);
+        unsigned int uiMeshIndex );	
+    
+    //!	\brief	Creates vertices from model.
+    void createVertexArray(const ObjFile::Model* pModel, const ObjFile::Object* pCurrentObject,
+        unsigned int uiMeshIndex, aiMesh* pMesh,unsigned int uiIdxCount);
 
-	//!	\brief	Object counter helper method.
-	void countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes);
+    //!	\brief	Object counter helper method.
+    void countObjects(const std::vector<ObjFile::Object*> &rObjects, int &iNumMeshes);
 
-	//!	\brief	Material creation.
-	void createMaterials(const ObjFile::Model* pModel, aiScene* pScene);
-	void addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode = 1);
+    //!	\brief	Material creation.
+    void createMaterials(const ObjFile::Model* pModel, aiScene* pScene);
+    void addTextureMappingModeProperty(aiMaterial* mat, aiTextureType type, int clampMode = 1);
 
-	//!	\brief	Appends a child node to a parent node and updates the data structures.
-	void appendChildToParentNode(aiNode *pParent, aiNode *pChild);
+    //!	\brief	Appends a child node to a parent node and updates the data structures.
+    void appendChildToParentNode(aiNode *pParent, aiNode *pChild);
 
 private:
-	//!	Data buffer
-	std::vector<char> m_Buffer;
-	//!	Pointer to root object instance
-	ObjFile::Object *m_pRootObject;
-	//!	Absolute pathname of model in file system
-	std::string m_strAbsPath;
+    //!	Data buffer
+    std::vector<char> m_Buffer;
+    //!	Pointer to root object instance
+    ObjFile::Object *m_pRootObject;
+    //!	Absolute pathname of model in file system
+    std::string m_strAbsPath;
 };
 
 // ------------------------------------------------------------------------------------------------

+ 486 - 486
code/ObjFileParser.cpp

@@ -57,177 +57,177 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
 // -------------------------------------------------------------------
 //	Constructor with loaded data and directories.
 ObjFileParser::ObjFileParser(std::vector<char> &Data,const std::string &strModelName, IOSystem *io ) :
-	m_DataIt(Data.begin()),
-	m_DataItEnd(Data.end()),
-	m_pModel(NULL),
-	m_uiLine(0),
-	m_pIO( io )
+    m_DataIt(Data.begin()),
+    m_DataItEnd(Data.end()),
+    m_pModel(NULL),
+    m_uiLine(0),
+    m_pIO( io )
 {
-	std::fill_n(m_buffer,BUFFERSIZE,0);
+    std::fill_n(m_buffer,BUFFERSIZE,0);
 
-	// Create the model instance to store all the data
-	m_pModel = new ObjFile::Model();
-	m_pModel->m_ModelName = strModelName;
-	
+    // Create the model instance to store all the data
+    m_pModel = new ObjFile::Model();
+    m_pModel->m_ModelName = strModelName;
+    
     // create default material and store it
-	m_pModel->m_pDefaultMaterial = new ObjFile::Material();
-	m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL );
+    m_pModel->m_pDefaultMaterial = new ObjFile::Material();
+    m_pModel->m_pDefaultMaterial->MaterialName.Set( DEFAULT_MATERIAL );
     m_pModel->m_MaterialLib.push_back( DEFAULT_MATERIAL );
-	m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
-	
-	// Start parsing the file
-	parseFile();
+    m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
+    
+    // Start parsing the file
+    parseFile();
 }
 
 // -------------------------------------------------------------------
 //	Destructor
 ObjFileParser::~ObjFileParser()
 {
-	delete m_pModel;
-	m_pModel = NULL;
+    delete m_pModel;
+    m_pModel = NULL;
 }
 
 // -------------------------------------------------------------------
 //	Returns a pointer to the model instance.
 ObjFile::Model *ObjFileParser::GetModel() const
 {
-	return m_pModel;
+    return m_pModel;
 }
 
 // -------------------------------------------------------------------
 //	File parsing method.
 void ObjFileParser::parseFile()
 {
-	if (m_DataIt == m_DataItEnd)
-		return;
-
-	while (m_DataIt != m_DataItEnd)
-	{
-		switch (*m_DataIt)
-		{
-		case 'v': // Parse a vertex texture coordinate
-			{
-				++m_DataIt;
-				if (*m_DataIt == ' ' || *m_DataIt == '\t') {
-					// read in vertex definition
-					getVector3(m_pModel->m_Vertices);
-				} else if (*m_DataIt == 't') {
-					// read in texture coordinate ( 2D or 3D )
+    if (m_DataIt == m_DataItEnd)
+        return;
+
+    while (m_DataIt != m_DataItEnd)
+    {
+        switch (*m_DataIt)
+        {
+        case 'v': // Parse a vertex texture coordinate
+            {
+                ++m_DataIt;
+                if (*m_DataIt == ' ' || *m_DataIt == '\t') {
+                    // read in vertex definition
+                    getVector3(m_pModel->m_Vertices);
+                } else if (*m_DataIt == 't') {
+                    // read in texture coordinate ( 2D or 3D )
                                         ++m_DataIt;
                                         getVector( m_pModel->m_TextureCoord );
-				} else if (*m_DataIt == 'n') {
-					// Read in normal vector definition
-					++m_DataIt;
-					getVector3( m_pModel->m_Normals );
-				}
-			}
-			break;
-
-		case 'p': // Parse a face, line or point statement
-		case 'l':
-		case 'f':
-			{
-				getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l' 
-					? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
-			}
-			break;
-
-		case '#': // Parse a comment
-			{
-				getComment();
-			}
-			break;
-
-		case 'u': // Parse a material desc. setter
-			{
-				getMaterialDesc();
-			}
-			break;
-
-		case 'm': // Parse a material library or merging group ('mg')
-			{
-				if (*(m_DataIt + 1) == 'g')
-					getGroupNumberAndResolution();
-				else
-					getMaterialLib();
-			}
-			break;
-
-		case 'g': // Parse group name
-			{
-				getGroupName();
-			}
-			break;
-
-		case 's': // Parse group number
-			{
-				getGroupNumber();
-			}
-			break;
-
-		case 'o': // Parse object name
-			{
-				getObjectName();
-			}
-			break;
-		
-		default:
-			{
-				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-			}
-			break;
-		}
-	}
+                } else if (*m_DataIt == 'n') {
+                    // Read in normal vector definition
+                    ++m_DataIt;
+                    getVector3( m_pModel->m_Normals );
+                }
+            }
+            break;
+
+        case 'p': // Parse a face, line or point statement
+        case 'l':
+        case 'f':
+            {
+                getFace(*m_DataIt == 'f' ? aiPrimitiveType_POLYGON : (*m_DataIt == 'l' 
+                    ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
+            }
+            break;
+
+        case '#': // Parse a comment
+            {
+                getComment();
+            }
+            break;
+
+        case 'u': // Parse a material desc. setter
+            {
+                getMaterialDesc();
+            }
+            break;
+
+        case 'm': // Parse a material library or merging group ('mg')
+            {
+                if (*(m_DataIt + 1) == 'g')
+                    getGroupNumberAndResolution();
+                else
+                    getMaterialLib();
+            }
+            break;
+
+        case 'g': // Parse group name
+            {
+                getGroupName();
+            }
+            break;
+
+        case 's': // Parse group number
+            {
+                getGroupNumber();
+            }
+            break;
+
+        case 'o': // Parse object name
+            {
+                getObjectName();
+            }
+            break;
+        
+        default:
+            {
+                m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+            }
+            break;
+        }
+    }
 }
 
 // -------------------------------------------------------------------
 //	Copy the next word in a temporary buffer
 void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
 {
-	size_t index = 0;
-	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
+    size_t index = 0;
+    m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
     while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
-		pBuffer[index] = *m_DataIt;
-		index++;
+        pBuffer[index] = *m_DataIt;
+        index++;
         if( index == length - 1 ) {
             break;
         }
-		++m_DataIt;
-	}
+        ++m_DataIt;
+    }
 
-	ai_assert(index < length);
-	pBuffer[index] = '\0';
+    ai_assert(index < length);
+    pBuffer[index] = '\0';
 }
 
 // -------------------------------------------------------------------
 // Copy the next line into a temporary buffer
 void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
 {
-	size_t index = 0u;
-
-	// some OBJ files have line continuations using \ (such as in C++ et al)
-	bool continuation = false;
-	for (;m_DataIt != m_DataItEnd && index < length-1; ++m_DataIt) 
-	{
-		const char c = *m_DataIt;
-		if (c == '\\') {
-			continuation = true;
-			continue;
-		}
-		
-		if (c == '\n' || c == '\r') {
-			if(continuation) {
-				pBuffer[ index++ ] = ' ';
-				continue;
-			}
-			break;
-		}
-
-		continuation = false;
-		pBuffer[ index++ ] = c;
-	}
-	ai_assert(index < length);
-	pBuffer[ index ] = '\0';
+    size_t index = 0u;
+
+    // some OBJ files have line continuations using \ (such as in C++ et al)
+    bool continuation = false;
+    for (;m_DataIt != m_DataItEnd && index < length-1; ++m_DataIt) 
+    {
+        const char c = *m_DataIt;
+        if (c == '\\') {
+            continuation = true;
+            continue;
+        }
+        
+        if (c == '\n' || c == '\r') {
+            if(continuation) {
+                pBuffer[ index++ ] = ' ';
+                continue;
+            }
+            break;
+        }
+
+        continuation = false;
+        pBuffer[ index++ ] = c;
+    }
+    ai_assert(index < length);
+    pBuffer[ index ] = '\0';
 }
 
 // -------------------------------------------------------------------
@@ -268,391 +268,391 @@ void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
 // -------------------------------------------------------------------
 //	Get values for a new 3D vector instance
 void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
-	float x, y, z;
-	copyNextWord(m_buffer, BUFFERSIZE);
-	x = (float) fast_atof(m_buffer);	
-	
-	copyNextWord(m_buffer, BUFFERSIZE);
-	y = (float) fast_atof(m_buffer);
+    float x, y, z;
+    copyNextWord(m_buffer, BUFFERSIZE);
+    x = (float) fast_atof(m_buffer);	
+    
+    copyNextWord(m_buffer, BUFFERSIZE);
+    y = (float) fast_atof(m_buffer);
 
     copyNextWord( m_buffer, BUFFERSIZE );
     z = ( float ) fast_atof( m_buffer );
 
-	point3d_array.push_back( aiVector3D( x, y, z ) );
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    point3d_array.push_back( aiVector3D( x, y, z ) );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Get values for a new 2D vector instance
 void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
-	float x, y;
-	copyNextWord(m_buffer, BUFFERSIZE);
-	x = (float) fast_atof(m_buffer);	
-	
-	copyNextWord(m_buffer, BUFFERSIZE);
-	y = (float) fast_atof(m_buffer);
+    float x, y;
+    copyNextWord(m_buffer, BUFFERSIZE);
+    x = (float) fast_atof(m_buffer);	
+    
+    copyNextWord(m_buffer, BUFFERSIZE);
+    y = (float) fast_atof(m_buffer);
 
-	point2d_array.push_back(aiVector2D(x, y));
+    point2d_array.push_back(aiVector2D(x, y));
 
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Get values for a new face instance
 void ObjFileParser::getFace(aiPrimitiveType type)
 {
-	copyNextLine(m_buffer, BUFFERSIZE);
-	if (m_DataIt == m_DataItEnd)
-		return;
-
-	char *pPtr = m_buffer;
-	char *pEnd = &pPtr[BUFFERSIZE];
-	pPtr = getNextToken<char*>(pPtr, pEnd);
-	if (pPtr == pEnd || *pPtr == '\0')
-		return;
-
-	std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
-	std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
-	std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
-	bool hasNormal = false;
-
-	const int vSize = m_pModel->m_Vertices.size();
-	const int vtSize = m_pModel->m_TextureCoord.size();
-	const int vnSize = m_pModel->m_Normals.size();
-
-	const bool vt = (!m_pModel->m_TextureCoord.empty());
-	const bool vn = (!m_pModel->m_Normals.empty());
-	int iStep = 0, iPos = 0;
-	while (pPtr != pEnd)
-	{
-		iStep = 1;
-
-		if (IsLineEnd(*pPtr))
-			break;
-
-		if (*pPtr=='/' )
-		{
-			if (type == aiPrimitiveType_POINT) {
-				DefaultLogger::get()->error("Obj: Separator unexpected in point statement");
-			}
-			if (iPos == 0)
-			{
-				//if there are no texture coordinates in the file, but normals
-				if (!vt && vn) {
-					iPos = 1;
-					iStep++;
-				}
-			}
-			iPos++;
-		}
+    copyNextLine(m_buffer, BUFFERSIZE);
+    if (m_DataIt == m_DataItEnd)
+        return;
+
+    char *pPtr = m_buffer;
+    char *pEnd = &pPtr[BUFFERSIZE];
+    pPtr = getNextToken<char*>(pPtr, pEnd);
+    if (pPtr == pEnd || *pPtr == '\0')
+        return;
+
+    std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
+    std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
+    std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
+    bool hasNormal = false;
+
+    const int vSize = m_pModel->m_Vertices.size();
+    const int vtSize = m_pModel->m_TextureCoord.size();
+    const int vnSize = m_pModel->m_Normals.size();
+
+    const bool vt = (!m_pModel->m_TextureCoord.empty());
+    const bool vn = (!m_pModel->m_Normals.empty());
+    int iStep = 0, iPos = 0;
+    while (pPtr != pEnd)
+    {
+        iStep = 1;
+
+        if (IsLineEnd(*pPtr))
+            break;
+
+        if (*pPtr=='/' )
+        {
+            if (type == aiPrimitiveType_POINT) {
+                DefaultLogger::get()->error("Obj: Separator unexpected in point statement");
+            }
+            if (iPos == 0)
+            {
+                //if there are no texture coordinates in the file, but normals
+                if (!vt && vn) {
+                    iPos = 1;
+                    iStep++;
+                }
+            }
+            iPos++;
+        }
         else if( IsSpaceOrNewLine( *pPtr ) )
-		{
-			iPos = 0;
-		}
-		else 
-		{
-			//OBJ USES 1 Base ARRAYS!!!!
-			const int iVal = atoi( pPtr );
-
-			// increment iStep position based off of the sign and # of digits
-			int tmp = iVal;
-			if (iVal < 0)
-			    ++iStep;
-			while ( ( tmp = tmp / 10 )!=0 )
-				++iStep;
-
-			if ( iVal > 0 )
-			{
-				// Store parsed index
-				if ( 0 == iPos )
-				{
-					pIndices->push_back( iVal-1 );
-				}
-				else if ( 1 == iPos )
-				{	
-					pTexID->push_back( iVal-1 );
-				}
-				else if ( 2 == iPos )
-				{
-					pNormalID->push_back( iVal-1 );
-					hasNormal = true;
-				}
-				else
-				{
-					reportErrorTokenInFace();
-				}
-			}
-			else if ( iVal < 0 )
-			{
-				// Store relatively index
-				if ( 0 == iPos )
-				{
-					pIndices->push_back( vSize + iVal );
-				}
-				else if ( 1 == iPos )
-				{
-					pTexID->push_back( vtSize + iVal );
-				}
-				else if ( 2 == iPos )
-				{
-					pNormalID->push_back( vnSize + iVal );
-					hasNormal = true;
-				}
-				else
-				{
-					reportErrorTokenInFace();
-				}
-			}
-		}
-		pPtr += iStep;
-	}
-
-	if ( pIndices->empty() ) 
-	{
-		DefaultLogger::get()->error("Obj: Ignoring empty face");
-		m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-		return;
-	}
-
-	ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type );
-	
-	// Set active material, if one set
-	if (NULL != m_pModel->m_pCurrentMaterial) 
-		face->m_pMaterial = m_pModel->m_pCurrentMaterial;
-	else 
-		face->m_pMaterial = m_pModel->m_pDefaultMaterial;
-
-	// Create a default object, if nothing is there
-	if ( NULL == m_pModel->m_pCurrent )
-		createObject( "defaultobject" );
-	
-	// Assign face to mesh
-	if ( NULL == m_pModel->m_pCurrentMesh )
-	{
-		createMesh();
-	}
-	
-	// Store the face
-	m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
-	m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
-	m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size(); 
-	if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) 
-	{
-		m_pModel->m_pCurrentMesh->m_hasNormals = true;
-	}
-	// Skip the rest of the line
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+        {
+            iPos = 0;
+        }
+        else 
+        {
+            //OBJ USES 1 Base ARRAYS!!!!
+            const int iVal = atoi( pPtr );
+
+            // increment iStep position based off of the sign and # of digits
+            int tmp = iVal;
+            if (iVal < 0)
+                ++iStep;
+            while ( ( tmp = tmp / 10 )!=0 )
+                ++iStep;
+
+            if ( iVal > 0 )
+            {
+                // Store parsed index
+                if ( 0 == iPos )
+                {
+                    pIndices->push_back( iVal-1 );
+                }
+                else if ( 1 == iPos )
+                {	
+                    pTexID->push_back( iVal-1 );
+                }
+                else if ( 2 == iPos )
+                {
+                    pNormalID->push_back( iVal-1 );
+                    hasNormal = true;
+                }
+                else
+                {
+                    reportErrorTokenInFace();
+                }
+            }
+            else if ( iVal < 0 )
+            {
+                // Store relatively index
+                if ( 0 == iPos )
+                {
+                    pIndices->push_back( vSize + iVal );
+                }
+                else if ( 1 == iPos )
+                {
+                    pTexID->push_back( vtSize + iVal );
+                }
+                else if ( 2 == iPos )
+                {
+                    pNormalID->push_back( vnSize + iVal );
+                    hasNormal = true;
+                }
+                else
+                {
+                    reportErrorTokenInFace();
+                }
+            }
+        }
+        pPtr += iStep;
+    }
+
+    if ( pIndices->empty() ) 
+    {
+        DefaultLogger::get()->error("Obj: Ignoring empty face");
+        m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+        return;
+    }
+
+    ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type );
+    
+    // Set active material, if one set
+    if (NULL != m_pModel->m_pCurrentMaterial) 
+        face->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    else 
+        face->m_pMaterial = m_pModel->m_pDefaultMaterial;
+
+    // Create a default object, if nothing is there
+    if ( NULL == m_pModel->m_pCurrent )
+        createObject( "defaultobject" );
+    
+    // Assign face to mesh
+    if ( NULL == m_pModel->m_pCurrentMesh )
+    {
+        createMesh();
+    }
+    
+    // Store the face
+    m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
+    m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
+    m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size(); 
+    if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) 
+    {
+        m_pModel->m_pCurrentMesh->m_hasNormals = true;
+    }
+    // Skip the rest of the line
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Get values for a new material description
 void ObjFileParser::getMaterialDesc()
 {
-	// Each material request a new object.
-	// Sometimes the object is already created (see 'o' tag by example), but it is not initialized !
-	// So, we create a new object only if the current on is already initialized !
-	if (m_pModel->m_pCurrent != NULL &&
-		(	m_pModel->m_pCurrent->m_Meshes.size() > 1 ||
-			(m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0)	)
-		)
-		m_pModel->m_pCurrent = NULL;
-
-	// Get next data for material data
-	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-	if (m_DataIt == m_DataItEnd)
-		return;
-
-	char *pStart = &(*m_DataIt);
+    // Each material request a new object.
+    // Sometimes the object is already created (see 'o' tag by example), but it is not initialized !
+    // So, we create a new object only if the current on is already initialized !
+    if (m_pModel->m_pCurrent != NULL &&
+        (	m_pModel->m_pCurrent->m_Meshes.size() > 1 ||
+            (m_pModel->m_pCurrent->m_Meshes.size() == 1 && m_pModel->m_Meshes[m_pModel->m_pCurrent->m_Meshes[0]]->m_Faces.size() != 0)	)
+        )
+        m_pModel->m_pCurrent = NULL;
+
+    // Get next data for material data
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    if (m_DataIt == m_DataItEnd)
+        return;
+
+    char *pStart = &(*m_DataIt);
     while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
         ++m_DataIt;
     }
 
-	// Get name
-	std::string strName(pStart, &(*m_DataIt));
-	if ( strName.empty())
-		return;
-
-	// Search for material
-	std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName );
-	if ( it == m_pModel->m_MaterialMap.end() )
-	{
-		// Not found, use default material
-		m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
-		DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping");
-	}
-	else
-	{
-		// Found, using detected material
-		m_pModel->m_pCurrentMaterial = (*it).second;
-		if ( needsNewMesh( strName ))
-		{
-			createMesh();	
-		}
-		m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
-	}
-
-	// Skip rest of line
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    // Get name
+    std::string strName(pStart, &(*m_DataIt));
+    if ( strName.empty())
+        return;
+
+    // Search for material
+    std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strName );
+    if ( it == m_pModel->m_MaterialMap.end() )
+    {
+        // Not found, use default material
+        m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
+        DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping");
+    }
+    else
+    {
+        // Found, using detected material
+        m_pModel->m_pCurrentMaterial = (*it).second;
+        if ( needsNewMesh( strName ))
+        {
+            createMesh();	
+        }
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strName );
+    }
+
+    // Skip rest of line
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Get a comment, values will be skipped
 void ObjFileParser::getComment()
 {
-	while (m_DataIt != m_DataItEnd)
-	{
-		if ( '\n' == (*m_DataIt))
-		{
-			++m_DataIt;
-			break;
-		}
-		else
-		{
-			++m_DataIt;
-		}
-	}
+    while (m_DataIt != m_DataItEnd)
+    {
+        if ( '\n' == (*m_DataIt))
+        {
+            ++m_DataIt;
+            break;
+        }
+        else
+        {
+            ++m_DataIt;
+        }
+    }
 }
 
 // -------------------------------------------------------------------
 //	Get material library from file.
 void ObjFileParser::getMaterialLib()
 {
-	// Translate tuple
-	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    // Translate tuple
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     if( m_DataIt == m_DataItEnd ) {
         return;
     }
-	
-	char *pStart = &(*m_DataIt);
+    
+    char *pStart = &(*m_DataIt);
     while( m_DataIt != m_DataItEnd && !IsLineEnd( *m_DataIt ) ) {
         ++m_DataIt;
     }
 
-	// Check for existence
-	const std::string strMatName(pStart, &(*m_DataIt));
-	IOStream *pFile = m_pIO->Open(strMatName);
+    // Check for existence
+    const std::string strMatName(pStart, &(*m_DataIt));
+    IOStream *pFile = m_pIO->Open(strMatName);
 
-	if (!pFile )
-	{
-		DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
-		m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-		return;
-	}
+    if (!pFile )
+    {
+        DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
+        m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+        return;
+    }
 
-	// Import material library data from file
-	std::vector<char> buffer;
-	BaseImporter::TextFileToBuffer(pFile,buffer);
-	m_pIO->Close( pFile );
+    // Import material library data from file
+    std::vector<char> buffer;
+    BaseImporter::TextFileToBuffer(pFile,buffer);
+    m_pIO->Close( pFile );
 
-	// Importing the material library 
-	ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel );			
+    // Importing the material library 
+    ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel );			
 }
 
 // -------------------------------------------------------------------
 //	Set a new material definition as the current material.
 void ObjFileParser::getNewMaterial()
 {
-	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-	m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
     if( m_DataIt == m_DataItEnd ) {
         return;
     }
 
-	char *pStart = &(*m_DataIt);
-	std::string strMat( pStart, *m_DataIt );
+    char *pStart = &(*m_DataIt);
+    std::string strMat( pStart, *m_DataIt );
     while( m_DataIt != m_DataItEnd && IsSpaceOrNewLine( *m_DataIt ) ) {
         ++m_DataIt;
     }
-	std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
-	if ( it == m_pModel->m_MaterialMap.end() )
-	{
-		// Show a warning, if material was not found
-		DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
-		m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
-	}
-	else
-	{
-		// Set new material
-		if ( needsNewMesh( strMat ) )
-		{
-			createMesh();	
-		}
-		m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
-	}
-
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
+    if ( it == m_pModel->m_MaterialMap.end() )
+    {
+        // Show a warning, if material was not found
+        DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
+        m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
+    }
+    else
+    {
+        // Set new material
+        if ( needsNewMesh( strMat ) )
+        {
+            createMesh();	
+        }
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );
+    }
+
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 int ObjFileParser::getMaterialIndex( const std::string &strMaterialName )
 {
-	int mat_index = -1;
+    int mat_index = -1;
     if( strMaterialName.empty() ) {
         return mat_index;
     }
-	for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
-	{
-		if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
-		{
-			mat_index = (int)index;
-			break;
-		}
-	}
-	return mat_index;
+    for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index)
+    {
+        if ( strMaterialName == m_pModel->m_MaterialLib[ index ])
+        {
+            mat_index = (int)index;
+            break;
+        }
+    }
+    return mat_index;
 }
 
 // -------------------------------------------------------------------
 //	Getter for a group name.  
 void ObjFileParser::getGroupName()
 {
-	std::string strGroupName;
+    std::string strGroupName;
    
-	m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
+    m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, strGroupName);
     if( isEndOfBuffer( m_DataIt, m_DataItEnd ) ) {
         return;
     }
 
-	// Change active group, if necessary
-	if ( m_pModel->m_strActiveGroup != strGroupName )
-	{
-		// Search for already existing entry
-		ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(strGroupName);
-		
-		// We are mapping groups into the object structure
-		createObject( strGroupName );
-		
-		// New group name, creating a new entry
-		if (it == m_pModel->m_Groups.end())
-		{
-			std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
-			m_pModel->m_Groups[ strGroupName ] = pFaceIDArray;
-			m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
-		}
-		else
-		{
-			m_pModel->m_pGroupFaceIDs = (*it).second;
-		}
-		m_pModel->m_strActiveGroup = strGroupName;
-	}
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    // Change active group, if necessary
+    if ( m_pModel->m_strActiveGroup != strGroupName )
+    {
+        // Search for already existing entry
+        ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(strGroupName);
+        
+        // We are mapping groups into the object structure
+        createObject( strGroupName );
+        
+        // New group name, creating a new entry
+        if (it == m_pModel->m_Groups.end())
+        {
+            std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
+            m_pModel->m_Groups[ strGroupName ] = pFaceIDArray;
+            m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
+        }
+        else
+        {
+            m_pModel->m_pGroupFaceIDs = (*it).second;
+        }
+        m_pModel->m_strActiveGroup = strGroupName;
+    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Not supported
 void ObjFileParser::getGroupNumber()
 {
-	// Not used
+    // Not used
 
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
 //	Not supported
 void ObjFileParser::getGroupNumberAndResolution()
 {
-	// Not used
+    // Not used
 
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------
@@ -660,105 +660,105 @@ void ObjFileParser::getGroupNumberAndResolution()
 //	identify it.
 void ObjFileParser::getObjectName()
 {
-	m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
+    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     if( m_DataIt == m_DataItEnd ) {
         return;
     }
-	char *pStart = &(*m_DataIt);
+    char *pStart = &(*m_DataIt);
     while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
         ++m_DataIt;
     }
 
-	std::string strObjectName(pStart, &(*m_DataIt));
-	if (!strObjectName.empty()) 
-	{
-		// Reset current object
-		m_pModel->m_pCurrent = NULL;
-		
-		// Search for actual object
-		for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin();
-			it != m_pModel->m_Objects.end();
-			++it)
-		{
-			if ((*it)->m_strObjName == strObjectName)
-			{
-				m_pModel->m_pCurrent = *it;
-				break;
-			}
-		}
-
-		// Allocate a new object, if current one was not found before
+    std::string strObjectName(pStart, &(*m_DataIt));
+    if (!strObjectName.empty()) 
+    {
+        // Reset current object
+        m_pModel->m_pCurrent = NULL;
+        
+        // Search for actual object
+        for (std::vector<ObjFile::Object*>::const_iterator it = m_pModel->m_Objects.begin();
+            it != m_pModel->m_Objects.end();
+            ++it)
+        {
+            if ((*it)->m_strObjName == strObjectName)
+            {
+                m_pModel->m_pCurrent = *it;
+                break;
+            }
+        }
+
+        // Allocate a new object, if current one was not found before
         if( NULL == m_pModel->m_pCurrent ) {
             createObject( strObjectName );
         }
-	}
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 // -------------------------------------------------------------------
 //	Creates a new object instance
 void ObjFileParser::createObject(const std::string &strObjectName)
 {
-	ai_assert( NULL != m_pModel );
-	//ai_assert( !strObjectName.empty() );
-
-	m_pModel->m_pCurrent = new ObjFile::Object;
-	m_pModel->m_pCurrent->m_strObjName = strObjectName;
-	m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
-	
-	createMesh();
-
-	if( m_pModel->m_pCurrentMaterial )
-	{
-		m_pModel->m_pCurrentMesh->m_uiMaterialIndex = 
-			getMaterialIndex( m_pModel->m_pCurrentMaterial->MaterialName.data );
-		m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
-	}		
+    ai_assert( NULL != m_pModel );
+    //ai_assert( !strObjectName.empty() );
+
+    m_pModel->m_pCurrent = new ObjFile::Object;
+    m_pModel->m_pCurrent->m_strObjName = strObjectName;
+    m_pModel->m_Objects.push_back( m_pModel->m_pCurrent );
+    
+    createMesh();
+
+    if( m_pModel->m_pCurrentMaterial )
+    {
+        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = 
+            getMaterialIndex( m_pModel->m_pCurrentMaterial->MaterialName.data );
+        m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    }		
 }
 // -------------------------------------------------------------------
 //	Creates a new mesh
 void ObjFileParser::createMesh()
 {
-	ai_assert( NULL != m_pModel );
-	m_pModel->m_pCurrentMesh = new ObjFile::Mesh;
-	m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
-	unsigned int meshId = m_pModel->m_Meshes.size()-1;
-	if ( NULL != m_pModel->m_pCurrent )
-	{
-		m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
-	}
-	else
-	{
-		DefaultLogger::get()->error("OBJ: No object detected to attach a new mesh instance.");
-	}
+    ai_assert( NULL != m_pModel );
+    m_pModel->m_pCurrentMesh = new ObjFile::Mesh;
+    m_pModel->m_Meshes.push_back( m_pModel->m_pCurrentMesh );
+    unsigned int meshId = m_pModel->m_Meshes.size()-1;
+    if ( NULL != m_pModel->m_pCurrent )
+    {
+        m_pModel->m_pCurrent->m_Meshes.push_back( meshId );
+    }
+    else
+    {
+        DefaultLogger::get()->error("OBJ: No object detected to attach a new mesh instance.");
+    }
 }
 
 // -------------------------------------------------------------------
 //	Returns true, if a new mesh must be created.
 bool ObjFileParser::needsNewMesh( const std::string &rMaterialName )
 {
-	if(m_pModel->m_pCurrentMesh == 0)
-	{
-		// No mesh data yet
-		return true;
-	}
-	bool newMat = false;
-	int matIdx = getMaterialIndex( rMaterialName );
-	int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
-	if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) || curMatIdx != matIdx )
-	{
-		// New material -> only one material per mesh, so we need to create a new 
-		// material
-		newMat = true;
-	}
-	return newMat;
+    if(m_pModel->m_pCurrentMesh == 0)
+    {
+        // No mesh data yet
+        return true;
+    }
+    bool newMat = false;
+    int matIdx = getMaterialIndex( rMaterialName );
+    int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
+    if ( curMatIdx != int(ObjFile::Mesh::NoMaterial) || curMatIdx != matIdx )
+    {
+        // New material -> only one material per mesh, so we need to create a new 
+        // material
+        newMat = true;
+    }
+    return newMat;
 }
 
 // -------------------------------------------------------------------
 //	Shows an error in parsing process.
 void ObjFileParser::reportErrorTokenInFace()
 {		
-	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-	DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+    DefaultLogger::get()->error("OBJ: Not supported token in face description detected");
 }
 
 // -------------------------------------------------------------------

+ 59 - 59
code/ObjFileParser.h

@@ -63,76 +63,76 @@ class IOSystem;
 class ObjFileParser
 {
 public:
-	static const size_t BUFFERSIZE = 4096;
-	typedef std::vector<char> DataArray;
-	typedef std::vector<char>::iterator DataArrayIt;
-	typedef std::vector<char>::const_iterator ConstDataArrayIt;
+    static const size_t BUFFERSIZE = 4096;
+    typedef std::vector<char> DataArray;
+    typedef std::vector<char>::iterator DataArrayIt;
+    typedef std::vector<char>::const_iterator ConstDataArrayIt;
 
 public:
-	///	\brief	Constructor with data array.
-	ObjFileParser(std::vector<char> &Data,const std::string &strModelName, IOSystem* io);
-	///	\brief	Destructor
-	~ObjFileParser();
-	///	\brief	Model getter.
-	ObjFile::Model *GetModel() const;
+    ///	\brief	Constructor with data array.
+    ObjFileParser(std::vector<char> &Data,const std::string &strModelName, IOSystem* io);
+    ///	\brief	Destructor
+    ~ObjFileParser();
+    ///	\brief	Model getter.
+    ObjFile::Model *GetModel() const;
 
 private:
-	///	Parse the loaded file
-	void parseFile();
-	///	Method to copy the new delimited word in the current line.
-	void copyNextWord(char *pBuffer, size_t length);
-	///	Method to copy the new line.
-	void copyNextLine(char *pBuffer, size_t length);
+    ///	Parse the loaded file
+    void parseFile();
+    ///	Method to copy the new delimited word in the current line.
+    void copyNextWord(char *pBuffer, size_t length);
+    ///	Method to copy the new line.
+    void copyNextLine(char *pBuffer, size_t length);
     /// Stores the vector 
     void getVector( std::vector<aiVector3D> &point3d_array );
     ///	Stores the following 3d vector.
-	void getVector3( std::vector<aiVector3D> &point3d_array );
-	///	Stores the following 3d vector.
-	void getVector2(std::vector<aiVector2D> &point2d_array);
+    void getVector3( std::vector<aiVector3D> &point3d_array );
+    ///	Stores the following 3d vector.
+    void getVector2(std::vector<aiVector2D> &point2d_array);
     ///	Stores the following face.
-	void getFace(aiPrimitiveType type);
-	/// Reads the material description.
+    void getFace(aiPrimitiveType type);
+    /// Reads the material description.
     void getMaterialDesc();
-	///	Gets a comment.
-	void getComment();
-	/// Gets a a material library.
-	void getMaterialLib();
-	/// Creates a new material.
-	void getNewMaterial();
-	/// Gets the group name from file.
-	void getGroupName();
-	/// Gets the group number from file.
-	void getGroupNumber();
-	/// Gets the group number and resolution from file.
-	void getGroupNumberAndResolution();
-	/// Returns the index of the material. Is -1 if not material was found.
-	int getMaterialIndex( const std::string &strMaterialName );
-	/// Parse object name
-	void getObjectName();
-	/// Creates a new object.
-	void createObject(const std::string &strObjectName);
-	///	Creates a new mesh.
-	void createMesh(); 
-	///	Returns true, if a new mesh instance must be created.
-	bool needsNewMesh( const std::string &rMaterialName );
-	///	Error report in token
-	void reportErrorTokenInFace();
+    ///	Gets a comment.
+    void getComment();
+    /// Gets a a material library.
+    void getMaterialLib();
+    /// Creates a new material.
+    void getNewMaterial();
+    /// Gets the group name from file.
+    void getGroupName();
+    /// Gets the group number from file.
+    void getGroupNumber();
+    /// Gets the group number and resolution from file.
+    void getGroupNumberAndResolution();
+    /// Returns the index of the material. Is -1 if not material was found.
+    int getMaterialIndex( const std::string &strMaterialName );
+    /// Parse object name
+    void getObjectName();
+    /// Creates a new object.
+    void createObject(const std::string &strObjectName);
+    ///	Creates a new mesh.
+    void createMesh(); 
+    ///	Returns true, if a new mesh instance must be created.
+    bool needsNewMesh( const std::string &rMaterialName );
+    ///	Error report in token
+    void reportErrorTokenInFace();
 
 private:
-	///	Default material name
-	static const std::string DEFAULT_MATERIAL;
-	//!	Iterator to current position in buffer
-	DataArrayIt m_DataIt;
-	//!	Iterator to end position of buffer
-	DataArrayIt m_DataItEnd;
-	//!	Pointer to model instance
-	ObjFile::Model *m_pModel;
-	//!	Current line (for debugging)
-	unsigned int m_uiLine;
-	//!	Helper buffer
-	char m_buffer[BUFFERSIZE];
-	///	Pointer to IO system instance.
-	IOSystem *m_pIO;
+    ///	Default material name
+    static const std::string DEFAULT_MATERIAL;
+    //!	Iterator to current position in buffer
+    DataArrayIt m_DataIt;
+    //!	Iterator to end position of buffer
+    DataArrayIt m_DataItEnd;
+    //!	Pointer to model instance
+    ObjFile::Model *m_pModel;
+    //!	Current line (for debugging)
+    unsigned int m_uiLine;
+    //!	Helper buffer
+    char m_buffer[BUFFERSIZE];
+    ///	Pointer to IO system instance.
+    IOSystem *m_pIO;
 };
 
 }	// Namespace Assimp

+ 50 - 50
code/OgreImporter.h

@@ -36,63 +36,63 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 ----------------------------------------------------------------------
-*/
-
+*/
+
 #ifndef AI_OGREIMPORTER_H_INC
 #define AI_OGREIMPORTER_H_INC
 
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
-
-#include "BaseImporter.h"
-
-#include "OgreStructs.h"
-#include "OgreParsingUtils.h"
-
-namespace Assimp
-{
-namespace Ogre
-{
-
+
+#include "BaseImporter.h"
+
+#include "OgreStructs.h"
+#include "OgreParsingUtils.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+
 /**	Importer for Ogre mesh, skeleton and material formats.
-	@todo Support vertex colors.
-	@todo Support poses/animations from the mesh file. 
-	Currently only skeleton file animations are supported. */
-class OgreImporter : public BaseImporter
-{
-public:
-	/// BaseImporter override.
-	virtual bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
-	
-	/// BaseImporter override.
+	@todo Support vertex colors.
+	@todo Support poses/animations from the mesh file. 
+	Currently only skeleton file animations are supported. */
+class OgreImporter : public BaseImporter
+{
+public:
+	/// BaseImporter override.
+	virtual bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
+	
+	/// BaseImporter override.
 	virtual void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
 	
 	/// BaseImporter override.
-	virtual const aiImporterDesc *GetInfo() const;
-	
-	/// BaseImporter override.
-	virtual void SetupProperties(const Importer *pImp);
-
-private:
-	/// Read materials referenced by the @c mesh to @c pScene.
-	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
-	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh);
-	void AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials);
-	
-	/// Reads material
-	aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName);
-
-	// These functions parse blocks from a material file from @c ss. Starting parsing from "{" and ending it to "}".
-	bool ReadTechnique(const std::string &techniqueName, std::stringstream &ss, aiMaterial *material);
-	bool ReadPass(const std::string &passName, std::stringstream &ss, aiMaterial *material);	
-	bool ReadTextureUnit(const std::string &textureUnitName, std::stringstream &ss, aiMaterial *material);
-
-	std::string m_userDefinedMaterialLibFile;
-	bool m_detectTextureTypeFromFilename;
-	
-	std::map<aiTextureType, unsigned int> m_textures;
-};
-} // Ogre
-} // Assimp
-
+	virtual const aiImporterDesc *GetInfo() const;
+	
+	/// BaseImporter override.
+	virtual void SetupProperties(const Importer *pImp);
+
+private:
+	/// Read materials referenced by the @c mesh to @c pScene.
+	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
+	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh);
+	void AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials);
+	
+	/// Reads material
+	aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName);
+
+	// These functions parse blocks from a material file from @c ss. Starting parsing from "{" and ending it to "}".
+	bool ReadTechnique(const std::string &techniqueName, std::stringstream &ss, aiMaterial *material);
+	bool ReadPass(const std::string &passName, std::stringstream &ss, aiMaterial *material);	
+	bool ReadTextureUnit(const std::string &textureUnitName, std::stringstream &ss, aiMaterial *material);
+
+	std::string m_userDefinedMaterialLibFile;
+	bool m_detectTextureTypeFromFilename;
+	
+	std::map<aiTextureType, unsigned int> m_textures;
+};
+} // Ogre
+} // Assimp
+
 #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
 #endif // AI_OGREIMPORTER_H_INC

+ 691 - 0
code/OpenGEXImporter.cpp

@@ -0,0 +1,691 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* 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.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+OWNER OR 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.
+
+----------------------------------------------------------------------
+*/
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#include "AssimpPCH.h"
+#include "OpenGEXImporter.h"
+#include "DefaultIOSystem.h"
+
+#include <openddlparser/OpenDDLParser.h>
+
+#include <vector>
+
+static const aiImporterDesc desc = {
+    "Open Game Engine Exchange",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour,
+    0,
+    0,
+    0,
+    0,
+    "ogex"
+};
+
+namespace Grammar {
+    static const char *MetricType          = "Metric";
+    static const char *Metric_DistanceType = "distance";
+    static const char *Metric_AngleType    = "angle";
+    static const char *Metric_TimeType     = "time";
+    static const char *Metric_UpType       = "up";
+    static const char *NameType            = "Name";
+    static const char *ObjectRefType       = "ObjectRef";
+    static const char *MaterialRefType     = "MaterialRef";
+    static const char *MetricKeyType       = "key";
+    static const char *GeometryNodeType    = "GeometryNode";
+    static const char *GeometryObjectType  = "GeometryObject";
+    static const char *TransformType       = "Transform";
+    static const char *MeshType            = "Mesh";
+    static const char *VertexArrayType     = "VertexArray";
+    static const char *IndexArrayType      = "IndexArray";
+    static const char *MaterialType        = "Material";
+    static const char *ColorType           = "Color";
+    static const char *TextureType         = "Texture";
+
+    enum TokenType {
+        NoneType = -1,
+        MetricToken,
+        NameToken,
+        ObjectRefToken,
+        MaterialRefToken,
+        MetricKeyToken,
+        GeometryNodeToken,
+        GeometryObjectToken,
+        TransformToken,
+        MeshToken,
+        VertexArrayToken,
+        IndexArrayToken,
+        MaterialToken,
+        ColorToken,
+        TextureToken
+    };
+
+    static const char *ValidMetricToken[ 4 ] = {
+        Metric_DistanceType,
+        Metric_AngleType,
+        Metric_TimeType,
+        Metric_UpType
+    };
+
+    static int isValidMetricType( const char *token ) {
+        if( NULL == token ) {
+            return false;
+        }
+
+        int idx( -1 );
+        for( size_t i = 0; i < 4; i++ ) {
+            if( 0 == strncmp( ValidMetricToken[ i ], token, strlen( token ) ) ) {
+                idx = (int) i;
+                break;
+            }
+        }
+
+        return idx;
+    }
+
+    static TokenType matchTokenType( const char *tokenType ) {
+        if( 0 == strncmp( MetricType, tokenType, strlen( MetricType ) ) ) {
+            return MetricToken;
+        } else if( 0 == strncmp( NameType, tokenType, strlen( NameType ) ) ) {
+            return NameToken;
+        }
+        else if( 0 == strncmp( ObjectRefType, tokenType, strlen( ObjectRefType ) ) ) {
+            return ObjectRefToken;
+        }
+        else if( 0 == strncmp( MaterialRefType, tokenType, strlen( MaterialRefType ) ) ) {
+            return MaterialRefToken; 
+        }
+        else if( 0 == strncmp( MetricKeyType, tokenType, strlen( MetricKeyType ) ) ) {
+            return MetricKeyToken;
+        }
+        else if( 0 == strncmp( GeometryNodeType, tokenType, strlen( GeometryNodeType ) ) ) {
+            return GeometryNodeToken;
+        }
+        else if( 0 == strncmp( GeometryObjectType, tokenType, strlen( GeometryObjectType ) ) ) {
+            return GeometryObjectToken;
+        }
+        else if( 0 == strncmp( TransformType, tokenType, strlen( TransformType ) ) ) {
+            return TransformToken;
+        }
+        else if( 0 == strncmp( MeshType, tokenType, strlen( MeshType ) ) ) {
+            return MeshToken;
+        }
+        else if( 0 == strncmp( VertexArrayType, tokenType, strlen( VertexArrayType ) ) ) {
+            return VertexArrayToken;
+        }
+        else if( 0 == strncmp( IndexArrayType, tokenType, strlen( IndexArrayType ) ) ) {
+            return IndexArrayToken;
+        }
+        else if( 0 == strncmp( MaterialType, tokenType, strlen( MaterialType ) ) ) {
+            return MaterialToken;
+        }
+        else if( 0 == strncmp( ColorType, tokenType, strlen( ColorType ) ) ) {
+            return ColorToken;
+        }
+        else if( 0 == strncmp( TextureType, tokenType, strlen( TextureType ) ) ) {
+            return TextureToken;
+        }
+
+        return NoneType;
+    }
+
+} // Namespace Grammar
+
+namespace Assimp {
+namespace OpenGEX {
+
+USE_ODDLPARSER_NS
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::RefInfo( aiNode *node, Type type, std::vector<std::string> &names )
+: m_node( node )
+, m_type( type )
+, m_Names( names ) {
+    // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::RefInfo::~RefInfo() {
+    // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::OpenGEXImporter() 
+: m_meshCache()
+, m_mesh2refMap()
+, m_ctx( NULL )
+, m_currentNode( NULL )
+, m_currentMesh( NULL )
+, m_nodeStack()
+, m_unresolvedRefStack() {
+    // empty
+}
+
+//------------------------------------------------------------------------------------------------
+OpenGEXImporter::~OpenGEXImporter() {
+    m_ctx = NULL;
+}
+
+//------------------------------------------------------------------------------------------------
+bool OpenGEXImporter::CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const {
+    bool canRead( false );
+    if( !checkSig ) {
+        canRead = SimpleExtensionCheck( file, "ogex" );
+    } else {
+        static const char *token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
+        canRead = BaseImporter::SearchFileHeaderForToken( pIOHandler, file, token, 4 );
+    }
+
+    return canRead;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
+    // open source file
+    IOStream *file = pIOHandler->Open( filename, "rb" );
+    if( !file ) {
+        throw DeadlyImportError( "Failed to open file " + filename );
+    }
+
+    std::vector<char> buffer;
+    TextFileToBuffer( file, buffer );
+
+    OpenDDLParser myParser;
+    myParser.setBuffer( &buffer[ 0 ], buffer.size() );
+    bool success( myParser.parse() );
+    if( success ) {
+        m_ctx = myParser.getContext();
+        pScene->mRootNode = new aiNode;
+        pScene->mRootNode->mName.Set( filename );
+        handleNodes( m_ctx->m_root, pScene );
+    }
+
+    resolveReferences();
+}
+
+//------------------------------------------------------------------------------------------------
+const aiImporterDesc *OpenGEXImporter::GetInfo() const {
+    return &desc;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::SetupProperties( const Importer *pImp ) {
+    if( NULL == pImp ) {
+        return;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNodes( DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        return;
+    }
+
+    DDLNode::DllNodeList childs = node->getChildNodeList();
+    for( DDLNode::DllNodeList::iterator it = childs.begin(); it != childs.end(); it++ ) {
+        Grammar::TokenType tokenType( Grammar::matchTokenType( ( *it )->getType().c_str() ) );
+        switch( tokenType ) {
+            case Grammar::MetricToken:
+                handleMetricNode( *it, pScene );
+                break;
+
+            case Grammar::NameToken:
+                handleNameNode( *it, pScene );
+                break;
+
+            case Grammar::ObjectRefToken:
+                handleObjectRefNode( *it, pScene );
+                break;
+
+            case Grammar::MaterialRefToken:
+                handleMaterialRefNode( *it, pScene );
+                break;
+
+            case Grammar::MetricKeyToken:
+                break;
+
+            case Grammar::GeometryNodeToken:
+                handleGeometryNode( *it, pScene );
+                break;
+
+            case Grammar::GeometryObjectToken:
+                handleGeometryObject( *it, pScene );
+                break;
+
+            case Grammar::TransformToken:
+                handleTransformNode( *it, pScene );
+                break;
+
+            case Grammar::MeshToken:
+                handleMeshNode( *it, pScene );
+                break;
+
+            case Grammar::VertexArrayToken:
+                handleVertexArrayNode( *it, pScene );
+                break;
+
+            case Grammar::IndexArrayToken:
+                handleIndexArrayNode( *it, pScene );
+                break;
+
+            case Grammar::MaterialToken:
+                handleMaterialNode( *it, pScene );
+                break;
+
+            case Grammar::ColorToken:
+                handleColorNode( *it, pScene );
+                break;
+
+            case Grammar::TextureToken:
+                handleTextureNode( *it, pScene );
+                break;
+            
+            default:
+                break;
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMetricNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == node || NULL == m_ctx ) {
+        return;
+    }
+
+    if( m_ctx->m_root != node->getParent() ) {
+        return;
+    }
+
+    Property *prop( node->getProperties() );
+    while( NULL != prop ) {
+        if( NULL != prop->m_id ) {
+            if( Value::ddl_string == prop->m_primData->m_type ) {
+                std::string valName( (char*) prop->m_primData->m_data );
+                int type( Grammar::isValidMetricType( valName.c_str() ) );
+                if( Grammar::NoneType != type ) {
+                    Value *val( node->getValue() );
+                    if( NULL != val ) {
+                        if( Value::ddl_float == val->m_type ) {
+                            m_metrics[ type ].m_floatValue = val->getFloat();
+                        } else if( Value::ddl_int32 == val->m_type ) {
+                            m_metrics[ type ].m_intValue = val->getInt32();
+                        } else if( Value::ddl_string == val->m_type ) {
+                            m_metrics[type].m_stringValue = std::string( val->getString() );
+                        } else {
+                            throw DeadlyImportError( "OpenGEX: invalid data type for Metric node." );
+                        }
+                    }
+                }
+            }
+        }
+        prop = prop->m_next;
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleNameNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    Value *val( node->getValue() );
+    if( NULL != val ) {
+        if( Value::ddl_string != val->m_type ) {
+            throw DeadlyImportError( "OpenGEX: invalid data type for value in node name." );
+            return;
+        }
+
+        const std::string name( val->getString() );
+        m_currentNode->mName.Set( name.c_str() );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+static void getRefNames( DDLNode *node, std::vector<std::string> &names ) {
+    ai_assert( NULL != node );
+
+    Reference *ref = node->getReferences();
+    if( NULL != ref ) {
+        for( size_t i = 0; i < ref->m_numRefs; i++ )  {
+            Name *currentName( ref->m_referencedName[ i ] );
+            if( NULL != currentName && NULL != currentName->m_id ) {
+                const std::string name( currentName->m_id->m_buffer );
+                if( !name.empty() ) {
+                    names.push_back( name );
+                }
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    std::vector<std::string> objRefNames;
+    getRefNames( node, objRefNames );
+    m_currentNode->mNumMeshes = objRefNames.size();
+    m_currentNode->mMeshes = new unsigned int[ objRefNames.size() ];
+    if( !objRefNames.empty() ) {
+        m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MeshRef, objRefNames ) );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    std::vector<std::string> matRefNames;
+    getRefNames( node, matRefNames );
+    if( !matRefNames.empty() ) {
+        m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MaterialRef, matRefNames ) );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryNode( DDLNode *node, aiScene *pScene ) {
+    aiNode *newNode = new aiNode;
+    pushNode( newNode, pScene );
+    m_currentNode = newNode;
+    handleNodes( node, pScene );
+    
+    popNode();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleGeometryObject( DDLNode *node, aiScene *pScene ) {
+    aiMesh *currentMesh( new aiMesh );
+    const size_t idx( m_meshCache.size() );
+    m_meshCache.push_back( currentMesh );
+
+    // store name to reference relation
+    m_mesh2refMap[ node->getName() ] = idx;
+
+    // todo: child nodes?
+
+    handleNodes( node, pScene );
+}
+
+//------------------------------------------------------------------------------------------------
+static void setMatrix( aiNode *node, DataArrayList *transformData ) {
+    ai_assert( NULL != node );
+    ai_assert( NULL != transformData );
+
+    float m[ 16 ];
+    size_t i( 1 );
+    Value *next( transformData->m_dataList->m_next );
+    m[ 0 ] = transformData->m_dataList->getFloat();
+    while(  next != NULL ) {
+        m[ i ] = next->getFloat();
+        next = next->m_next;
+        i++;
+    }
+    
+    node->mTransformation.a1 = m[ 0 ];
+    node->mTransformation.a2 = m[ 1 ];
+    node->mTransformation.a3 = m[ 2 ];
+    node->mTransformation.a4 = m[ 3 ];
+
+    node->mTransformation.b1 = m[ 4 ];
+    node->mTransformation.b2 = m[ 5 ];
+    node->mTransformation.b3 = m[ 6 ];
+    node->mTransformation.b4 = m[ 7 ];
+
+    node->mTransformation.c1 = m[ 8 ];
+    node->mTransformation.c2 = m[ 9 ];
+    node->mTransformation.c3 = m[ 10 ];
+    node->mTransformation.c4 = m[ 11 ];
+
+    node->mTransformation.d1 = m[ 12 ];
+    node->mTransformation.d2 = m[ 13 ];
+    node->mTransformation.d3 = m[ 14 ];
+    node->mTransformation.d4 = m[ 15 ];
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == m_currentNode ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+
+    DataArrayList *transformData( node->getDataArrayList() );
+    if( NULL != transformData ) {
+        if( transformData->m_numItems != 16 ) {
+            throw DeadlyImportError( "Invalid number of data for transform matrix." );
+            return;
+        }
+        setMatrix( m_currentNode, transformData );
+    } 
+}
+
+//------------------------------------------------------------------------------------------------
+static void propId2StdString( Property *prop, std::string &name, std::string &key ) {
+    name = key = "";
+    if( NULL == prop ) {
+        return;
+    }
+
+    if( NULL != prop->m_id ) {
+        name = prop->m_id->m_buffer;
+        if( Value::ddl_string == prop->m_primData->m_type ) {
+            key = prop->m_primData->getString();
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    Property *prop = node->getProperties();
+    m_currentMesh = new aiMesh;
+    m_meshCache.push_back( m_currentMesh );
+    
+    if( NULL != prop ) {
+        std::string propName, propKey;
+        propId2StdString( prop, propName, propKey );
+        if( "triangles" == propName ) {
+            m_currentMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+        }
+    }
+
+    handleNodes( node, pScene );
+}
+
+//------------------------------------------------------------------------------------------------
+enum MeshAttribute {
+    None,
+    Position,
+    Normal,
+    TexCoord
+};
+
+//------------------------------------------------------------------------------------------------
+static MeshAttribute getAttributeByName( const char *attribName ) {
+    ai_assert( NULL != attribName  );
+
+    if( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) {
+        return Position;
+    } else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) {
+        return Normal;
+    } else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) {
+        return TexCoord;
+    }
+
+    return None;
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+    if( NULL == node ) {
+        throw DeadlyImportError( "No parent node for name." );
+        return;
+    }
+
+    Property *prop( node->getProperties() );
+    if( NULL != prop ) {
+        std::string propName, propKey;
+        propId2StdString( prop, propName, propKey );
+        MeshAttribute attribType( getAttributeByName( propName.c_str() ) );
+        if( None == attribType ) {
+            return;
+        }
+
+        DataArrayList *vaList = node->getDataArrayList();
+        if( NULL == vaList ) {
+            return;
+        }
+
+        if( Position == attribType ) {
+            aiVector3D *pos = new aiVector3D[ vaList->m_numItems ];
+            Value *next( vaList->m_dataList );
+            for( size_t i = 0; i < vaList->m_numItems; i++ ) {
+                
+            }
+        } else if( Normal == attribType ) {
+            aiVector3D *normal = new aiVector3D[ vaList->m_numItems ];
+        } else if( TexCoord == attribType ) {
+            aiVector3D *tex = new aiVector3D[ vaList->m_numItems ];
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleMaterialNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::resolveReferences() {
+    if( m_unresolvedRefStack.empty() ) {
+        return;
+    }
+
+    RefInfo *currentRefInfo( NULL );
+    for( std::vector<RefInfo*>::iterator it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it ) {
+        currentRefInfo = *it;
+        if( NULL != currentRefInfo ) {
+            aiNode *node( currentRefInfo->m_node );
+            if( RefInfo::MeshRef == currentRefInfo->m_type ) {
+                for( size_t i = 0; i < currentRefInfo->m_Names.size(); i++ ) {
+                    const std::string &name(currentRefInfo->m_Names[ i ] );
+                    unsigned int meshIdx = m_mesh2refMap[ name ];
+                    node->mMeshes[ i ] = meshIdx;
+                }
+            } else if( RefInfo::MaterialRef == currentRefInfo->m_type ) {
+                // ToDo
+            } else {
+                throw DeadlyImportError( "Unknown reference info to resolve." );
+            }
+        }
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::pushNode( aiNode *node, aiScene *pScene ) {
+    ai_assert( NULL != pScene );
+
+    if( NULL != node ) {
+        if( m_nodeStack.empty() ) {
+            node->mParent = pScene->mRootNode;
+        } else {
+            aiNode *parent( m_nodeStack.back() );
+            ai_assert( NULL != parent );
+            node->mParent = parent;
+        }
+        m_nodeStack.push_back( node );
+    }
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::popNode() {
+    if( m_nodeStack.empty() ) {
+        return NULL;
+    }
+    
+    aiNode *node( top() );
+    m_nodeStack.pop_back();
+    
+    return node;
+}
+
+//------------------------------------------------------------------------------------------------
+aiNode *OpenGEXImporter::top() const {
+    if( m_nodeStack.empty() ) {
+        return NULL;
+    }
+
+    return m_nodeStack.back();
+}
+
+//------------------------------------------------------------------------------------------------
+void OpenGEXImporter::clearNodeStack() {
+    m_nodeStack.clear();
+}
+
+//------------------------------------------------------------------------------------------------
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER

+ 158 - 0
code/OpenGEXImporter.h

@@ -0,0 +1,158 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* 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.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+OWNER OR 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.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_OPENGEX_IMPORTER_H
+#define AI_OPENGEX_IMPORTER_H
+
+#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#include "BaseImporter.h"
+
+#include <vector>
+
+namespace ODDLParser {
+    class DDLNode;
+    struct Context;
+}
+
+namespace Assimp {
+namespace OpenGEX {
+
+struct MetricInfo {
+    enum Type {
+        Distance = 0,
+        Angle,
+        Time,
+        Up,
+        Max
+    };
+
+    std::string m_stringValue;
+    float m_floatValue;
+    int m_intValue;
+
+    MetricInfo()
+    : m_stringValue( "" )
+    , m_floatValue( 0.0f )
+    , m_intValue( -1 ) {
+        // empty
+    }
+};
+
+/** @brief  This class is used to implement the OpenGEX importer
+ *
+ *  See http://opengex.org/OpenGEX.pdf for spec.
+ */
+class OpenGEXImporter : public BaseImporter {
+public:
+    /// The class constructor.
+    OpenGEXImporter();
+
+    /// The class destructor.
+    virtual ~OpenGEXImporter();
+
+    /// BaseImporter override.
+    virtual bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const;
+
+    /// BaseImporter override.
+    virtual void InternReadFile( const std::string &file, aiScene *pScene, IOSystem *pIOHandler );
+
+    /// BaseImporter override.
+    virtual const aiImporterDesc *GetInfo() const;
+
+    /// BaseImporter override.
+    virtual void SetupProperties( const Importer *pImp );
+
+protected:
+    void handleNodes( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMetricNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleNameNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleObjectRefNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleGeometryNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleGeometryObject( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleTransformNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMeshNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleMaterialNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleColorNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene );
+    void resolveReferences();
+    void pushNode( aiNode *node, aiScene *pScene );
+    aiNode *popNode();
+    aiNode *top() const;
+    void clearNodeStack();
+
+private:
+    struct RefInfo {
+        enum Type {
+            MeshRef,
+            MaterialRef
+        };
+
+        aiNode *m_node;
+        Type m_type;
+        std::vector<std::string> m_Names;
+
+        RefInfo( aiNode *node, Type type, std::vector<std::string> &names );
+        ~RefInfo();
+
+    private:
+        RefInfo( const RefInfo & );
+        RefInfo &operator = ( const RefInfo & );
+    };
+
+    std::vector<aiMesh*> m_meshCache;
+    std::map<std::string, size_t> m_mesh2refMap;
+
+    ODDLParser::Context *m_ctx;
+    MetricInfo m_metrics[ MetricInfo::Max ];
+    aiNode *m_currentNode;
+    aiMesh *m_currentMesh;
+    std::vector<aiNode*> m_nodeStack;
+    std::vector<RefInfo*> m_unresolvedRefStack;
+};
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_OPENGEX_IMPORTER
+
+#endif // AI_OPENGEX_IMPORTER_H

+ 265 - 0
code/OpenGEXStructs.h

@@ -0,0 +1,265 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2014, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* 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.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+OWNER OR 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.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_OPENGEXSTRUCTS_H_INC
+#define AI_OPENGEXSTRUCTS_H_INC
+
+#include <string>
+#include <map>
+
+namespace Assimp {
+namespace OpenGEX {
+
+struct Skin;
+struct Object;
+struct LightObject;
+struct CameraObject;
+struct Material;
+struct BoneNode;
+struct BoneCountArray;
+struct BoneIndexArray;
+struct BoneWeightArray;
+
+struct Metric {
+    float m_distance;
+    float m_angle;
+    float m_time;
+    float m_up;
+};
+
+struct VertexArray {
+    std::string arrayAttrib;
+    unsigned int morphIndex;
+};
+
+struct IndexArray {
+    unsigned int materialIndex;
+    unsigned int restartIndex;
+    std::string frontFace;
+};
+
+struct Mesh {
+    unsigned int meshLevel;
+    std::string meshPrimitive;
+    Skin *skinStructure;
+};
+
+struct Node {
+    std::string nodeName;
+};
+
+struct GeometryNode {
+    bool visibleFlag[ 2 ];
+    bool shadowFlag[ 2 ];
+    bool motionBlurFlag[ 2 ];
+};
+
+struct LightNode {
+    bool shadowFlag[ 2 ];
+    const LightObject *lightObjectStructure;
+};
+
+struct CameraNode {
+    const CameraObject *cameraObjectStructure;
+};
+
+struct GeometryObject {
+    Object *object;
+    bool visibleFlag;
+    bool shadowFlag;
+    bool motionBlurFlag;
+    std::map<std::string, Mesh*> meshMap;
+};
+
+struct LightObject {
+    Object *object;
+    std::string typeString;
+    bool shadowFlag;
+};
+
+
+struct CameraObject {
+    float focalLength;
+    float nearDepth;
+    float farDepth;
+};
+
+struct Matrix {
+    bool objectFlag;
+};
+
+struct Transform {
+    Matrix *matrix;
+    int transformCount;
+    const float	*transformArray;
+};
+
+struct Translation {
+    std::string translationKind;
+};
+
+struct Rotation {
+    std::string rotationKind;
+};
+
+struct Scale {
+    std::string scaleKind;
+};
+
+struct Name {
+    std::string	name;
+};
+
+
+struct ObjectRef {
+    Object *targetStructure;
+};
+
+struct MaterialRef {
+    unsigned int materialIndex;
+    const Material *targetStructure;
+};
+
+struct BoneRefArray {
+    int	boneCount;
+    const BoneNode **boneNodeArray;
+};
+
+struct BoneCount {
+    int	vertexCount;
+    const unsigned short *boneCountArray;
+    unsigned short *arrayStorage;
+};
+
+struct BoneIndex {
+    int	boneIndexCount;
+    const unsigned short *boneIndexArray;
+    unsigned short *arrayStorage;
+};
+
+
+struct BoneWeight {
+    int boneWeightCount;
+    const float *boneWeightArray;
+};
+
+struct Skeleton {
+    const BoneRefArray *boneRefArrayStructure;
+    const Transform *transformStructure;
+};
+
+struct Skin {
+    const Skeleton *skeletonStructure;
+    const BoneCountArray *boneCountArrayStructure;
+    const BoneIndexArray *boneIndexArrayStructure;
+    const BoneWeightArray *boneWeightArrayStructure;
+};
+
+struct Material {
+    bool twoSidedFlag;
+    const char *materialName;
+};
+
+struct Attrib {
+    std::string attribString;
+};
+
+struct Param {
+    float param;
+};
+
+struct Color {
+    float color[ 4 ];
+};
+
+struct Texture {
+    std::string textureName;
+    unsigned int texcoordIndex;
+};
+
+struct Atten {
+    std::string attenKind;
+    std::string curveType;
+
+    float beginParam;
+    float endParam;
+
+    float scaleParam;
+    float offsetParam;
+
+    float constantParam;
+    float linearParam;
+    float quadraticParam;
+
+    float powerParam;
+};
+
+struct Key {
+    std::string keyKind;
+    bool scalarFlag;
+};
+
+struct Curve {
+    std::string curveType;
+    const Key *keyValueStructure;
+    const Key *keyControlStructure[ 2 ];
+    const Key *keyTensionStructure;
+    const Key *keyContinuityStructure;
+    const Key *keyBiasStructure;
+};
+
+struct Animation {
+    int clipIndex;
+    bool beginFlag;
+    bool endFlag;
+    float beginTime;
+    float endTime;
+};
+
+struct OpenGexDataDescription {
+    float distanceScale;
+    float angleScale;
+    float timeScale;
+    int upDirection;
+};
+
+} // Namespace OpenGEX
+} // Namespace Assimp
+
+#endif // AI_OPENGEXSTRUCTS_H_INC

+ 2 - 2
code/PlyExporter.cpp

@@ -50,7 +50,7 @@ namespace Assimp	{
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to PLY. Prototyped and registered in Exporter.cpp
-void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
+void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	// invoke the exporter 
 	PlyExporter exporter(pFile, pScene);
@@ -64,7 +64,7 @@ void ExportScenePly(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 	outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
 }
 
-void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
+void ExportScenePlyBinary(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	// invoke the exporter 
 	PlyExporter exporter(pFile, pScene, true);

+ 46 - 27
code/PlyLoader.cpp

@@ -64,6 +64,25 @@ static const aiImporterDesc desc = {
 	"ply" 
 };
 
+
+// ------------------------------------------------------------------------------------------------
+// Internal stuff
+namespace
+{
+	// ------------------------------------------------------------------------------------------------
+	// Checks that property index is within range
+	template <class T>
+	const T &GetProperty(const std::vector<T> &props, int idx)
+	{
+        if( static_cast< size_t >( idx ) >= props.size() ) {
+            throw DeadlyImportError( "Invalid .ply file: Property index is out of range." );
+        }
+
+		return props[idx];
+	}
+}
+
+
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PLYImporter::PLYImporter()
@@ -431,13 +450,13 @@ void PLYImporter::LoadTextureCoordinates(std::vector<aiVector2D>* pvOut)
 			if (0xFFFFFFFF != aiPositions[0])
 			{
 				vOut.x = PLY::PropertyInstance::ConvertTo<float>(
-					(*i).alProperties[aiPositions[0]].avList.front(),aiTypes[0]);
+					GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
 			}
 
 			if (0xFFFFFFFF != aiPositions[1])
 			{
 				vOut.y = PLY::PropertyInstance::ConvertTo<float>(
-					(*i).alProperties[aiPositions[1]].avList.front(),aiTypes[1]);
+					GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
 			}
 			// and add them to our nice list
 			pvOut->push_back(vOut);
@@ -541,19 +560,19 @@ void PLYImporter::LoadVertices(std::vector<aiVector3D>* pvOut, bool p_bNormals)
 			if (0xFFFFFFFF != aiPositions[0])
 			{
 				vOut.x = PLY::PropertyInstance::ConvertTo<float>(
-					(*i).alProperties[aiPositions[0]].avList.front(),aiTypes[0]);
+					GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
 			}
 
 			if (0xFFFFFFFF != aiPositions[1])
 			{
 				vOut.y = PLY::PropertyInstance::ConvertTo<float>(
-					(*i).alProperties[aiPositions[1]].avList.front(),aiTypes[1]);
+					GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
 			}
 
 			if (0xFFFFFFFF != aiPositions[2])
 			{
 				vOut.z = PLY::PropertyInstance::ConvertTo<float>(
-					(*i).alProperties[aiPositions[2]].avList.front(),aiTypes[2]);
+					GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]);
 			}
 
 			// and add them to our nice list
@@ -659,28 +678,28 @@ void PLYImporter::LoadVertexColor(std::vector<aiColor4D>* pvOut)
 			
 			if (0xFFFFFFFF != aiPositions[0])
 			{
-				vOut.r = NormalizeColorValue((*i).alProperties[
-					aiPositions[0]].avList.front(),aiTypes[0]);
+				vOut.r = NormalizeColorValue(GetProperty((*i).alProperties,
+					aiPositions[0]).avList.front(),aiTypes[0]);
 			}
 
 			if (0xFFFFFFFF != aiPositions[1])
 			{
-				vOut.g = NormalizeColorValue((*i).alProperties[
-					aiPositions[1]].avList.front(),aiTypes[1]);
+				vOut.g = NormalizeColorValue(GetProperty((*i).alProperties,
+					aiPositions[1]).avList.front(),aiTypes[1]);
 			}
 
 			if (0xFFFFFFFF != aiPositions[2])
 			{
-				vOut.b = NormalizeColorValue((*i).alProperties[
-					aiPositions[2]].avList.front(),aiTypes[2]);
+				vOut.b = NormalizeColorValue(GetProperty((*i).alProperties,
+					aiPositions[2]).avList.front(),aiTypes[2]);
 			}
 
 			// assume 1.0 for the alpha channel ifit is not set
 			if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0f;
 			else
 			{
-				vOut.a = NormalizeColorValue((*i).alProperties[
-					aiPositions[3]].avList.front(),aiTypes[3]);
+				vOut.a = NormalizeColorValue(GetProperty((*i).alProperties,
+					aiPositions[3]).avList.front(),aiTypes[3]);
 			}
 
 			// and add them to our nice list
@@ -773,11 +792,11 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
 				// parse the list of vertex indices
 				if (0xFFFFFFFF != iProperty)
 				{
-					const unsigned int iNum = (unsigned int)(*i).alProperties[iProperty].avList.size();
+					const unsigned int iNum = (unsigned int)GetProperty((*i).alProperties, iProperty).avList.size();
 					sFace.mIndices.resize(iNum);
 
 					std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p = 
-						(*i).alProperties[iProperty].avList.begin();
+						GetProperty((*i).alProperties, iProperty).avList.begin();
 
 					for (unsigned int a = 0; a < iNum;++a,++p)
 					{
@@ -789,7 +808,7 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
 				if (0xFFFFFFFF != iMaterialIndex)
 				{
 					sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo<unsigned int>(
-						(*i).alProperties[iMaterialIndex].avList.front(),eType2);
+						GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2);
 				}
 				pvOut->push_back(sFace);
 			}
@@ -800,7 +819,7 @@ void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
 			// a value of -1 indicates a restart of the strip
 			bool flip = false;
 			for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
-				const std::vector<PLY::PropertyInstance::ValueUnion>& quak = (*i).alProperties[iProperty].avList;
+				const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty((*i).alProperties, iProperty).avList;
 				pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u));
 
 				int aiTable[2] = {-1,-1};
@@ -851,30 +870,30 @@ void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avL
 	if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
 	else
 	{
-		clrOut->r = NormalizeColorValue(avList[
-			aiPositions[0]].avList.front(),aiTypes[0]);
+		clrOut->r = NormalizeColorValue(GetProperty(avList,
+			aiPositions[0]).avList.front(),aiTypes[0]);
 	}
 
 	if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
 	else
 	{
-		clrOut->g = NormalizeColorValue(avList[
-			aiPositions[1]].avList.front(),aiTypes[1]);
+		clrOut->g = NormalizeColorValue(GetProperty(avList,
+			aiPositions[1]).avList.front(),aiTypes[1]);
 	}
 
 	if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
 	else
 	{
-		clrOut->b = NormalizeColorValue(avList[
-			aiPositions[2]].avList.front(),aiTypes[2]);
+		clrOut->b = NormalizeColorValue(GetProperty(avList,
+			aiPositions[2]).avList.front(),aiTypes[2]);
 	}
 
 	// assume 1.0 for the alpha channel ifit is not set
 	if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
 	else
 	{
-		clrOut->a = NormalizeColorValue(avList[
-			aiPositions[3]].avList.front(),aiTypes[3]);
+		clrOut->a = NormalizeColorValue(GetProperty(avList, 
+			aiPositions[3]).avList.front(),aiTypes[3]);
 	}
 }
 
@@ -1025,7 +1044,7 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
 			// handle phong power and shading mode
 			int iMode;
 			if (0xFFFFFFFF != iPhong)	{
-				float fSpec = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),ePhong);
+				float fSpec = PLY::PropertyInstance::ConvertTo<float>(GetProperty((*i).alProperties, iPhong).avList.front(),ePhong);
 
 				// if shininess is 0 (and the pow() calculation would therefore always
 				// become 1, not depending on the angle), use gouraud lighting
@@ -1043,7 +1062,7 @@ void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
 
 			// handle opacity
 			if (0xFFFFFFFF != iOpacity)	{
-				float fOpacity = PLY::PropertyInstance::ConvertTo<float>((*i).alProperties[iPhong].avList.front(),eOpacity);
+				float fOpacity = PLY::PropertyInstance::ConvertTo<float>(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity);
 				pcHelper->AddProperty<float>(&fOpacity, 1, AI_MATKEY_OPACITY);
 			}
 

+ 2 - 2
code/STLExporter.cpp

@@ -50,7 +50,7 @@ namespace Assimp	{
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Stereolithograpy. Prototyped and registered in Exporter.cpp
-void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	// invoke the exporter 
 	STLExporter exporter(pFile, pScene);
@@ -63,7 +63,7 @@ void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
 
 	outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
 }
-void ExportSceneSTLBinary(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneSTLBinary(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	// invoke the exporter 
 	STLExporter exporter(pFile, pScene, true);

+ 28 - 9
code/XFileExporter.cpp

@@ -59,7 +59,7 @@ namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
-void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
+void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
 {
 	std::string path = "";
 	std::string file = pFile;
@@ -78,13 +78,19 @@ void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pSce
 		}
 	}
 
+	// create/copy Properties
+	ExportProperties props(*pProperties);
+
+	// set standard properties if not set
+	if (!props.HasPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT)) props.SetPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT, false);
+
 	// invoke the exporter 
-	XFileExporter iDoTheExportThing( pScene, pIOSystem, path, file);
+	XFileExporter iDoTheExportThing( pScene, pIOSystem, path, file, &props);
 
 	// we're still here - export successfully completed. Write result to the given IOSYstem
 	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
 	if(outfile == NULL) {
-		throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
+		throw DeadlyExportError("could not open output .x file: " + std::string(pFile));
 	}
 
 	// XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
@@ -96,7 +102,7 @@ void ExportSceneXFile(const char* pFile,IOSystem* pIOSystem, const aiScene* pSce
 
 // ------------------------------------------------------------------------------------------------
 // Constructor for a specific scene to export
-XFileExporter::XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
+XFileExporter::XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file, const ExportProperties* pProperties) : mIOSystem(pIOSystem), mPath(path), mFile(file), mProperties(pProperties)
 {
 	// make sure that all formatting happens using the standard, C locale and not the user's current locale
 	mOutput.imbue( std::locale("C") );
@@ -126,7 +132,7 @@ void XFileExporter::WriteFile()
 {
 	// note, that all realnumber values must be comma separated in x files
 	mOutput.setf(std::ios::fixed);
-	mOutput.precision(6); // precission for float
+	mOutput.precision(16); // precission for double
 
 	// entry of writing the file
 	WriteHeader();
@@ -148,7 +154,10 @@ void XFileExporter::WriteFile()
 // Writes the asset header
 void XFileExporter::WriteHeader()
 {
-	mOutput << startstr << "xof 0303txt 0032" << endstr;
+	if (mProperties->GetPropertyBool(AI_CONFIG_EXPORT_XFILE_64BIT) == true)
+		mOutput << startstr << "xof 0303txt 0064" << endstr;
+	else
+		mOutput << startstr << "xof 0303txt 0032" << endstr;
 	mOutput << endstr;
 	mOutput << startstr << "template Frame {" << endstr;
 	PushTag();
@@ -298,7 +307,7 @@ void XFileExporter::WriteNode( aiNode* pNode)
 		ss << "Node_" << pNode;
 		pNode->mName.Set(ss.str());
 	}
-	mOutput << startstr << "Frame " << pNode->mName.C_Str() << " {" << endstr;
+	mOutput << startstr << "Frame " << toXFileString(pNode->mName) << " {" << endstr;
 
 	PushTag();
 
@@ -318,9 +327,9 @@ void XFileExporter::WriteNode( aiNode* pNode)
 	mOutput << startstr << "}" << endstr << endstr;
 }
 
-void XFileExporter::WriteMesh(const aiMesh* mesh)
+void XFileExporter::WriteMesh(aiMesh* mesh)
 {
-	mOutput << startstr << "Mesh " << mesh->mName.C_Str() << "_mShape" << " {" << endstr;
+	mOutput << startstr << "Mesh " << toXFileString(mesh->mName) << "_mShape" << " {" << endstr;
 
 	PushTag();
 
@@ -496,6 +505,16 @@ void XFileExporter::WriteMesh(const aiMesh* mesh)
 
 }
 
+std::string XFileExporter::toXFileString(aiString &name)
+{
+	std::string str = std::string(name.C_Str());
+	std::replace(str.begin(), str.end(), '<', '_');
+	std::replace(str.begin(), str.end(), '>', '_');
+	std::replace(str.begin(), str.end(), '{', '_');
+	std::replace(str.begin(), str.end(), '}', '_');
+	std::replace(str.begin(), str.end(), '$', '_');
+	return str;
+}
 
 void XFileExporter::writePath(aiString path)
 {

+ 8 - 2
code/XFileExporter.h

@@ -61,7 +61,7 @@ class XFileExporter
 {
 public:
 	/// Constructor for a specific scene to export
-	XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
+	XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file, const ExportProperties* pProperties);
 
 	/// Destructor
 	virtual ~XFileExporter();
@@ -80,7 +80,7 @@ protected:
 	void WriteNode( aiNode* pNode );
 
 	/// write a mesh entry of the scene
-	void WriteMesh(const aiMesh* mesh);
+	void WriteMesh( aiMesh* mesh);
 
 	/// Enters a new xml element, which increases the indentation
 	void PushTag() { startstr.append( "  "); }
@@ -94,6 +94,12 @@ public:
 
 protected:
 
+	/// normalize the name to be accepted by xfile readers
+	std::string toXFileString(aiString &name);
+
+	/// hold the properties pointer
+	const ExportProperties* mProperties;
+
 	/// write a path
 	void writePath(aiString path);	
 

+ 64 - 0
contrib/openddlparser/CMakeLists.txt

@@ -0,0 +1,64 @@
+CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
+PROJECT( OpenDDL-Parser )
+SET ( OPENDDL_PARSER_VERSION_MAJOR 0 )
+SET ( OPENDDL_PARSER_VERSION_MINOR 1 )
+SET ( OPENDDL_PARSER_VERSION_PATCH 0 )
+SET ( OPENDDL_PARSER_VERSION ${CPPCORE_VERSION_MAJOR}.${CPPCORE_VERSION_MINOR}.${CPPCORE_VERSION_PATCH} )
+SET ( PROJECT_VERSION "${OPENDDL_PARSER_VERSION}" )
+
+if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
+    find_package(Threads)
+else()
+    add_definitions( -D_CRT_SECURE_NO_WARNINGS )
+endif()
+
+add_definitions( -DOPENDDLPARSER_BUILD )
+add_definitions( -DOPENDDL_NO_USE_CPP11 )
+add_definitions( -D_VARIADIC_MAX=10 )
+
+INCLUDE_DIRECTORIES(
+    ./
+    include/
+    contrib/gtest-1.7.0/include
+    contrib/gtest-1.7.0/
+)
+
+link_directories(
+    ./
+)
+
+SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib )
+SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib )
+SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin )
+
+if( WIN32 AND NOT CYGWIN )
+  set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" )  # Force to always compile with W4
+  if( CMAKE_CXX_FLAGS MATCHES "/W[0-4]" )
+    string( REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" )
+  else()
+    set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4" )
+  endif()
+elseif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
+  # Update if necessary
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++0x")
+elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++11")
+endif()
+
+SET ( openddl_parser_src
+    code/OpenDDLParser.cpp
+    code/DDLNode.cpp
+    code/Value.cpp
+    include/openddlparser/OpenDDLParser.h
+    include/openddlparser/OpenDDLParserUtils.h
+    include/openddlparser/OpenDDLCommon.h
+    include/openddlparser/DDLNode.h
+    include/openddlparser/Value.h
+    README.md
+)
+ 
+SOURCE_GROUP( code            FILES ${openddl_parser_src} )
+
+ADD_LIBRARY( openddl_parser SHARED
+    ${openddl_parser_src}
+)

+ 111 - 0
contrib/openddlparser/README.md

@@ -0,0 +1,111 @@
+The OpenDDL-Parser
+==================
+
+A simple and fast OpenDDL Parser
+Current build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser)
+
+Get the source code
+===================
+You can get the code from our git repository, which is located at GitHub. You can clone the repository like:
+
+> git clone https://github.com/kimkulling/openddl-parser.git
+
+Build from repo
+===============
+To build the library you need to install cmake first ( see http://www.cmake.org/ for more information ). Make also sure that a compiler toolchain is installed on your machine.
+After installing it you can open a console and type:
+
+> cmake CMakeLists.txt
+
+This command will generate a build environment for your installed build enrironment ( for Visual Studio the project files will be generated, for gcc the makefiles will be generated ).
+When using an IDE open the IDE and run the build. When using GNU-make type in your console:
+
+> make
+
+and that's all.
+
+Use the library
+===============
+To use the OpenDDL-parser you need to build the lib first. Now add the 
+> <Repo-folder>/include 
+
+to your include-path and the 
+
+> <Repo-folder>/lib
+
+to your lib-folder. Link the openddl.lib to your application. 
+
+Here is a small example how to use the lib:
+
+```cpp
+
+#include <iostream>
+#include <cassert>
+#include <openddlparser/OpenDDLParser.h>
+
+USE_ODDLPARSER_NS;
+
+int main( int argc, char *argv[] ) {
+    if( argc < 3 ) {
+        return 1;
+    }
+
+    char *filename( nullptr );
+    if( 0 == strncmp( FileOption, argv[ 1 ], strlen( FileOption ) ) ) {
+        filename = argv[ 2 ];
+    }
+    std::cout << "file to import: " << filename << std::endl;   
+    if( nullptr == filename ) {
+        std::cerr << "Invalid filename." << std::endl;
+        return Error;
+    }
+
+    FILE *fileStream = fopen( filename, "r+" );
+    if( NULL == filename ) {
+        std::cerr << "Cannot open file " << filename << std::endl;
+        return 1;
+    }
+
+    // obtain file size:
+    fseek( fileStream, 0, SEEK_END );
+    const size_t size( ftell( fileStream ) );   
+    rewind( fileStream );   
+    if( size > 0 ) {
+        char *buffer = new char[ size ];
+        const size_t readSize( fread( buffer, sizeof( char ), size, fileStream ) );
+        assert( readSize == size );
+        OpenDDLParser theParser;
+        theParser.setBuffer( buffer, size );
+        const bool result( theParser.parse() );
+        if( !result ) {
+            std::cerr << "Error while parsing file " << filename << "." << std::endl;
+        }
+    }
+    return 0;
+}
+
+```
+
+How to access the imported data
+===============================
+The data is organized as a tree. You can get the root tree with the following code:
+
+```
+OpenDDLParser theParser;
+theParser.setBuffer( buffer, size );
+const bool result( theParser.parse() );
+if ( result ) {
+    DDLNode *root = theParser.getRoot();
+
+    DDLNode::DllNodeList childs = root->getChildNodeList();
+    for ( size_t i=0; i<childs.size(); i++ ) {
+        DDLNode *child = childs[ i ];
+        Property *prop = child->getProperty(); // to get properties
+        std:.string type = child->getType();   // to get the node type
+        Value *values = child->getValue();     // to get the data;
+    }
+}
+
+```
+
+The instance called root contains the data.

+ 184 - 0
contrib/openddlparser/code/DDLNode.cpp

@@ -0,0 +1,184 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#include <openddlparser/DDLNode.h>
+#include <openddlparser/OpenDDLParser.h>
+
+#include <algorithm>
+
+BEGIN_ODDLPARSER_NS
+
+DDLNode::DllNodeList DDLNode::s_allocatedNodes;
+
+template<class T>
+inline
+static void releaseDataType( T *ptr ) {
+    if( ddl_nullptr == ptr ) {
+        return;
+    }
+
+    T *current( ddl_nullptr );
+    while( ptr ) {
+        current = ptr;
+        ptr = ptr->m_next;
+        delete current;
+    }
+}
+
+static void releaseReferencedNames( Reference *ref ) {
+    if( ddl_nullptr == ref ) {
+        return;
+    }
+
+    if( ref->m_referencedName ) {
+        for( size_t i = 0; i < ref->m_numRefs; i++ ) {
+            delete ref->m_referencedName;
+        }
+    }
+}
+
+DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent )
+: m_type( type )
+, m_name( name )
+, m_parent( parent )
+, m_children()
+, m_properties( ddl_nullptr )
+, m_value( ddl_nullptr )
+, m_dtArrayList( ddl_nullptr )
+, m_references( ddl_nullptr )
+, m_idx( idx ) {
+    if( m_parent ) {
+        m_parent->m_children.push_back( this );
+    }
+}
+
+DDLNode::~DDLNode() {
+    releaseDataType<Property>( m_properties );
+    releaseDataType<Value>( m_value );
+    releaseReferencedNames( m_references );
+
+    delete m_dtArrayList;
+    m_dtArrayList = ddl_nullptr;
+    if( s_allocatedNodes[ m_idx ] == this ) {
+        s_allocatedNodes[ m_idx ] = ddl_nullptr;
+    }
+}
+
+void DDLNode::attachParent( DDLNode *parent ) {
+    if( m_parent == parent ) {
+        return;
+    }
+
+    m_parent = parent;
+    if( ddl_nullptr != m_parent ) {
+        m_parent->m_children.push_back( this );
+    }
+}
+
+void DDLNode::detachParent() {
+    if( m_parent ) {
+        std::vector<DDLNode*>::iterator it;
+        it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this );
+        if( m_parent->m_children.end() != it ) {
+            m_parent->m_children.erase( it );
+        }
+        m_parent = ddl_nullptr;
+    }
+}
+
+DDLNode *DDLNode::getParent() const {
+    return m_parent;
+}
+
+const DDLNode::DllNodeList &DDLNode::getChildNodeList() const {
+    return m_children;
+}
+
+void DDLNode::setType( const std::string &type ) {
+    m_type = type;
+}
+
+const std::string &DDLNode::getType() const {
+    return m_type;
+}
+
+
+void DDLNode::setName( const std::string &name ) {
+    m_name = name;
+}
+
+const std::string &DDLNode::getName() const {
+    return m_name;
+}
+
+void DDLNode::setProperties( Property *prop ) {
+    m_properties = prop;
+}
+
+Property *DDLNode::getProperties() const {
+    return m_properties;
+}
+
+void DDLNode::setValue( Value *val ) {
+    m_value = val;
+}
+
+Value *DDLNode::getValue() const {
+    return m_value;
+}
+
+void DDLNode::setDataArrayList( DataArrayList  *dtArrayList ) {
+    m_dtArrayList = dtArrayList;
+}
+
+DataArrayList *DDLNode::getDataArrayList() const {
+    return m_dtArrayList;
+}
+
+void DDLNode::setReferences( Reference *refs ) {
+    m_references = refs;
+}
+
+Reference *DDLNode::getReferences() const {
+    return m_references;
+}
+
+DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLNode *parent ) {
+    const size_t idx( s_allocatedNodes.size() );
+    DDLNode *node = new DDLNode( type, name, idx, parent );
+    s_allocatedNodes.push_back( node );
+    
+    return node;
+}
+
+void DDLNode::releaseNodes() {
+    if( s_allocatedNodes.size() > 0 ) {
+        for( DllNodeList::iterator it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) {
+            if( *it ) {
+                delete *it;
+            }
+        }
+        s_allocatedNodes.clear();
+    }
+}
+
+END_ODDLPARSER_NS

+ 900 - 0
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -0,0 +1,900 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#include <openddlparser/OpenDDLParser.h>
+
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <math.h>
+
+#ifdef _WIN32
+#  include <windows.h>
+#endif // _WIN32
+
+#define DEBUG_HEADER_NAME 
+
+BEGIN_ODDLPARSER_NS
+
+static const char *Version = "0.1.0";
+
+namespace Grammar {
+    static const char *OpenBracketToken   = "{";
+    static const char *CloseBracketToken  = "}";
+    static const char *OpenPropertyToken  = "(";
+    static const char *ClosePropertyToken = ")";
+    static const char *BoolTrue           = "true";
+    static const char *BoolFalse          = "false";
+    static const char *RefToken           = "ref";
+
+    static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = {
+        "bool",
+        "int8",
+        "int16",
+        "int32",
+        "int64",
+        "unsigned_int8",
+        "unsigned_int16",
+        "unsigned_int32",
+        "unsigned_int64",
+        "half",
+        "float",
+        "double",
+        "string",
+        "ref"
+    };
+} // Namespace Grammar
+
+
+static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) {
+    std::stringstream stream;
+    stream << "Invalid token " << *in << ", " << exp << " expected." << std::endl;
+    callback( ddl_error_msg, stream.str() );
+}
+
+static bool isIntegerType( Value::ValueType integerType ) {
+    if( integerType != Value::ddl_int8 && integerType != Value::ddl_int16 && 
+            integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) {
+        return false;
+    }
+
+    return true;
+}
+
+static DDLNode *createDDLNode( Identifier *id, OpenDDLParser *parser ) {
+    if( ddl_nullptr == id || ddl_nullptr == parser ) {
+        return ddl_nullptr;
+    }
+
+    const std::string type( id->m_buffer );
+    DDLNode *parent( parser->top() );
+    DDLNode *node = DDLNode::create( type, "", parent );
+
+    return node;
+}
+
+static void logMessage( LogSeverity severity, const std::string &msg ) {
+    std::string log;
+    if( ddl_debug_msg == severity ) {
+        log += "Debug:";
+    } else if( ddl_info_msg == severity ) {
+        log += "Info :";
+    } else if( ddl_warn_msg == severity ) {
+        log += "Warn :";
+    } else if( ddl_error_msg == severity ) {
+        log += "Error:";
+    } else {
+        log += "None :";
+    }
+
+    log += msg;
+    std::cout << log;
+}
+
+OpenDDLParser::OpenDDLParser()
+: m_logCallback( logMessage )
+, m_buffer()
+, m_stack()
+, m_context( ddl_nullptr ) {
+    // empty
+}
+
+OpenDDLParser::OpenDDLParser( char *buffer, size_t len )
+: m_logCallback( &logMessage )
+, m_buffer()
+, m_context( ddl_nullptr ) {
+    if( 0 != len ) {
+        setBuffer( buffer, len );
+    }
+}
+
+OpenDDLParser::~OpenDDLParser() {
+    clear();
+}
+
+void OpenDDLParser::setLogCallback( logCallback callback ) {
+    if( ddl_nullptr != callback ) {
+        // install user-specific log callback
+        m_logCallback = callback;
+    } else {
+        // install default log callback
+        m_logCallback = &logMessage;
+    }
+}
+
+OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {
+    return m_logCallback;
+}
+
+void OpenDDLParser::setBuffer( char *buffer, size_t len ) {
+    clear();
+    if( 0 == len ) {
+        return;
+    }
+
+    m_buffer.resize( len );
+    ::memcpy(&m_buffer[ 0 ], buffer, len );
+}
+
+void OpenDDLParser::setBuffer( const std::vector<char> &buffer ) {
+    clear();
+    m_buffer.resize( buffer.size() );
+    std::copy( buffer.begin(), buffer.end(), m_buffer.begin() );
+}
+
+const char *OpenDDLParser::getBuffer() const {
+    if( m_buffer.empty() ) {
+        return ddl_nullptr;
+    }
+
+    return &m_buffer[ 0 ];
+}
+
+size_t OpenDDLParser::getBufferSize() const {
+    return m_buffer.size();
+}
+
+void OpenDDLParser::clear() {
+    m_buffer.resize( 0 );
+    if( m_context ) {
+        m_context->m_root = ddl_nullptr;
+    }
+
+    DDLNode::releaseNodes();
+}
+
+bool OpenDDLParser::parse() {
+    if( m_buffer.empty() ) {
+        return false;
+    }
+    
+    normalizeBuffer( m_buffer );
+
+    std::cout << &m_buffer[0] << std::endl;
+
+    m_context = new Context;
+    m_context->m_root = DDLNode::create( "root", "", ddl_nullptr );
+    pushNode( m_context->m_root );
+
+    // do the main parsing
+    char *current( &m_buffer[ 0 ] );
+    char *end( &m_buffer[ m_buffer.size() - 1 ] + 1 );
+    size_t pos( current - &m_buffer[ 0 ] );
+    while( pos < m_buffer.size() ) {
+        current = parseNextNode( current, end );
+        pos = current - &m_buffer[ 0 ];
+    }
+    return true;
+}
+
+char *OpenDDLParser::parseNextNode( char *in, char *end ) {
+    in = parseHeader( in, end );
+    in = parseStructure( in, end );
+
+    return in;
+}
+
+static void dumpId( Identifier *id ) {
+    if( ddl_nullptr != id ) {
+        std::cout << id->m_buffer << std::endl;
+    }
+}
+
+char *OpenDDLParser::parseHeader( char *in, char *end ) {
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    Identifier *id( ddl_nullptr );
+    in = OpenDDLParser::parseIdentifier( in, end, &id );
+
+#ifdef DEBUG_HEADER_NAME    
+    dumpId( id );
+#endif // DEBUG_HEADER_NAME
+
+    in = lookForNextToken( in, end );
+    Property *first( ddl_nullptr );
+    if( ddl_nullptr != id ) {
+        if( *in == '(' ) {
+            in++;
+            Property *prop( ddl_nullptr ), *prev( ddl_nullptr );
+            while( *in != ')' && in != end ) {
+                in = OpenDDLParser::parseProperty( in, end, &prop );
+                in = lookForNextToken( in, end );
+
+                if( *in != ',' && *in != ')' ) {
+                    logInvalidTokenError( in, ")", m_logCallback );
+                    return in;
+                }
+                
+                if( ddl_nullptr != prop && *in != ',' ) {
+                    if( ddl_nullptr == first ) {
+                        first = prop;
+                    }
+                    if( ddl_nullptr != prev ) {
+                        prev->m_next = prop;
+                    }
+                    prev = prop;
+                }
+            }
+            in++;
+        }
+
+        // store the node
+        DDLNode *node( createDDLNode( id, this ) );
+        if( ddl_nullptr != node ) {
+            pushNode( node );
+        } else {
+            std::cerr << "nullptr returned by creating DDLNode." << std::endl;
+        }
+
+        // set the properties
+        if( ddl_nullptr != first ) {
+            node->setProperties( first );
+        }
+
+        Name *name( ddl_nullptr );
+        in = OpenDDLParser::parseName( in, end, &name );
+        if( ddl_nullptr != name ) {
+            const std::string nodeName( name->m_id->m_buffer );
+            node->setName( nodeName );
+        }
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseStructure( char *in, char *end ) {
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    bool error( false );
+    in = lookForNextToken( in, end );
+    if( *in == '{' ) {
+        // loop over all children ( data and nodes )
+        do {
+            in = parseStructureBody( in, end, error );
+        } while ( *in != '}' );
+        in++;
+    } else {
+        in++;
+        logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback );
+        error = true;
+        return in;
+    }
+    in = lookForNextToken( in, end );
+    
+    // pop node from stack after successful parsing
+    if( !error ) {
+        popNode();
+    }
+
+    return in;
+}
+
+static void setNodeValues( DDLNode *currentNode, Value *values ) {
+    if( ddl_nullptr != values ){
+        if( ddl_nullptr != currentNode ) {
+            currentNode->setValue( values );
+        }
+    }
+}
+
+static void setNodeReferences( DDLNode *currentNode, Reference *refs ) {
+    if( ddl_nullptr != refs ) {
+        if( ddl_nullptr != currentNode ) {
+            currentNode->setReferences( refs );
+        }
+    }
+}
+
+static void setNodeDataArrayList( DDLNode *currentNode, DataArrayList *dtArrayList ) {
+    if( ddl_nullptr != dtArrayList ) {
+        if( ddl_nullptr != currentNode ) {
+            currentNode->setDataArrayList( dtArrayList );
+        }
+    }
+}
+
+char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) {
+    if( !isNumeric( *in ) && !isCharacter( *in ) ) {
+        in++;
+    }
+
+    in = lookForNextToken( in, end );
+    Value::ValueType type( Value::ddl_none );
+    size_t arrayLen( 0 );
+    in = OpenDDLParser::parsePrimitiveDataType( in, end, type, arrayLen );
+    if( Value::ddl_none != type ) {
+        // parse a primitive data type
+        in = lookForNextToken( in, end );
+        if( *in == '{' ) {
+            Reference *refs( ddl_nullptr );
+            DataArrayList *dtArrayList( ddl_nullptr );
+            Value *values( ddl_nullptr );
+            if( 1 == arrayLen ) {
+                size_t numRefs( 0 ), numValues( 0 );
+                in = parseDataList( in, end, &values, numValues, &refs, numRefs );
+                setNodeValues( top(), values );
+                setNodeReferences( top(), refs );
+            } else if( arrayLen > 1 ) {
+                in = parseDataArrayList( in, end, &dtArrayList );
+                setNodeDataArrayList( top(), dtArrayList );
+            } else {
+                std::cerr << "0 for array is invalid." << std::endl;
+                error = true;
+            }
+        }
+
+        in = lookForNextToken( in, end );
+        if( *in != '}' ) {
+            logInvalidTokenError( in, std::string( Grammar::CloseBracketToken ), m_logCallback );
+        } else {
+            //in++;
+        }
+    } else {
+        // parse a complex data type
+        in = parseNextNode( in, end );
+    }
+
+    return in;
+}
+
+void OpenDDLParser::pushNode( DDLNode *node ) {
+    if( ddl_nullptr == node ) {
+        return;
+    }
+
+    m_stack.push_back( node );
+}
+
+DDLNode *OpenDDLParser::popNode() {
+    if( m_stack.empty() ) {
+        return ddl_nullptr;
+    }
+
+    DDLNode *topNode( top() );
+    m_stack.pop_back();
+
+    return topNode;
+}
+
+DDLNode *OpenDDLParser::top() {
+    if( m_stack.empty() ) {
+        return ddl_nullptr;
+    }
+    
+    DDLNode *top( m_stack.back() );
+    return top;
+}
+
+DDLNode *OpenDDLParser::getRoot() const {
+    if( ddl_nullptr == m_context ) {
+        return ddl_nullptr;
+    }
+
+    return m_context->m_root;
+}
+
+Context *OpenDDLParser::getContext() const {
+    return m_context;
+}
+
+void OpenDDLParser::normalizeBuffer( std::vector<char> &buffer) {
+    if( buffer.empty() ) {
+        return;
+    }
+
+    std::vector<char> newBuffer;
+    const size_t len( buffer.size() );
+    char *end( &buffer[ len-1 ] + 1 );
+    for( size_t readIdx = 0; readIdx<len; ++readIdx ) {
+        char *c( &buffer[readIdx] );
+        // check for a comment
+        if( !isComment<char>( c, end ) && !isNewLine( *c ) ) {
+            newBuffer.push_back( buffer[ readIdx ] );
+        } else {
+            if( isComment<char>( c, end ) ) {
+                readIdx++;
+                // skip the comment and the rest of the line
+                while( !isEndofLine( buffer[ readIdx ] ) ) {
+                    readIdx++;
+                }
+            }
+        }
+    }
+    buffer = newBuffer;
+}
+
+char *OpenDDLParser::parseName( char *in, char *end, Name **name ) {
+    *name = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    // ignore blanks
+    in = lookForNextToken( in, end );
+    if( *in != '$' && *in != '%' ) {
+        return in;
+    }
+
+    NameType ntype( GlobalName );
+    if( *in == '%' ) {
+        ntype = LocalName;
+    }
+
+    Name *currentName( ddl_nullptr );
+    Identifier *id( ddl_nullptr );
+    in = parseIdentifier( in, end, &id );
+    if( id ) {
+        currentName = new Name( ntype, id );
+        if( currentName ) {
+            *name = currentName;
+        }
+    }
+    
+    return in;
+}
+
+char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) {
+    *id = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    // ignore blanks
+    in = lookForNextToken( in, end );
+    
+    // staring with a number is forbidden
+    if( isNumeric<const char>( *in ) ) {
+        return in;
+    }
+
+    // get size of id
+    size_t idLen( 0 );
+    char *start( in );
+    while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != '(' && *in != ')' ) {
+        in++;
+        idLen++;
+    }
+    
+    const size_t len( idLen + 1 );
+    Identifier *newId = new Identifier( len, new char[ len ] );
+    ::strncpy( newId->m_buffer, start, newId->m_len-1 );
+    newId->m_buffer[ newId->m_len - 1 ] = '\0';
+    *id = newId;
+
+    return in;
+}
+
+char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueType &type, size_t &len ) {
+    type = Value::ddl_none;
+    len = 0;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    size_t prim_len( 0 );
+    for( unsigned int i = 0; i < Value::ddl_types_max; i++ ) {
+        prim_len = strlen( Grammar::PrimitiveTypeToken[ i ] );
+        if( 0 == strncmp( in, Grammar::PrimitiveTypeToken[ i ], prim_len ) ) {
+            type = ( Value::ValueType ) i;
+            break;
+        }
+    }
+
+    if( Value::ddl_none == type ) {
+        in = lookForNextToken( in, end );
+        return in;
+    } else {
+        in += prim_len;
+    }
+
+    bool ok( true );
+    if( *in == '[' ) {
+        ok = false;
+        in++;
+        char *start( in );
+        while ( in != end ) {
+            in++;
+            if( *in == ']' ) {
+                len = atoi( start );
+                ok = true;
+                in++;
+                break;
+            }
+        }
+    } else {
+        len = 1;
+    }
+    if( !ok ) {
+        type = Value::ddl_none;
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseReference( char *in, char *end, std::vector<Name*> &names ) {
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    Name *nextName( ddl_nullptr );
+    in = parseName( in, end, &nextName );
+    if( nextName ) {
+        names.push_back( nextName );
+    }
+    while( ',' == *in ) {
+        in = getNextSeparator( in, end );
+        if( ',' == *in ) {
+            in = parseName( in, end, &nextName );
+            if( nextName ) {
+                names.push_back( nextName );
+            }
+        } else {
+            break;
+        }
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseBooleanLiteral( char *in, char *end, Value **boolean ) {
+    *boolean = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    char *start( in );
+    size_t len( 0 );
+    while( !isSeparator( *in ) && in != end ) {
+        in++;
+        len++;
+    }
+    len++;
+    int res = ::strncmp( Grammar::BoolTrue, start, strlen( Grammar::BoolTrue ) );
+    if( 0 != res ) {
+        res = ::strncmp( Grammar::BoolFalse, start, strlen( Grammar::BoolFalse ) );
+        if( 0 != res ) {
+            *boolean = ddl_nullptr;
+            return in;
+        }
+        *boolean = ValueAllocator::allocPrimData( Value::ddl_bool );
+        (*boolean)->setBool( false );
+    } else {
+        *boolean = ValueAllocator::allocPrimData( Value::ddl_bool );
+        (*boolean)->setBool( true );
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, Value::ValueType integerType ) {
+    *integer = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    if( !isIntegerType( integerType ) ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    char *start( in );
+    while( !isSeparator( *in ) && in != end ) {
+        in++;
+    }
+
+    if( isNumeric( *start ) ) {
+        const int value( atoi( start ) );
+        *integer = ValueAllocator::allocPrimData( integerType );
+        switch( integerType ) {
+            case Value::ddl_int8:
+                    ( *integer )->setInt8( (int8) value );
+                    break;
+            case Value::ddl_int16:
+                    ( *integer )->setInt16( ( int16 ) value );
+                    break;
+            case Value::ddl_int32:
+                    ( *integer )->setInt32( ( int32 ) value );
+                    break;
+            case Value::ddl_int64:
+                    ( *integer )->setInt64( ( int64 ) value );
+                    break;
+            default:
+                break;
+        }
+    } 
+
+    return in;
+}
+
+char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating ) {
+    *floating = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    char *start( in );
+    while( !isSeparator( *in ) && in != end ) {
+        in++;
+    }
+
+    // parse the float value
+    bool ok( false );
+    if( isNumeric( *start ) ) {
+        ok = true;
+    } else {
+        if( *start == '-' ) {
+            if( isNumeric( *(start+1) ) ) {
+                ok = true;
+            }
+        }
+    }
+
+    if( ok ) {
+        const float value( ( float ) atof( start ) );
+        *floating = ValueAllocator::allocPrimData( Value::ddl_float );
+        ( *floating )->setFloat( value );
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData ) {
+    *stringData = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    size_t len( 0 );
+    char *start( in );
+    if( *start == '\"' ) {
+        start++;
+        in++;
+        while( *in != '\"' && in != end ) {
+            in++;
+            len++;
+        }
+
+        *stringData = ValueAllocator::allocPrimData( Value::ddl_string, len );
+        ::strncpy( ( char* ) ( *stringData )->m_data, start, len );
+        ( *stringData )->m_data[len] = '\0';
+        in++;
+    }
+
+    return in;
+}
+
+static void createPropertyWithData( Identifier *id, Value *primData, Property **prop ) {
+    if( ddl_nullptr != primData ) {
+        ( *prop ) = new Property( id );
+        ( *prop )->m_primData = primData;
+    }
+}
+
+char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) {
+    *data = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    if( *in != '0' ) {
+        return in;
+    }
+
+    in++;
+    if( *in != 'x' && *in != 'X' ) {
+        return in;
+    }
+
+    in++;
+    bool ok( true );
+    char *start( in );
+    int pos( 0 );
+    while( !isSeparator( *in ) && in != end ) {
+        if( ( *in < '0' && *in > '9' ) || ( *in < 'a' && *in > 'f' ) || ( *in < 'A' && *in > 'F' ) ) {
+            ok = false;
+            break;
+        }
+        pos++;
+        in++;
+    }
+
+    if( !ok ) {
+        return in;
+    }
+
+    int value( 0 );
+    while( pos > 0 ) {
+        pos--;
+        value += hex2Decimal( *start ) * static_cast<int>( pow( 16.0, pos ) );
+        start++;
+    }
+
+    *data = ValueAllocator::allocPrimData( Value::ddl_int32 );
+    (*data)->setInt32( value );
+
+    return in;
+}
+
+char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) {
+    *prop = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    Identifier *id( ddl_nullptr );
+    in = parseIdentifier( in, end, &id );
+    if( ddl_nullptr != id ) {
+        in = lookForNextToken( in, end );
+        if( *in == '=' ) {
+            in++;
+            in = getNextToken( in, end );
+            Value *primData( ddl_nullptr );
+            if( isInteger( in, end ) ) {
+                in = parseIntegerLiteral( in, end, &primData );
+                createPropertyWithData( id, primData, prop );
+            } else if( isFloat( in, end ) ) {
+                in = parseFloatingLiteral( in, end, &primData );
+                createPropertyWithData( id, primData, prop );
+            } else if( isStringLiteral( *in ) ) { // string data
+                in = parseStringLiteral( in, end, &primData );
+                createPropertyWithData( id, primData, prop );
+            } else {                          // reference data
+                std::vector<Name*> names;
+                in = parseReference( in, end, names );
+                if( !names.empty() ) {
+                    Reference *ref = new Reference( names.size(), &names[ 0 ] );
+                    ( *prop ) = new Property( id );
+                    ( *prop )->m_ref = ref;
+                }
+            }
+        } 
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) {
+    *data = ddl_nullptr;
+    numValues = numRefs = 0;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    if( *in == '{' ) {
+        in++;
+        Value *current( ddl_nullptr ), *prev( ddl_nullptr );
+        while( '}' != *in ) {
+            current = ddl_nullptr;
+            in = lookForNextToken( in, end );
+            if( isInteger( in, end ) ) {
+                in = parseIntegerLiteral( in, end, &current );
+            } else if( isFloat( in, end ) ) {
+                in = parseFloatingLiteral( in, end, &current );
+            } else if( isStringLiteral( *in ) ) {
+                in = parseStringLiteral( in, end, &current );
+            } else if( isHexLiteral( in, end ) ) {
+                in = parseHexaLiteral( in, end, &current );
+            } else {                          // reference data
+                std::vector<Name*> names;
+                in = parseReference( in, end, names );
+                if( !names.empty() ) {
+                    Reference *ref = new Reference( names.size(), &names[ 0 ] );
+                    *refs = ref;
+                    numRefs = names.size();
+                }
+            }
+
+            if( ddl_nullptr != current ) {
+                if( ddl_nullptr == *data ) {
+                    *data = current;
+                    prev = current;
+                } else {
+                    prev->setNext( current );
+                    prev = current;
+                }
+                numValues++;
+            }
+
+            in = getNextSeparator( in, end );
+            if( ',' != *in && '}' != *in && !isSpace( *in ) ) {
+                break;
+            }
+        }
+        in++;
+    }
+
+    return in;
+}
+
+char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **dataList ) {
+    *dataList = ddl_nullptr;
+    if( ddl_nullptr == in || in == end ) {
+        return in;
+    }
+
+    in = lookForNextToken( in, end );
+    if( *in == Grammar::OpenBracketToken[ 0 ] ) {
+        in++;
+        Value *current( ddl_nullptr );
+        Reference *refs( ddl_nullptr );
+        DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr );
+        do {
+            size_t numRefs( 0 ), numValues( 0 );
+            in = parseDataList( in, end, &current, numValues, &refs, numRefs );
+            if( ddl_nullptr != current ) {
+                if( ddl_nullptr == prev ) {
+                    *dataList = new DataArrayList;
+                    ( *dataList )->m_dataList = current;
+                    ( *dataList )->m_numItems = numValues;
+                    prev = *dataList;
+                } else {
+                    currentDataList = new DataArrayList;
+                    if( ddl_nullptr != prev ) {
+                        prev->m_next = currentDataList;
+                        prev = currentDataList;
+                    }
+                }
+            }
+        } while( ',' == *in && in != end );
+        in = lookForNextToken( in, end );
+        in++;
+    }
+
+    return in;
+}
+
+const char *OpenDDLParser::getVersion() {
+    return Version;
+}
+
+END_ODDLPARSER_NS

+ 256 - 0
contrib/openddlparser/code/Value.cpp

@@ -0,0 +1,256 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#include <openddlparser/Value.h>
+
+#include <iostream>
+#include <cassert>
+
+BEGIN_ODDLPARSER_NS
+
+Value::Value()
+: m_type( ddl_none )
+, m_size( 0 )
+, m_data( ddl_nullptr )
+, m_next( ddl_nullptr ) {
+    // empty
+}
+
+Value::~Value() {
+    // empty
+}
+
+void Value::setBool( bool value ) {
+    assert( ddl_bool == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+bool Value::getBool() {
+    assert( ddl_bool == m_type );
+    return ( bool ) ( *m_data );
+}
+
+void Value::setInt8( int8 value ) {
+    assert( ddl_int8 == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+int8 Value::getInt8() {
+    assert( ddl_int8 == m_type );
+    return ( int8 ) ( *m_data );
+}
+
+void Value::setInt16( int16 value ) {
+    assert( ddl_int16 == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+int16 Value::getInt16() {
+    assert( ddl_int16 == m_type );
+    return ( int16 ) ( *m_data );
+}
+
+void Value::setInt32( int32 value ) {
+    assert( ddl_int32 == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+int32 Value::getInt32() {
+    assert( ddl_int32 == m_type );
+    return ( int32 ) ( *m_data );
+}
+
+void Value::setInt64( int64 value ) {
+    assert( ddl_int32 == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+int64 Value::getInt64() {
+    return ( int64 ) ( *m_data );
+}
+
+void Value::setFloat( float value ) {
+    assert( ddl_float == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+float Value::getFloat() const {
+    float v;
+    ::memcpy( &v, m_data, m_size );
+    return v;
+}
+
+void Value::setDouble( double value ) {
+    assert( ddl_double == m_type );
+    ::memcpy( m_data, &value, m_size );
+}
+
+double Value::getDouble() const {
+    double v;
+    ::memcpy( &v, m_data, m_size );
+    return v;
+}
+
+void Value::setString( const std::string &str ) {
+    assert( ddl_string == m_type );
+    ::memcpy( m_data, str.c_str(), str.size() );
+    m_data[ str.size() ] = '\0';
+}
+const char *Value::getString() const {
+    return (const char*) m_data;
+}
+
+void Value::dump() {
+    switch( m_type ) {
+    case ddl_none:
+        std::cout << "None" << std::endl;
+        break;
+    case ddl_bool:
+        std::cout << getBool() << std::endl;
+        break;
+    case ddl_int8:
+        std::cout << getInt8() << std::endl;
+        break;
+    case ddl_int16:
+        std::cout << getInt16() << std::endl;
+        break;
+    case ddl_int32:
+        std::cout << getInt32() << std::endl;
+        break;
+    case ddl_int64:
+        std::cout << getInt64() << std::endl;
+        break;
+    case ddl_unsigned_int8:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_unsigned_int16:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_unsigned_int32:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_unsigned_int64:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_half:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_float:
+        std::cout << getFloat() << std::endl;
+        break;
+    case ddl_double:
+        std::cout << getDouble() << std::endl;
+        break;
+    case ddl_string:
+        std::cout << "Not supported" << std::endl;
+        break;
+    case ddl_ref:
+        std::cout << "Not supported" << std::endl;
+        break;
+    default:
+        break;
+    }
+}
+
+void Value::setNext( Value *next ) {
+    m_next = next;
+}
+
+Value *Value::getNext() const {
+    return m_next;
+}
+
+Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
+    if( type == Value::ddl_none || Value::ddl_types_max == type ) {
+        return ddl_nullptr;
+    }
+
+    Value *data = new Value;
+    data->m_type = type;
+    switch( type ) {
+        case Value::ddl_bool:
+            data->m_size = sizeof( bool );
+            break;
+        case Value::ddl_int8:
+            data->m_size = sizeof( char );
+            break;
+        case Value::ddl_int16:
+            data->m_size = sizeof( short );
+            break;
+        case Value::ddl_int32:
+            data->m_size = sizeof( int );
+            break;
+        case Value::ddl_int64:
+            data->m_size = sizeof( long );
+            break;
+        case Value::ddl_unsigned_int8:
+            data->m_size = sizeof( unsigned char );
+            break;
+        case Value::ddl_unsigned_int32:
+            data->m_size = sizeof( unsigned int );
+            break;
+        case Value::ddl_unsigned_int64:
+            data->m_size = sizeof( unsigned long );
+            break;
+        case Value::ddl_half:
+            data->m_size = sizeof( short );
+            break;
+        case Value::ddl_float:
+            data->m_size = sizeof( float );
+            break;
+        case Value::ddl_double:
+            data->m_size = sizeof( double );
+            break;
+        case Value::ddl_string:
+            data->m_size = sizeof( char );
+            break;
+        case Value::ddl_ref:
+            data->m_size = sizeof( char );
+            break;
+        case Value::ddl_none:
+        case Value::ddl_types_max:
+        default:
+            break;
+    }
+
+    if( data->m_size ) {
+        size_t len1( len );
+        if( Value::ddl_string == type ) {
+            len1++;
+        }
+        data->m_size *= len1;
+        data->m_data = new unsigned char[ data->m_size ];
+    }
+
+    return data;
+}
+
+void ValueAllocator::releasePrimData( Value **data ) {
+    if( !data ) {
+        return;
+    }
+
+    delete *data;
+    *data = ddl_nullptr;
+}
+
+END_ODDLPARSER_NS

+ 90 - 0
contrib/openddlparser/include/openddlparser/DDLNode.h

@@ -0,0 +1,90 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef OPENDDLPARSER_DDLNODE_H_INC
+#define OPENDDLPARSER_DDLNODE_H_INC
+
+#include <openddlparser/OpenDDLCommon.h>
+
+#include <vector>
+#include <string>
+
+BEGIN_ODDLPARSER_NS
+
+class Value;
+class OpenDDLParser;
+
+struct Identifier;
+struct Reference;
+struct Property;
+struct DataArrayList;
+
+class DLL_ODDLPARSER_EXPORT DDLNode {
+public:
+    friend class OpenDDLParser;
+
+    typedef std::vector<DDLNode*> DllNodeList;
+
+public:
+    ~DDLNode();
+    void attachParent( DDLNode *parent );
+    void detachParent();
+    DDLNode *getParent() const;
+    const DllNodeList &getChildNodeList() const;
+    void setType( const std::string &name );
+    const std::string &getType() const;
+    void setName( const std::string &name );
+    const std::string &getName() const;
+    void setProperties( Property *prop );
+    Property *getProperties() const;
+    void setValue( Value *val );
+    Value *getValue() const;
+    void setDataArrayList( DataArrayList  *dtArrayList );
+    DataArrayList *getDataArrayList() const;
+    void setReferences( Reference  *refs );
+    Reference *getReferences() const;
+    static DDLNode *create( const std::string &type, const std::string &name, DDLNode *parent = ddl_nullptr );
+
+private:
+    DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent = ddl_nullptr );
+    DDLNode();
+    DDLNode( const DDLNode & );
+    DDLNode &operator = ( const DDLNode & );
+    static void releaseNodes();
+
+private:
+    std::string m_type;
+    std::string m_name;
+    DDLNode *m_parent;
+    std::vector<DDLNode*> m_children;
+    Property *m_properties;
+    Value *m_value;
+    DataArrayList *m_dtArrayList;
+    Reference *m_references;
+    size_t m_idx;
+    static DllNodeList s_allocatedNodes;
+};
+
+END_ODDLPARSER_NS
+
+#endif // OPENDDLPARSER_DDLNODE_H_INC

+ 170 - 0
contrib/openddlparser/include/openddlparser/OpenDDLCommon.h

@@ -0,0 +1,170 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef OPENDDLPARSER_OPENDDLPARSERCOMMON_H_INC
+#define OPENDDLPARSER_OPENDDLPARSERCOMMON_H_INC
+
+#include <cstddef>
+#include <vector>
+
+#include <string.h>
+
+#ifdef _MSC_VER
+#   define TAG_DLL_EXPORT __declspec(dllexport)
+#   define TAG_DLL_IMPORT __declspec(dllimport )
+#   ifdef OPENDDLPARSER_BUILD
+#       define DLL_ODDLPARSER_EXPORT TAG_DLL_EXPORT
+#   else
+#       define DLL_ODDLPARSER_EXPORT TAG_DLL_IMPORT
+#   endif // OPENDDLPARSER_BUILD
+#   pragma warning( disable : 4251 )
+#else
+#   define DLL_ODDLPARSER_EXPORT
+#endif // _WIN32
+
+#define BEGIN_ODDLPARSER_NS namespace ODDLParser {
+#define END_ODDLPARSER_NS   }
+#define USE_ODDLPARSER_NS   using namespace ODDLParser;
+
+BEGIN_ODDLPARSER_NS
+
+#ifndef OPENDDL_NO_USE_CPP11
+#   define ddl_nullptr nullptr
+#else
+#   define ddl_nullptr NULL
+#endif // OPENDDL_NO_USE_CPP11
+
+class DDLNode;
+class Value;
+
+struct Name;
+struct Identifier;
+struct Reference;
+struct Property;
+struct DataArrayList;
+
+typedef char  int8;
+typedef short int16;
+typedef int   int32;
+typedef long  int64;
+
+enum NameType {
+    GlobalName,
+    LocalName
+};
+
+struct Name {
+    NameType    m_type;
+    Identifier *m_id;
+
+    Name( NameType type, Identifier *id )
+        : m_type( type )
+        , m_id( id ) {
+        // empty
+    }
+};
+
+struct Reference {
+    size_t   m_numRefs;
+    Name   **m_referencedName;
+
+    Reference()
+    : m_numRefs( 0 )
+    , m_referencedName( ddl_nullptr ) {
+        // empty
+    }
+     
+    Reference( size_t numrefs, Name **names )
+    : m_numRefs( numrefs )
+    , m_referencedName( ddl_nullptr ) {
+        m_referencedName = new Name *[ numrefs ];
+        for( size_t i = 0; i < numrefs; i++ ) {
+            Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id );
+            m_referencedName[ i ] = name;
+        }
+    }
+};
+
+struct Identifier {
+    size_t m_len;
+    char *m_buffer;
+
+    Identifier( size_t len, char buffer[] )
+        : m_len( len )
+        , m_buffer( buffer ) {
+        // empty
+    }
+};
+
+struct Property {
+    Identifier *m_id;
+    Value *m_primData;
+    Reference *m_ref;
+    Property *m_next;
+
+    Property( Identifier *id )
+        : m_id( id )
+        , m_primData( ddl_nullptr )
+        , m_ref( ddl_nullptr )
+        , m_next( ddl_nullptr ) {
+        // empty
+    }
+};
+
+struct DataArrayList {
+    size_t m_numItems;
+    Value *m_dataList;
+    DataArrayList *m_next;
+
+    DataArrayList()
+        : m_numItems( 0 )
+        , m_dataList( ddl_nullptr )
+        , m_next( ddl_nullptr ) {
+        // empty
+    }
+};
+
+struct Context {
+    DDLNode *m_root;
+
+    Context()
+        : m_root( ddl_nullptr ) {
+        // empty
+    }
+};
+
+struct BufferIt {
+    std::vector<char> m_buffer;
+    size_t m_idx;
+
+    BufferIt( const std::vector<char> &buffer )
+        : m_buffer( buffer )
+        , m_idx( 0 ) {
+        // empty
+    }
+};
+
+END_ODDLPARSER_NS
+
+#endif // OPENDDLPARSER_OPENDDLPARSERCOMMON_H_INC
+

+ 131 - 0
contrib/openddlparser/include/openddlparser/OpenDDLParser.h

@@ -0,0 +1,131 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef OPENDDLPARSER_OPENDDLPARSER_H_INC
+#define OPENDDLPARSER_OPENDDLPARSER_H_INC
+
+#include <openddlparser/OpenDDLCommon.h>
+#include <openddlparser/DDLNode.h>
+#include <openddlparser/OpenDDLParserUtils.h>
+#include <openddlparser/Value.h>
+
+#include <vector>
+#include <string>
+
+BEGIN_ODDLPARSER_NS
+
+class DDLNode;
+class Value;
+
+struct Identifier;
+struct Reference;
+struct Property;
+
+template<class T>
+inline
+T *lookForNextToken( T *in, T *end ) {
+    while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
+        in++;
+    }
+    return in;
+}
+
+template<class T>
+inline
+T *getNextToken( T *in, T *end ) {
+    T *tmp( in );
+    while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
+        in++;
+    }
+    if( tmp == in ) {
+        in++;
+    }
+    return in;
+}
+
+///	@brief  Defines the log severity.
+enum LogSeverity {
+    ddl_debug_msg = 0,  ///< Debug message, for debugging
+    ddl_info_msg,       ///< Info messages, normal mode
+    ddl_warn_msg,       ///< Parser warnings
+    ddl_error_msg       ///< Parser errors
+};
+
+class DLL_ODDLPARSER_EXPORT OpenDDLParser {
+public:
+    typedef void( *logCallback )( LogSeverity severity, const std::string &msg );
+
+public:
+    OpenDDLParser();
+    OpenDDLParser( char *buffer, size_t len );
+    ~OpenDDLParser();
+    void setLogCallback( logCallback callback );
+    logCallback getLogCallback() const;
+    void setBuffer( char *buffer, size_t len );
+    void setBuffer( const std::vector<char> &buffer );
+    const char *getBuffer() const;
+    size_t getBufferSize() const;
+    void clear();
+    bool parse();
+    char *parseNextNode( char *current, char *end );
+    char *parseHeader( char *in, char *end );
+    char *parseStructure( char *in, char *end );
+    char *parseStructureBody( char *in, char *end, bool &error );
+    void pushNode( DDLNode *node );
+    DDLNode *popNode();
+    DDLNode *top();
+    DDLNode *getRoot() const;
+    Context *getContext() const;
+
+public: // static parser helpers
+    static void normalizeBuffer( std::vector<char> &buffer );
+    static char *parseName( char *in, char *end, Name **name );
+    static char *parseIdentifier( char *in, char *end, Identifier **id );
+    static char *parsePrimitiveDataType( char *in, char *end, Value::ValueType &type, size_t &len );
+    static char *parseReference( char *in, char *end, std::vector<Name*> &names );
+    static char *parseBooleanLiteral( char *in, char *end, Value **boolean );
+    static char *parseIntegerLiteral( char *in, char *end, Value **integer, Value::ValueType integerType = Value::ddl_int32 );
+    static char *parseFloatingLiteral( char *in, char *end, Value **floating );
+    static char *parseStringLiteral( char *in, char *end, Value **stringData );
+    static char *parseHexaLiteral( char *in, char *end, Value **data );
+    static char *parseProperty( char *in, char *end, Property **prop );
+    static char *parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs );
+    static char *parseDataArrayList( char *in, char *end, DataArrayList **dataList );
+    static const char *getVersion();
+
+private:
+    OpenDDLParser( const OpenDDLParser & );
+    OpenDDLParser &operator = ( const OpenDDLParser & );
+
+private:
+    logCallback m_logCallback;
+    std::vector<char> m_buffer;
+
+    typedef std::vector<DDLNode*> DDLNodeStack;
+    DDLNodeStack m_stack;
+    Context *m_context;
+};
+
+END_ODDLPARSER_NS
+
+#endif // OPENDDLPARSER_OPENDDLPARSER_H_INC

+ 249 - 0
contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h

@@ -0,0 +1,249 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef OPENDDLPARSER_OPENDDLPARSERUTILS_H_INC
+#define OPENDDLPARSER_OPENDDLPARSERUTILS_H_INC
+
+#include <openddlparser/OpenDDLCommon.h>
+
+BEGIN_ODDLPARSER_NS
+
+template<class T>
+inline
+bool isComment( T *in, T *end ) {
+    if( *in == '/' ) {
+        if( in + 1 != end ) {
+            if( *( in + 1 ) == '/' ) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+template<class T>
+inline
+bool isUpperCase( T in ) {
+    return ( in >= 'A' && in <= 'Z' );
+}
+
+template<class T>
+inline
+bool isLowerCase( T in ) {
+    return ( in >= 'a' && in <= 'z' );
+}
+
+template<class T> 
+inline 
+bool isSpace( const T in ) {
+    return ( ' ' == in || '\t' == in );
+}
+
+template<class T>
+inline
+bool isNewLine( const T in ) {
+    return ( '\n' == in || ( '\r' == in ) );
+}
+
+template<class T>
+inline
+bool isSeparator( T in ) {
+    if( isSpace( in ) || ',' == in || '{' == in || '}' == in || '[' == in ) {
+        return true;
+    }
+    return false;
+}
+
+static const unsigned char chartype_table[ 256 ] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 48-63
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-79
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-95
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112-127
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // > 127 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+template<class T>
+inline
+bool isNumeric( const T in ) {
+    return ( in >= '0' && in <= '9' );
+    //return ( chartype_table[in] );
+    /*if (in >= '0' &&  in <= '9' )
+    return true;
+
+    return false;*/
+}
+
+template<class T>
+inline
+bool isInteger( T *in, T *end ) {
+    if( in != end ) {
+        if( *in == '-' ) {
+            in++;
+        }
+    }
+
+    bool result( false );
+    while( '}' != *in && ',' != *in && !isSpace( *in ) && in != end ) {
+        result = isNumeric( *in );
+        if( !result ) {
+            break;
+        }
+        in++;
+    }
+
+    return result;
+}
+
+template<class T>
+inline
+bool isFloat( T *in, T *end ) {
+    if( in != end ) {
+        if( *in == '-' ) {
+            in++;
+        }
+    }
+
+    // check for <1>.0f
+    bool result( false );
+    while( !isSpace( *in ) && in != end ) {
+        if( *in == '.' ) {
+            result = true;
+            break;
+        }
+        result = isNumeric( *in );
+        if( !result ) {
+            return false;
+        }
+        in++;
+    }
+
+    // check for 1<.>0f
+    if( *in == '.' ) {
+        in++;
+    } else {
+        return false;
+    }
+
+    // check for 1.<0>f
+    while( !isSpace( *in ) && in != end && *in != ',' ) {
+        result = isNumeric( *in );
+        if( !result ) {
+            return false;
+        }
+        in++;
+    }
+
+    return result;
+}
+
+template<class T>
+inline
+bool isCharacter( const T in ) {
+    return ( ( in >= 'a' && in <= 'z' ) || ( in >= 'A' && in <= 'Z' ) );
+}
+
+template<class T>
+inline
+bool isStringLiteral( const T in ) {
+    return ( in == '\"' );
+}
+
+template<class T>
+inline
+bool isHexLiteral( T *in, T *end ) {
+    if( *in == '0' ) {
+        if( in + 1 != end ) {
+            if( *( in + 1 ) == 'x' || *( in + 1 ) == 'X' ) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+template<class T>
+inline
+bool isReference( T *in, T *end ) {
+    if( *in == 'r' ) {
+        if( *(in+1) == 'e' ) {
+            if( *(in+2) == 'f' ) {
+                if( ( in + 2 ) != end ) {
+                    return true;
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
+template<class T>
+inline
+bool isEndofLine( const T in ) {
+    return ( '\n' == in );
+}
+
+template<class T>
+inline
+static T *getNextSeparator( T *in, T *end ) {
+    while( !isSeparator( *in ) || in == end ) {
+        in++;
+    }
+    return in;
+}
+
+static const int ErrorHex2Decimal = 9999;
+
+inline
+int hex2Decimal( char in ) {
+    if( isNumeric( in ) ) {
+        return (int) in-48;
+    }
+    char hexCodeLower( 'a' ), hexCodeUpper( 'A' );
+    for( int i = 0; i<16; i++ ) {
+        if( in == hexCodeLower + i || in == hexCodeUpper + i ) {
+            return i+10;
+        }
+    }
+
+    return ErrorHex2Decimal;
+}
+
+END_ODDLPARSER_NS
+
+#endif // OPENDDLPARSER_OPENDDLPARSERUTILS_H_INC

+ 97 - 0
contrib/openddlparser/include/openddlparser/Value.h

@@ -0,0 +1,97 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+#ifndef OPENDDLPARSER_VALUE_H_INC
+#define OPENDDLPARSER_VALUE_H_INC
+
+#include <openddlparser/OpenDDLCommon.h>
+
+#include <string>
+
+BEGIN_ODDLPARSER_NS
+
+///------------------------------------------------------------------------------------------------
+///	@brief  This class implements a value.
+///
+///	Values are used to store data types like boolean, integer, floats, double and many mode. To get
+///	an overview please check the enum VylueType ( @see Value::ValueType ).
+/// Values can be single items or lists of items. They are implemented as linked lists.
+///------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT Value {
+public:
+    ///	@brief  This enum describes the data type stored in the value.
+    enum ValueType {
+        ddl_none = -1,          ///< Nothing specified
+        ddl_bool = 0,           ///< A boolean type
+        ddl_int8,               ///< Integer type, 8 bytes
+        ddl_int16,              ///< Integer type, 16 bytes
+        ddl_int32,              ///< Integer type, 32 bytes
+        ddl_int64,              ///< Integer type, 64 bytes
+        ddl_unsigned_int8,      ///< Unsigned integer type, 8 bytes
+        ddl_unsigned_int16,     ///< Unsigned integer type, 16 bytes
+        ddl_unsigned_int32,     ///< Unsigned integer type, 32 bytes
+        ddl_unsigned_int64,     ///< Unsigned integer type, 64 bytes
+        ddl_half,               
+        ddl_float,
+        ddl_double,
+        ddl_string,
+        ddl_ref,
+        ddl_types_max
+    };
+
+    Value();
+    ~Value();
+    void setBool( bool value );
+    bool getBool();
+    void setInt8( int8 value );
+    int8 getInt8();
+    void setInt16( int16 value );
+    int16  getInt16();
+    void setInt32( int32 value );
+    int32  getInt32();
+    void setInt64( int64 value );
+    int64  getInt64();
+    void setFloat( float value );
+    float getFloat() const;
+    void setDouble( double value );
+    double getDouble() const;
+    void setString( const std::string &str );
+    const char *getString() const;
+    void dump();
+    void setNext( Value *next );
+    Value *getNext() const;
+
+    ValueType m_type;
+    size_t m_size;
+    unsigned char *m_data;
+    Value *m_next;
+};
+
+struct DLL_ODDLPARSER_EXPORT ValueAllocator {
+    static Value *allocPrimData( Value::ValueType type, size_t len = 1 );
+    static void releasePrimData( Value **data );
+};
+
+END_ODDLPARSER_NS
+
+#endif // OPENDDLPARSER_VALUE_H_INC

+ 46 - 46
include/assimp/Compiler/pushpack1.h

@@ -1,46 +1,46 @@
-
-
-// ===============================================================================
-// May be included multiple times - sets structure packing to 1 
-// for all supported compilers. #include <poppack1.h> reverts the changes.
-//
-// Currently this works on the following compilers:
-// MSVC 7,8,9
-// GCC
-// BORLAND (complains about 'pack state changed but not reverted', but works)
-// Clang
-//
-//
-// USAGE:
-//
-// struct StructToBePacked {
-// } PACK_STRUCT;
-//
-// ===============================================================================
-
-#ifdef AI_PUSHPACK_IS_DEFINED
-#	error poppack1.h must be included after pushpack1.h
-#endif
-
-#if defined(_MSC_VER) ||  defined(__BORLANDC__) ||	defined (__BCPLUSPLUS__)
-#	pragma pack(push,1)
-#	define PACK_STRUCT
-#elif defined( __GNUC__ )
-#	if defined(__clang__)
-#		define PACK_STRUCT	__attribute__((__packed__))
-#	else
-#		define PACK_STRUCT	__attribute__((gcc_struct, __packed__))
-#	endif
-#else
-#	error Compiler not supported
-#endif
-
-#if defined(_MSC_VER)
-
-// C4103: Packing was changed after the inclusion of the header, propably missing #pragma pop
-#	pragma warning (disable : 4103) 
-#endif
-
-#define AI_PUSHPACK_IS_DEFINED
-
-
+
+
+// ===============================================================================
+// May be included multiple times - sets structure packing to 1 
+// for all supported compilers. #include <poppack1.h> reverts the changes.
+//
+// Currently this works on the following compilers:
+// MSVC 7,8,9
+// GCC
+// BORLAND (complains about 'pack state changed but not reverted', but works)
+// Clang
+//
+//
+// USAGE:
+//
+// struct StructToBePacked {
+// } PACK_STRUCT;
+//
+// ===============================================================================
+
+#ifdef AI_PUSHPACK_IS_DEFINED
+#	error poppack1.h must be included after pushpack1.h
+#endif
+
+#if defined(_MSC_VER) ||  defined(__BORLANDC__) ||	defined (__BCPLUSPLUS__)
+#	pragma pack(push,1)
+#	define PACK_STRUCT
+#elif defined( __GNUC__ )
+#	if !defined(HOST_MINGW)
+#		define PACK_STRUCT	__attribute__((__packed__))
+#	else
+#		define PACK_STRUCT	__attribute__((gcc_struct, __packed__))
+#	endif
+#else
+#	error Compiler not supported
+#endif
+
+#if defined(_MSC_VER)
+
+// C4103: Packing was changed after the inclusion of the header, propably missing #pragma pop
+#	pragma warning (disable : 4103) 
+#endif
+
+#define AI_PUSHPACK_IS_DEFINED
+
+

+ 185 - 9
include/assimp/Exporter.hpp

@@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 
 #include "cexport.h"
+#include <map>
 
 namespace Assimp	{
 	class ExporterPimpl;
@@ -72,6 +73,9 @@ namespace Assimp	{
  * #ExportToBlob is especially useful if you intend to work 
  * with the data in-memory. 
 */
+
+class ASSIMP_API ExportProperties;
+
 class ASSIMP_API Exporter
 	// TODO: causes good ol' base class has no dll interface warning
 //#ifdef __cplusplus
@@ -81,7 +85,7 @@ class ASSIMP_API Exporter
 public:
 
 	/** Function pointer type of a Export worker function */
-	typedef void (*fpExportFunc)(const char*,IOSystem*, const aiScene*);
+	typedef void (*fpExportFunc)(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 
 	/** Internal description of an Assimp export format option */
 	struct ExportFormatEntry
@@ -171,8 +175,8 @@ public:
 	*   Any IO handlers set via #SetIOHandler are ignored here.
 	* @note Use aiCopyScene() to get a modifiable copy of a previously
 	*   imported scene. */
-	const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing = 0u );
-	inline const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, const std::string& pFormatId, unsigned int pPreprocessing = 0u );
+	const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = NULL);
+	inline const aiExportDataBlob* ExportToBlob(  const aiScene* pScene, const std::string& pFormatId, unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = NULL);
 
 
 	// -------------------------------------------------------------------
@@ -208,8 +212,8 @@ public:
 	 * @return AI_SUCCESS if everything was fine. 
 	 * @note Use aiCopyScene() to get a modifiable copy of a previously
 	 *   imported scene.*/
-	aiReturn Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing = 0u);
-	inline aiReturn Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath,  unsigned int pPreprocessing = 0u);
+	aiReturn Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = NULL);
+	inline aiReturn Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath,  unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = NULL);
 
 
 	// -------------------------------------------------------------------
@@ -309,16 +313,188 @@ protected:
 };
 
 
+class ASSIMP_API ExportProperties
+{
+public:
+	// Data type to store the key hash
+	typedef unsigned int KeyType;
+	
+	// typedefs for our four configuration maps.
+	// We don't need more, so there is no need for a generic solution
+	typedef std::map<KeyType, int> IntPropertyMap;
+	typedef std::map<KeyType, float> FloatPropertyMap;
+	typedef std::map<KeyType, std::string> StringPropertyMap;
+	typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
+
+public:
+
+	/** Standard constructor
+	* @see ExportProperties()
+	*/
+
+	ExportProperties();
+
+	// -------------------------------------------------------------------
+	/** Copy constructor.
+	 * 
+	 * This copies the configuration properties of another ExportProperties.
+	 * @see ExportProperties(const ExportProperties& other)
+	 */
+	ExportProperties(const ExportProperties& other);
+
+	// -------------------------------------------------------------------
+	/** Set an integer configuration property.
+	 * @param szName Name of the property. All supported properties
+	 *   are defined in the aiConfig.g header (all constants share the
+	 *   prefix AI_CONFIG_XXX and are simple strings).
+	 * @param iValue New value of the property
+	 * @param bWasExisting Optional pointer to receive true if the
+	 *   property was set before. The new value replaces the previous value
+	 *   in this case.
+	 * @note Property of different types (float, int, string ..) are kept
+	 *   on different stacks, so calling SetPropertyInteger() for a 
+	 *   floating-point property has no effect - the loader will call
+	 *   GetPropertyFloat() to read the property, but it won't be there.
+	 */
+	void SetPropertyInteger(const char* szName, int iValue, 
+		bool* bWasExisting = NULL);
+
+	// -------------------------------------------------------------------
+	/** Set a boolean configuration property. Boolean properties
+	 *  are stored on the integer stack internally so it's possible
+	 *  to set them via #SetPropertyBool and query them with
+	 *  #GetPropertyBool and vice versa.
+	 * @see SetPropertyInteger()
+	 */
+	void SetPropertyBool(const char* szName, bool value, bool* bWasExisting = NULL)	{
+		SetPropertyInteger(szName,value,bWasExisting);
+	}
+
+	// -------------------------------------------------------------------
+	/** Set a floating-point configuration property.
+	 * @see SetPropertyInteger()
+	 */
+	void SetPropertyFloat(const char* szName, float fValue, 
+		bool* bWasExisting = NULL);
+
+	// -------------------------------------------------------------------
+	/** Set a string configuration property.
+	 * @see SetPropertyInteger()
+	 */
+	void SetPropertyString(const char* szName, const std::string& sValue, 
+		bool* bWasExisting = NULL);
+
+	// -------------------------------------------------------------------
+	/** Set a matrix configuration property.
+	 * @see SetPropertyInteger()
+	 */
+	void SetPropertyMatrix(const char* szName, const aiMatrix4x4& sValue, 
+		bool* bWasExisting = NULL);
+
+	// -------------------------------------------------------------------
+	/** Get a configuration property.
+	 * @param szName Name of the property. All supported properties
+	 *   are defined in the aiConfig.g header (all constants share the
+	 *   prefix AI_CONFIG_XXX).
+	 * @param iErrorReturn Value that is returned if the property 
+	 *   is not found. 
+	 * @return Current value of the property
+	 * @note Property of different types (float, int, string ..) are kept
+	 *   on different lists, so calling SetPropertyInteger() for a 
+	 *   floating-point property has no effect - the loader will call
+	 *   GetPropertyFloat() to read the property, but it won't be there.
+	 */
+	int GetPropertyInteger(const char* szName, 
+		int iErrorReturn = 0xffffffff) const;
+
+	// -------------------------------------------------------------------
+	/** Get a boolean configuration property. Boolean properties
+	 *  are stored on the integer stack internally so it's possible
+	 *  to set them via #SetPropertyBool and query them with
+	 *  #GetPropertyBool and vice versa.
+	 * @see GetPropertyInteger()
+	 */
+	bool GetPropertyBool(const char* szName, bool bErrorReturn = false) const {
+		return GetPropertyInteger(szName,bErrorReturn)!=0;
+	}
+
+	// -------------------------------------------------------------------
+	/** Get a floating-point configuration property
+	 * @see GetPropertyInteger()
+	 */
+	float GetPropertyFloat(const char* szName, 
+		float fErrorReturn = 10e10f) const;
+
+	// -------------------------------------------------------------------
+	/** Get a string configuration property
+	 *
+	 *  The return value remains valid until the property is modified.
+	 * @see GetPropertyInteger()
+	 */
+	const std::string GetPropertyString(const char* szName,
+		const std::string& sErrorReturn = "") const;
+
+	// -------------------------------------------------------------------
+	/** Get a matrix configuration property
+	 *
+	 *  The return value remains valid until the property is modified.
+	 * @see GetPropertyInteger()
+	 */
+	const aiMatrix4x4 GetPropertyMatrix(const char* szName,
+		const aiMatrix4x4& sErrorReturn = aiMatrix4x4()) const;
+
+	// -------------------------------------------------------------------
+	/** Determine a integer configuration property has been set.
+	* @see HasPropertyInteger()
+	 */
+	bool HasPropertyInteger(const char* szName) const;
+
+	/** Determine a boolean configuration property has been set.
+	* @see HasPropertyBool()
+	 */
+	bool HasPropertyBool(const char* szName) const;
+
+	/** Determine a boolean configuration property has been set.
+	* @see HasPropertyFloat()
+	 */
+	bool HasPropertyFloat(const char* szName) const;
+
+	/** Determine a String configuration property has been set.
+	* @see HasPropertyString()
+	 */
+	bool HasPropertyString(const char* szName) const;
+
+	/** Determine a Matrix configuration property has been set.
+	* @see HasPropertyMatrix()
+	 */
+	bool HasPropertyMatrix(const char* szName) const;
+
+protected:
+
+	/** List of integer properties */
+	IntPropertyMap mIntProperties;
+
+	/** List of floating-point properties */
+	FloatPropertyMap mFloatProperties;
+
+	/** List of string properties */
+	StringPropertyMap mStringProperties;
+
+	/** List of Matrix properties */
+	MatrixPropertyMap mMatrixProperties;
+};
+
+
 // ----------------------------------------------------------------------------------
-inline const aiExportDataBlob* Exporter :: ExportToBlob(  const aiScene* pScene, const std::string& pFormatId,unsigned int pPreprocessing ) 
+inline const aiExportDataBlob* Exporter :: ExportToBlob(  const aiScene* pScene, const std::string& pFormatId,unsigned int pPreprocessing, const ExportProperties* pProperties) 
 {
-	return ExportToBlob(pScene,pFormatId.c_str(),pPreprocessing);
+	return ExportToBlob(pScene,pFormatId.c_str(),pPreprocessing, pProperties);
 }
 
 // ----------------------------------------------------------------------------------
-inline aiReturn Exporter :: Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, unsigned int pPreprocessing )
+inline aiReturn Exporter :: Export( const aiScene* pScene, const std::string& pFormatId, const std::string& pPath, unsigned int pPreprocessing, const ExportProperties* pProperties)
 {
-	return Export(pScene,pFormatId.c_str(),pPath.c_str(),pPreprocessing);
+	return Export(pScene,pFormatId.c_str(),pPath.c_str(),pPreprocessing, pProperties);
 }
 
 } // namespace Assimp

+ 11 - 2
include/assimp/config.h

@@ -885,7 +885,7 @@ enum aiComponent
  * Property type: Bool. Default value: false.
  */
 #define AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION "IMPORT_COLLADA_IGNORE_UP_DIRECTION"
-
+
 // ---------------------------------------------------------------------------
 /** @brief Specifies whether the Collada loader will invert the transparency value.
  *
@@ -894,6 +894,15 @@ enum aiComponent
  * not respect the standard and do the opposite of what is normally expected.
  * Property type: Bool. Default value: false.
  */
-#define AI_CONFIG_IMPORT_COLLADA_INVERT_TRANSPARENCY "IMPORT_COLLADA_INVERT_TRANSPARENCY"
+#define AI_CONFIG_IMPORT_COLLADA_INVERT_TRANSPARENCY "IMPORT_COLLADA_INVERT_TRANSPARENCY"
+
+// ---------- All the Export defines ------------
+
+/** @brief Specifies the xfile use double for real values of float
+ *
+ * Property type: Bool. Default value: false.
+ */
+
+#define AI_CONFIG_EXPORT_XFILE_64BIT "EXPORT_XFILE_64BIT"
 
 #endif // !! AI_CONFIG_H_INC

+ 53 - 44
port/jassimp/build.xml

@@ -1,45 +1,54 @@
 <project name="jassimp" basedir="." default="all">
-  <property name="native-src.dir" value="jassimp-native/src" />
-  <property name="src.dir" value="jassimp/src" />
-  <property name="jassimp.lwjgl-src.dir" value="jassimp.lwjgl/src" />
-  <property name="build.dir" value="jassimp/bin" />
-  <property name="dist.dir" value="dist" />
-  <property name="doc.dir" value="doc" />
-  
-  <path id="classpath">
-  </path>
-
-  <target name="compile">
-    <delete dir="${build.dir}" />
-    <mkdir dir="${build.dir}" />
-    <javac classpathref="classpath" destdir="${build.dir}" srcdir="${src.dir}"
-      source="1.6" target="1.6" includeantruntime="false">
-    </javac>
-  </target>
-
-  <target name="jni_header">
-    <mkdir dir="${native-src.dir}" />
-    <javah outputfile="${native-src.dir}/jassimp.h" force="yes">
-      <classpath>
-        <pathelement path="${build.dir}" />
-      </classpath>
-      <class name="jassimp.Jassimp" />
-    </javah>
-  </target>
-  
-  <target name="package" depends="compile">
-    <jar destfile="${dist.dir}/jassimp.jar" basedir="${build.dir}">
-    </jar>
-  </target>
-  
-  
-  <target name="doc">
-    <delete dir="${doc.dir}" />
-    <javadoc access="public" author="false" destdir="${doc.dir}"
-      sourcepath="${src.dir}">
-    </javadoc>
-  </target>
-  
-  <target name="all" depends="package, doc">
-  </target>
-</project>
+	<property name="native-src.dir" value="jassimp-native/src" />
+	<property name="src.dir" value="jassimp/src" />
+	<property name="jassimp.lwjgl-src.dir" value="jassimp.lwjgl/src" />
+	<property name="build.dir" value="jassimp/bin" />
+	<property name="dist.dir" value="dist" />
+	<property name="doc.dir" value="doc" />
+	<property environment="env"/>
+	<property name="ndk.dir" value="${env.NDK_HOME}" />
+	<property name="my.dir" value="${env.PWD}" />
+
+	<path id="classpath">
+	</path>
+
+	<target name="compile">
+		<delete dir="${build.dir}" />
+		<mkdir dir="${build.dir}" />
+		<javac classpathref="classpath" destdir="${build.dir}" srcdir="${src.dir}"
+			source="1.6" target="1.6" includeantruntime="false">
+		</javac>
+	</target>
+
+	<target name="jni_header">
+		<mkdir dir="${native-src.dir}" />
+		<javah outputfile="${native-src.dir}/jassimp.h" force="yes">
+			<classpath>
+				<pathelement path="${build.dir}" />
+			</classpath>
+			<class name="jassimp.Jassimp" />
+		</javah>
+	</target>
+
+	<target name="ndk-jni" depends="package">
+		<exec executable="${ndk.dir}/ndk-build">
+			<arg line="all NDK_PROJECT_PATH=${my.dir}/workspaces/Android-NDK"/>
+		</exec>
+	</target>
+
+	<target name="package" depends="compile">
+		<jar destfile="${dist.dir}/jassimp.jar" basedir="${build.dir}">
+		</jar>
+	</target>
+
+
+	<target name="doc">
+		<delete dir="${doc.dir}" />
+		<javadoc access="public" author="false" destdir="${doc.dir}"
+			sourcepath="${src.dir}">
+		</javadoc>
+	</target>
+
+	<target name="all" depends="package, doc">
+	</target>
+</project>

+ 13 - 0
port/jassimp/jassimp-native/Android.mk

@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := jassimp
+LOCAL_SRC_FILES :=  src/jassimp.cpp
+
+LOCAL_CFLAGS += -DJNI_LOG
+
+#LOCAL_STATIC_LIBRARIES := assimp_static
+LOCAL_SHARED_LIBRARIES := assimp
+LOCAL_LDLIBS    := -llog
+
+include $(BUILD_SHARED_LIBRARY)

+ 59 - 25
port/jassimp/jassimp-native/src/jassimp.cpp

@@ -5,12 +5,16 @@
 
 
 #ifdef JNI_LOG
+#ifdef ANDROID
+#include <android/log.h>
+#define lprintf(...) __android_log_print(ANDROID_LOG_VERBOSE, __func__, __VA_ARGS__)
+#else
 #define lprintf(...) printf (__VA_ARGS__)
+#endif /* ANDROID */
 #else
 #define lprintf
 #endif
 
-
 static bool createInstance(JNIEnv *env, const char* className, jobject& newInstance)
 {
 	jclass clazz = env->FindClass(className);
@@ -30,6 +34,7 @@ static bool createInstance(JNIEnv *env, const char* className, jobject& newInsta
 	}
 
 	newInstance = env->NewObject(clazz, ctr_id);
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == newInstance) 
 	{
@@ -41,7 +46,7 @@ static bool createInstance(JNIEnv *env, const char* className, jobject& newInsta
 }
 
 
-static bool createInstance(JNIEnv *env, const char* className, const char* signature, const jvalue* params, jobject& newInstance)
+static bool createInstance(JNIEnv *env, const char* className, const char* signature,/* const*/ jvalue* params, jobject& newInstance)
 {
 	jclass clazz = env->FindClass(className);
 
@@ -60,6 +65,7 @@ static bool createInstance(JNIEnv *env, const char* className, const char* signa
 	}
 
 	newInstance = env->NewObjectA(clazz, ctr_id, params);
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == newInstance) 
 	{
@@ -82,6 +88,7 @@ static bool getField(JNIEnv *env, jobject object, const char* fieldName, const c
 	}
 
 	jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == fieldId)
 	{
@@ -106,6 +113,7 @@ static bool setIntField(JNIEnv *env, jobject object, const char* fieldName, jint
 	}
 
 	jfieldID fieldId = env->GetFieldID(clazz, fieldName, "I");
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == fieldId)
 	{
@@ -130,6 +138,7 @@ static bool setFloatField(JNIEnv *env, jobject object, const char* fieldName, jf
 	}
 
 	jfieldID fieldId = env->GetFieldID(clazz, fieldName, "F");
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == fieldId)
 	{
@@ -154,6 +163,7 @@ static bool setObjectField(JNIEnv *env, jobject object, const char* fieldName, c
 	}
 
 	jfieldID fieldId = env->GetFieldID(clazz, fieldName, signature);
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == fieldId)
 	{
@@ -192,7 +202,7 @@ static bool getStaticField(JNIEnv *env, const char* className, const char* field
 
 
 static bool call(JNIEnv *env, jobject object, const char* typeName, const char* methodName, 
-	const char* signature, const jvalue* params)
+	const char* signature,/* const*/ jvalue* params)
 {
 	jclass clazz = env->FindClass(typeName);
 
@@ -203,6 +213,7 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char*
 	}
 
 	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+	env->DeleteLocalRef(clazz);
 
 	if (NULL == mid)
 	{
@@ -210,6 +221,27 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char*
 		return false;
 	}
 
+	jboolean jReturnValue = env->CallBooleanMethod(object, mid, params[0].l);
+
+	return (bool)jReturnValue;
+}
+static bool callv(JNIEnv *env, jobject object, const char* typeName,
+		const char* methodName, const char* signature,/* const*/ jvalue* params) {
+	jclass clazz = env->FindClass(typeName);
+
+	if (NULL == clazz) {
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+	env->DeleteLocalRef(clazz);
+
+	if (NULL == mid) {
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
 	env->CallVoidMethodA(object, mid, params);
 
 	return true;
@@ -217,7 +249,7 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char*
 
 
 static bool callStaticObject(JNIEnv *env, const char* typeName, const char* methodName, 
-	const char* signature, const jvalue* params, jobject& returnValue)
+	const char* signature,/* const*/ jvalue* params, jobject& returnValue)
 {
 	jclass clazz = env->FindClass(typeName);
 
@@ -338,7 +370,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		/* set general mesh data in java */
 		jvalue setTypesParams[1];
 		setTypesParams[0].i = cMesh->mPrimitiveTypes;
-		if (!call(env, jMesh, "jassimp/AiMesh", "setPrimitiveTypes", "(I)V", setTypesParams))
+		if (!callv(env, jMesh, "jassimp/AiMesh", "setPrimitiveTypes", "(I)V", setTypesParams))
 		{
 			return false;
 		}
@@ -380,7 +412,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		allocateBuffersParams[1].i = cMesh->mNumFaces;
 		allocateBuffersParams[2].z = isPureTriangle;
 		allocateBuffersParams[3].i = (jint) faceBufferSize;
-		if (!call(env, jMesh, "jassimp/AiMesh", "allocateBuffers", "(IIZI)V", allocateBuffersParams))
+		if (!callv(env, jMesh, "jassimp/AiMesh", "allocateBuffers", "(IIZI)V", allocateBuffersParams))
 		{
 			return false;
 		}
@@ -470,7 +502,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 			jvalue allocateDataChannelParams[2];
 			allocateDataChannelParams[0].i = 0;
 			allocateDataChannelParams[1].i = 0;
-			if (!call(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
 			{
 				lprintf("could not allocate normal data channel\n");
 				return false;
@@ -491,7 +523,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 			jvalue allocateDataChannelParams[2];
 			allocateDataChannelParams[0].i = 1;
 			allocateDataChannelParams[1].i = 0;
-			if (!call(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
 			{
 				lprintf("could not allocate tangents data channel\n");
 				return false;
@@ -512,7 +544,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 			jvalue allocateDataChannelParams[2];
 			allocateDataChannelParams[0].i = 2;
 			allocateDataChannelParams[1].i = 0;
-			if (!call(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+			if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
 			{
 				lprintf("could not allocate bitangents data channel\n");
 				return false;
@@ -535,7 +567,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				jvalue allocateDataChannelParams[2];
 				allocateDataChannelParams[0].i = 3;
 				allocateDataChannelParams[1].i = c;
-				if (!call(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+				if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
 				{
 					lprintf("could not allocate colorset data channel\n");
 					return false;
@@ -574,7 +606,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				}
 
 				allocateDataChannelParams[1].i = c;
-				if (!call(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
+				if (!callv(env, jMesh, "jassimp/AiMesh", "allocateDataChannel", "(II)V", allocateDataChannelParams))
 				{
 					lprintf("could not allocate texture coordinates data channel\n");
 					return false;
@@ -671,7 +703,7 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				wrapParams[0].l = jMatrixArr;
 				jobject jMatrix;
 				
-				if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix)) 
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapParams, jMatrix))
 				{
 					return false;
 				}
@@ -701,6 +733,8 @@ static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				}
 			}
 		}
+		env->DeleteLocalRef(jMeshes);
+		env->DeleteLocalRef(jMesh);
 	}
 
 	return true;
@@ -719,7 +753,7 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj
 	wrapMatParams[0].l = jMatrixArr;
 	jobject jMatrix;
 				
-	if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix)) 
+	if (!callStaticObject(env, "jassimp/Jassimp", "wrapMatrix", "([F)Ljava/lang/Object;", wrapMatParams, jMatrix))
 	{
 		return false;
 	}
@@ -749,7 +783,7 @@ static bool loadSceneNode(JNIEnv *env, const aiNode *cNode, jobject parent, jobj
 	wrapNodeParams[2].l = jMeshrefArr;
 	wrapNodeParams[3].l = jNodeName;
 	jobject jNode;
-	if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapSceneNode", 
+	if (!callStaticObject(env, "jassimp/Jassimp", "wrapSceneNode",
 		"(Ljava/lang/Object;Ljava/lang/Object;[ILjava/lang/String;)Ljava/lang/Object;", wrapNodeParams, jNode)) 
 	{
 		return false;
@@ -842,7 +876,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 			setNumberParams[0].i = ttInd;
 			setNumberParams[1].i = num;
 
-			if (!call(env, jMaterial, "jassimp/AiMaterial", "setTextureNumber", "(II)V", setNumberParams))
+			if (!callv(env, jMaterial, "jassimp/AiMaterial", "setTextureNumber", "(II)V", setNumberParams))
 			{
 				return false;
 			}
@@ -880,7 +914,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				wrapColorParams[0].f = ((float*) cProperty->mData)[0];
 				wrapColorParams[1].f = ((float*) cProperty->mData)[1];
 				wrapColorParams[2].f = ((float*) cProperty->mData)[2];
-				if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jData)) 
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jData))
 				{
 					return false;
 				}
@@ -905,7 +939,7 @@ static bool loadMaterials(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 				wrapColorParams[1].f = ((float*) cProperty->mData)[1];
 				wrapColorParams[2].f = ((float*) cProperty->mData)[2];
 				wrapColorParams[3].f = ((float*) cProperty->mData)[3];
-				if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapColor4", "(FFFF)Ljava/lang/Object;", wrapColorParams, jData)) 
+				if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor4", "(FFFF)Ljava/lang/Object;", wrapColorParams, jData))
 				{
 					return false;
 				}
@@ -1137,7 +1171,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapColorParams[1].f = cLight->mColorDiffuse.g;
 		wrapColorParams[2].f = cLight->mColorDiffuse.b;
 		jobject jDiffuse;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jDiffuse))
 		{
 			return false;
 		}
@@ -1146,7 +1180,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapColorParams[1].f = cLight->mColorSpecular.g;
 		wrapColorParams[2].f = cLight->mColorSpecular.b;
 		jobject jSpecular;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jSpecular))
 		{
 			return false;
 		}
@@ -1155,7 +1189,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapColorParams[1].f = cLight->mColorAmbient.g;
 		wrapColorParams[2].f = cLight->mColorAmbient.b;
 		jobject jAmbient;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapColor3", "(FFF)Ljava/lang/Object;", wrapColorParams, jAmbient))
 		{
 			return false;
 		}
@@ -1167,7 +1201,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapVec3Params[1].f = cLight->mPosition.y;
 		wrapVec3Params[2].f = cLight->mPosition.z;
 		jobject jPosition;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jPosition))
 		{
 			return false;
 		}
@@ -1176,7 +1210,7 @@ static bool loadLights(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapVec3Params[1].f = cLight->mPosition.y;
 		wrapVec3Params[2].f = cLight->mPosition.z;
 		jobject jDirection;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapVec3Params, jDirection))
 		{
 			return false;
 		}
@@ -1242,7 +1276,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapPositionParams[1].f = cCamera->mPosition.y;
 		wrapPositionParams[2].f = cCamera->mPosition.z;
 		jobject jPosition;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jPosition))
 		{
 			return false;
 		}
@@ -1251,7 +1285,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapPositionParams[1].f = cCamera->mUp.y;
 		wrapPositionParams[2].f = cCamera->mUp.z;
 		jobject jUp;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jUp))
 		{
 			return false;
 		}
@@ -1260,7 +1294,7 @@ static bool loadCameras(JNIEnv *env, const aiScene* cScene, jobject& jScene)
 		wrapPositionParams[1].f = cCamera->mLookAt.y;
 		wrapPositionParams[2].f = cCamera->mLookAt.z;
 		jobject jLookAt;
-		if (!callStaticObject(env, "Ljassimp/Jassimp;", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt)) 
+		if (!callStaticObject(env, "jassimp/Jassimp", "wrapVec3", "(FFF)Ljava/lang/Object;", wrapPositionParams, jLookAt))
 		{
 			return false;
 		}

+ 0 - 33
test/RunSingleUnitTestSuite.bat

@@ -1,33 +0,0 @@
-
-rem ------------------------------------------------------------------------------
-rem Tiny script to execute a single unit test suite.
-rem 
-rem Usage:
-rem    SET  OUTDIR=<directory_for_test_results>
-rem    SET  BINDIR=<directory_where_binaries_are_stored>
-rem
-rem    CALL RunSingleUnitTestSuite <name_of_test> <output_file>
-rem
-rem Post:
-rem    FIRSTUTNA       - if the test wasn't found, receives the test name
-rem    FIRSTUTFAILUR   - if the test failed, receives the test name
-rem
-rem ------------------------------------------------------------------------------
-IF NOT EXIST %BINDIR%\%1\unit.exe (
-
-   echo NOT AVAILABLE. Please rebuild this configuration
-   echo Unable to find %BINDIR%\%1\unit.exe > %OUTDIR%%2
-   SET FIRSTUTNA=%2
-) ELSE (
-
-   %BINDIR%\%1\unit.exe > %OUTDIR%%2
-   IF errorlevel == 0 ( 
-      echo SUCCESS
-   ) ELSE (
-      echo FAILURE, check output file: %2
-      SET FIRSTUTFAILURE=%2
-   )
-)
-
-echo.
-echo.

+ 0 - 94
test/RunUnitTestSuite.bat

@@ -1,94 +0,0 @@
-rem ------------------------------------------------------------------------------
-rem Tiny script to execute Assimp's fully unit test suite for all configurations
-rem 
-rem Usage: call RunUnitTestSuite
-rem ------------------------------------------------------------------------------
-
-rem Setup the console environment
-set errorlevel=0
-color 4e
-cls
-
-@echo off
-
-rem Setup target architecture
-SET ARCHEXT=x64
-IF %PROCESSOR_ARCHITECTURE% == x86 (
-   SET ARCHEXT=win32
-)
-
-rem Setup standard paths from here
-SET OUTDIR=results\
-SET BINDIR=..\bin\
-SET FIRSTUTFAILURE=nil
-SET FIRSTUTNA=nil
-
-echo #=====================================================================
-echo # Open Asset Import Library - Unittests                               
-echo #=====================================================================
-echo #                                                                     
-echo # Executes the Assimp library unit test suite for the following                
-echo # build configurations (if available):                                               
-echo #                                                                     
-echo #  Release                                                           
-echo #  Release -st                                                        
-echo #  Release -noboost                                                   
-echo #  Release -dll                                                       
-echo #                                                                     
-echo #  Debug                                                              
-echo #  Debug   -st                                                        
-echo #  Debug   -noboost                                                   
-echo #  Debug   -dll                                                                                                                        
-echo ======================================================================
-echo.
-echo.
-
-
-echo assimp-core release 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_release_%ARCHEXT% release.txt
-
-echo assimp-core release -st 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_release-st_%ARCHEXT% release-st.txt
-
-echo assimp-core release -noboost 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_release-noboost-st_%ARCHEXT% release-st-noboost.txt
-
-echo assimp-core release -dll 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_release-dll_%ARCHEXT% release-dll.txt
-
-echo assimp-core debug
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_debug_%ARCHEXT% debug.txt
-
-echo assimp-core debug -st 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_debug-st_%ARCHEXT% debug-st.txt
-
-echo assimp-core debug -noboost 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_debug-noboost-st_%ARCHEXT% debug-st-noboost.txt
-
-echo assimp-core debug -dll 
-echo **********************************************************************
-call RunSingleUnitTestSuite unit_debug-dll_%ARCHEXT% debug-dll.txt
-
-
-echo ======================================================================
-IF %FIRSTUTNA% == nil (
-   echo All test configs have been found.
-) ELSE (
-   echo One or more test configs are not available.
-)
-
-IF %FIRSTUTFAILURE% == nil (
-   echo All tests have been successful. 
-) ELSE (
-   echo One or more tests failed.
-)
-echo.
-
-pause

BIN
test/models-nonbsd/FBX/2013_BINARY/anims_with_full_rotations_between_keys.fbx


+ 754 - 0
test/models-nonbsd/PLY/ant-half.ply

@@ -0,0 +1,754 @@
+ply
+format ascii 1.0
+element vertex 486
+property float32 x
+property float32 y
+property float32 z
+element face 912
+property list uint8 int32 vertex_indices
+end_header
+-1.106 3.844 9.073 
+-0.3523 0.4402 11.07 
+1.028 3.76 9.209 
+0.137 -0.5632 10.73 
+2.01 4.503 5.887 
+0.07813 5.232 6.794 
+-0.7266 3.741 3.839 
+-2.789 3.179 5.07 
+-0.9185 2.402 3.279 
+1.445 2.139 3.394 
+-3.114 1.498 5.285 
+-1.317 -1.269 8.385 
+-0.854 -1.319 5.036 
+-0.9351 5.347 0.6162 
+-0.8184 2.622 3.235 
+0.4875 5.529 -0.2241 
+3.193 2.756 1.633 
+3.213 1.145 -2.568 
+-2.25 1.208 2.767 
+0.3225 0.8339 3.323 
+1.354 -1.725 1.105 
+0.1887 1.133 -5.785 
+-3.637 2.696 0.3325 
+-3.706 0.8936 -0.5452 
+-0.4326 -0.8737 -4.095 
+-2.994 -0.4858 0.9023 
+0.1252 -2.079 -1.51 
+2.856 -0.7459 -1.187 
+2.32 3.733 8.13 
+2.031 3.721 9.095 
+2.819 3.567 8.537 
+1.994 2.581 9.711 
+2.64 2.491 9.542 
+3.187 2.528 8.375 
+1.628 2.491 7.518 
+1.62 3.721 8.274 
+0.9868 2.471 8.914 
+1.552 2.106 9.414 
+2.657 1.774 8.918 
+-1.805 3.733 8.13 
+-2.094 3.721 9.095 
+-1.306 3.567 8.537 
+-2.131 2.581 9.711 
+-1.485 2.491 9.542 
+-0.938 2.528 8.375 
+-2.497 2.491 7.518 
+-2.505 3.721 8.274 
+-3.138 2.471 8.914 
+-2.573 2.106 9.414 
+-1.469 1.774 8.918 
+1.549 3.638 6.803 
+1.355 3.638 6.7 
+1.424 5.126 6.883 
+1.615 5.083 6.981 
+1.169 3.638 6.815 
+1.237 5.115 6.997 
+1.176 3.638 7.035 
+1.241 5.061 7.21 
+1.369 3.638 7.138 
+1.433 5.018 7.308 
+1.556 3.638 7.023 
+1.62 5.029 7.194 
+1.625 6.512 7.421 
+1.811 6.429 7.504 
+1.437 6.49 7.531 
+1.434 6.386 7.724 
+1.619 6.304 7.807 
+1.808 6.326 7.697 
+1.945 7.702 8.276 
+2.121 7.585 8.335 
+1.754 7.672 8.38 
+1.74 7.525 8.542 
+1.916 7.408 8.601 
+2.107 7.439 8.497 
+2.362 8.615 9.391 
+2.526 8.473 9.417 
+2.168 8.578 9.487 
+2.138 8.398 9.608 
+2.303 8.255 9.635 
+2.497 8.293 9.539 
+2.847 9.189 10.69 
+2.998 9.03 10.68 
+2.649 9.148 10.78 
+2.603 8.947 10.85 
+2.753 8.788 10.84 
+2.95 8.83 10.75 
+3.368 9.385 12.08 
+3.503 9.22 12.03 
+3.167 9.342 12.16 
+3.101 9.134 12.18 
+3.236 8.97 12.13 
+3.438 9.013 12.06 
+3.889 9.189 13.48 
+4.01 9.03 13.39 
+3.684 9.148 13.54 
+3.599 8.947 13.51 
+3.719 8.788 13.42 
+3.925 8.83 13.36 
+4.374 8.615 14.77 
+4.481 8.473 14.65 
+4.165 8.578 14.83 
+4.063 8.398 14.76 
+4.17 8.255 14.63 
+4.379 8.293 14.57 
+4.791 7.702 15.89 
+4.886 7.585 15.73 
+4.579 7.672 15.94 
+4.462 7.525 15.82 
+4.556 7.408 15.66 
+4.769 7.439 15.62 
+5.111 6.512 16.74 
+5.196 6.429 16.56 
+4.896 6.49 16.78 
+4.768 6.386 16.64 
+4.853 6.304 16.46 
+5.068 6.326 16.42 
+-1.141 5.126 6.883 
+-1.072 3.638 6.7 
+-1.266 3.638 6.803 
+-1.332 5.083 6.981 
+-0.9541 5.115 6.997 
+-0.886 3.638 6.815 
+-0.9585 5.061 7.21 
+-0.8928 3.638 7.035 
+-1.15 5.018 7.308 
+-1.086 3.638 7.138 
+-1.337 5.029 7.194 
+-1.272 3.638 7.023 
+-1.342 6.512 7.421 
+-1.528 6.429 7.504 
+-1.154 6.49 7.531 
+-1.151 6.386 7.724 
+-1.336 6.304 7.807 
+-1.525 6.326 7.697 
+-1.662 7.702 8.276 
+-1.838 7.585 8.335 
+-1.471 7.672 8.38 
+-1.457 7.525 8.542 
+-1.633 7.408 8.601 
+-1.824 7.439 8.497 
+-2.079 8.615 9.391 
+-2.243 8.473 9.417 
+-1.885 8.578 9.487 
+-1.855 8.398 9.608 
+-2.02 8.255 9.635 
+-2.214 8.293 9.539 
+-2.564 9.189 10.69 
+-2.715 9.03 10.68 
+-2.366 9.148 10.78 
+-2.32 8.947 10.85 
+-2.47 8.788 10.84 
+-2.667 8.83 10.75 
+-3.085 9.385 12.08 
+-3.22 9.22 12.03 
+-2.884 9.342 12.16 
+-2.818 9.134 12.18 
+-2.953 8.97 12.13 
+-3.155 9.013 12.06 
+-3.606 9.189 13.48 
+-3.726 9.03 13.39 
+-3.4 9.148 13.54 
+-3.316 8.947 13.51 
+-3.437 8.788 13.42 
+-3.642 8.83 13.36 
+-4.091 8.615 14.77 
+-4.198 8.473 14.65 
+-3.882 8.578 14.83 
+-3.78 8.398 14.76 
+-3.887 8.255 14.63 
+-4.096 8.293 14.57 
+-4.508 7.702 15.89 
+-4.603 7.585 15.73 
+-4.296 7.672 15.94 
+-4.179 7.525 15.82 
+-4.273 7.408 15.66 
+-4.485 7.439 15.62 
+-4.828 6.512 16.74 
+-4.913 6.429 16.56 
+-4.613 6.49 16.78 
+-4.484 6.386 16.64 
+-4.57 6.304 16.46 
+-4.784 6.326 16.42 
+-1.519 -2.27 2.989 
+-1.987 -1.082 3.408 
+-2.709 -1.989 3.536 
+-1.513 -2.259 2.974 
+-2.524 -1.536 2.471 
+-4.318 -0.3933 4.187 
+-4.692 -0.6204 3.123 
+-6.274 0.9227 4.173 
+-5.533 1.852 4.043 
+-6.084 1.387 3.082 
+-6.844 2.279 4.015 
+-6.83 1.957 4.012 
+-6.886 2.118 3.737 
+-7.536 1.346 4.658 
+-7.229 0.9683 4.298 
+-8.053 1.724 3.821 
+-7.747 1.346 3.46 
+-9.085 -0.1982 5.078 
+-9.347 -0.1982 3.597 
+-8.702 -0.7393 4.247 
+-10.91 -1.528 5.154 
+-10.39 -2.11 4.847 
+-11.08 -1.528 4.148 
+-10.49 -2.11 4.26 
+-11.58 -2.509 4.768 
+-11.57 -2.523 4.76 
+-11.59 -2.509 4.742 
+-11.57 -2.523 4.744 
+-12.39 -3.546 5.269 
+-11.93 -3.852 5.034 
+-12.52 -3.546 4.548 
+-12.87 -4.803 5.622 
+-12.58 -5.09 4.606 
+-13.49 -4.516 4.767 
+-13.11 -6.264 5.38 
+-14.78 -6.803 5.643 
+-14.49 -7.092 4.622 
+-15.35 -8.042 5.637 
+-14.73 -8.43 5.528 
+-15.15 -8.236 4.95 
+-15.78 -9.378 5.503 
+-15.77 -9.385 5.497 
+-15.78 -9.375 5.495 
+-15.78 -9.378 5.486 
+-15.77 -9.383 5.484 
+-1.522 -2.262 -1.24 
+-1.519 -2.258 -1.231 
+-1.522 -2.262 -1.222 
+-1.529 -2.27 -1.222 
+-1.529 -2.27 -1.24 
+-2.061 -1.082 -0.8906 
+-2.428 -1.536 -1.907 
+-3.082 -0.4963 -0.5522 
+-3.082 -0.4963 -1.91 
+-3.759 -1.333 -1.628 
+-5.567 0.1257 -0.8323 
+-5.665 1.852 -0.8818 
+-6.417 0.9227 -0.8818 
+-6.041 1.387 -1.924 
+-6.95 2.279 -1.137 
+-6.937 1.957 -1.326 
+-6.943 2.118 -1.418 
+-7.378 0.9683 -0.9246 
+-8.108 1.724 -0.9246 
+-7.743 1.346 -1.84 
+-8.797 0.8371 -0.6052 
+-9.793 0.269 -1.611 
+-8.891 -0.6654 -1.611 
+-10.59 -2.11 -0.9326 
+-10.57 -0.523 -0.8679 
+-11.3 -1.375 -0.9326 
+-10.94 -1.742 -1.823 
+-11.75 -2.506 -1.223 
+-11.73 -2.523 -1.223 
+-11.74 -2.514 -1.247 
+-12.76 -3.466 -1.017 
+-12.14 -3.852 -1.017 
+-12.45 -3.659 -1.656 
+-13.16 -4.803 -0.6001 
+-12.7 -5.09 -1.55 
+-13.62 -4.516 -1.55 
+-13.36 -6.264 -0.8809 
+-15.05 -6.803 -0.9114 
+-14.58 -7.092 -1.866 
+-15.6 -8.042 -1.016 
+-14.98 -8.43 -1.016 
+-15.29 -8.236 -1.658 
+-16.01 -9.378 -1.222 
+-15.99 -9.385 -1.226 
+-16.01 -9.375 -1.231 
+-16.01 -9.378 -1.24 
+-16 -9.383 -1.24 
+-1.522 -2.27 -4.918 
+-2.105 -1.082 -4.684 
+-2.827 -1.989 -4.812 
+-1.513 -2.262 -4.935 
+-2.29 -1.536 -5.749 
+-4.562 -0.3933 -4.75 
+-4.55 -0.6204 -5.878 
+-6.395 0.9227 -5.432 
+-5.655 1.852 -5.302 
+-5.844 1.387 -6.393 
+-6.877 2.279 -5.776 
+-6.863 1.957 -5.773 
+-6.821 2.118 -6.051 
+-7.747 1.346 -5.408 
+-7.335 0.9683 -5.641 
+-7.947 1.724 -6.372 
+-7.536 1.346 -6.605 
+-9.347 -0.1982 -5.543 
+-9.085 -0.1982 -7.025 
+-8.702 -0.7393 -6.193 
+-11.08 -1.528 -6.095 
+-10.49 -2.11 -6.206 
+-10.91 -1.528 -7.101 
+-10.39 -2.11 -6.794 
+-11.59 -2.509 -6.689 
+-11.57 -2.523 -6.691 
+-11.58 -2.509 -6.715 
+-11.57 -2.523 -6.707 
+-12.52 -3.546 -6.495 
+-12.01 -3.852 -6.559 
+-12.39 -3.546 -7.217 
+-13.09 -4.803 -6.326 
+-12.47 -5.09 -7.18 
+-13.38 -4.516 -7.341 
+-13.24 -6.264 -6.637 
+-14.89 -6.803 -6.96 
+-14.27 -7.092 -7.819 
+-15.42 -8.042 -7.159 
+-14.8 -8.43 -7.051 
+-15 -8.236 -7.738 
+-15.78 -9.378 -7.432 
+-15.77 -9.385 -7.434 
+-15.78 -9.375 -7.442 
+-15.78 -9.378 -7.45 
+-15.77 -9.383 -7.448 
+1.522 -2.27 -4.918 
+1.511 -2.258 -4.926 
+1.513 -2.262 -4.935 
+2.828 -1.989 -4.812 
+2.105 -1.082 -4.684 
+2.29 -1.536 -5.749 
+4.55 -0.6204 -5.878 
+4.562 -0.3933 -4.75 
+6.395 0.9227 -5.432 
+5.655 1.852 -5.302 
+5.844 1.387 -6.393 
+6.877 2.279 -5.776 
+6.863 1.957 -5.773 
+6.821 2.118 -6.051 
+7.335 0.9683 -5.641 
+7.747 1.346 -5.408 
+7.947 1.724 -6.372 
+7.536 1.346 -6.605 
+9.347 -0.1982 -5.543 
+9.086 -0.1982 -7.025 
+8.702 -0.7393 -6.193 
+11.08 -1.528 -6.095 
+10.49 -2.11 -6.206 
+10.91 -1.528 -7.101 
+10.39 -2.11 -6.794 
+11.59 -2.509 -6.689 
+11.57 -2.523 -6.691 
+11.58 -2.509 -6.715 
+11.57 -2.523 -6.707 
+12.52 -3.546 -6.495 
+12.01 -3.852 -6.559 
+12.39 -3.546 -7.217 
+12.47 -5.09 -7.18 
+13.09 -4.803 -6.326 
+13.38 -4.516 -7.341 
+13.24 -6.264 -6.637 
+14.89 -6.803 -6.96 
+14.27 -7.092 -7.819 
+15.42 -8.042 -7.159 
+14.8 -8.43 -7.051 
+15 -8.236 -7.738 
+15.78 -9.378 -7.432 
+15.77 -9.385 -7.434 
+15.78 -9.375 -7.442 
+15.78 -9.378 -7.45 
+15.77 -9.383 -7.448 
+-0.9592 -0.9547 10.35 
+0.007813 0.3928 11.6 
+-0.7324 1.062 10.63 
+0.007813 -1.855 11.37 
+0.007813 -2.459 10.63 
+0.007813 0.3928 9.662 
+-0.3928 1.509 10.63 
+0.7327 1.062 10.63 
+-0.007813 0.3928 11.6 
+0.9595 -0.9547 10.35 
+-0.007813 -1.855 11.37 
+-0.007813 -2.459 10.63 
+-0.007813 0.3928 9.662 
+0.3931 1.509 10.63 
+1.513 -2.262 2.988 
+1.511 -2.258 2.979 
+1.516 -2.262 2.97 
+1.522 -2.27 2.971 
+1.52 -2.27 2.989 
+1.987 -1.082 3.408 
+2.524 -1.536 2.471 
+2.933 -0.4963 3.919 
+3.168 -0.4963 2.581 
+3.786 -1.333 2.977 
+5.429 0.1257 4.074 
+5.534 1.852 4.042 
+6.274 0.9227 4.173 
+6.085 1.387 3.082 
+6.863 1.957 3.827 
+6.844 2.279 4.015 
+6.886 2.118 3.737 
+7.229 0.9683 4.298 
+7.947 1.724 4.425 
+7.747 1.346 3.46 
+8.57 0.8371 4.859 
+9.726 0.269 4.042 
+8.838 -0.6654 3.885 
+10.39 -2.11 4.847 
+10.37 -0.523 4.909 
+11.09 -1.375 4.97 
+10.89 -1.742 4.032 
+11.59 -2.506 4.763 
+11.57 -2.523 4.76 
+11.58 -2.514 4.739 
+12.55 -3.466 5.142 
+11.93 -3.852 5.034 
+12.35 -3.659 4.459 
+12.58 -5.09 4.606 
+12.87 -4.803 5.622 
+13.49 -4.516 4.767 
+13.11 -6.264 5.38 
+14.78 -6.803 5.643 
+14.49 -7.092 4.622 
+15.35 -8.042 5.637 
+14.73 -8.43 5.528 
+15.15 -8.236 4.95 
+15.78 -9.378 5.503 
+15.77 -9.385 5.497 
+15.78 -9.375 5.495 
+15.78 -9.378 5.486 
+15.77 -9.383 5.484 
+1.529 -2.27 -1.222 
+1.519 -2.258 -1.231 
+1.522 -2.262 -1.24 
+2.795 -1.989 -0.8906 
+2.062 -1.082 -0.8906 
+2.428 -1.536 -1.907 
+4.677 -0.6204 -1.642 
+4.493 -0.3933 -0.5283 
+6.417 0.9227 -0.8818 
+5.665 1.852 -0.8818 
+6.041 1.387 -1.924 
+6.951 2.279 -1.137 
+6.937 1.957 -1.137 
+6.944 2.118 -1.418 
+7.379 0.9683 -0.9246 
+7.743 1.346 -0.623 
+8.108 1.724 -1.538 
+7.743 1.346 -1.84 
+9.343 -0.1982 -0.4792 
+9.343 -0.1982 -1.983 
+8.82 -0.7393 -1.231 
+11.15 -1.528 -0.7207 
+10.59 -2.11 -0.9326 
+11.15 -1.528 -1.742 
+10.59 -2.11 -1.53 
+11.75 -2.509 -1.218 
+11.73 -2.523 -1.223 
+11.75 -2.509 -1.245 
+11.73 -2.523 -1.239 
+12.63 -3.546 -0.8647 
+12.14 -3.852 -1.017 
+12.63 -3.546 -1.598 
+12.7 -5.09 -1.55 
+13.16 -4.803 -0.6001 
+13.62 -4.516 -1.55 
+13.36 -6.264 -0.8804 
+15.05 -6.803 -0.9111 
+14.58 -7.092 -1.866 
+15.6 -8.042 -1.016 
+14.98 -8.43 -1.016 
+15.29 -8.236 -1.658 
+16.01 -9.378 -1.222 
+15.99 -9.385 -1.226 
+16.01 -9.375 -1.231 
+16.01 -9.378 -1.24 
+16 -9.383 -1.24 
+-0.7932 4.462 -7.734 
+-0.3843 1.974 -5.495 
+1.95 3.241 -7.348 
+1.167 0.6428 -6.109 
+3.808 0.1871 -9.572 
+3.644 1.688 -11.88 
+0.07617 4.961 -10.12 
+3.28 -0.5704 -14.15 
+0.2488 -1.848 -16.78 
+-0.9744 -2.686 -16.57 
+0.7307 -3.159 -16.47 
+-2.678 2.963 -8.185 
+-2.616 -2.779 -12.24 
+-1.159 -1.533 -8.922 
+3 0 1 2 
+3 1 3 2 
+3 2 4 5 
+3 4 6 5 
+3 5 6 7 
+3 7 6 8 
+3 2 3 9 
+3 2 9 4 
+3 4 9 6 
+3 6 9 8 
+3 5 0 2 
+3 5 7 0 
+3 8 10 7 
+3 7 10 0 
+3 0 10 1 
+3 1 10 11 
+3 1 11 3 
+3 10 12 11 
+3 11 12 3 
+3 3 12 9 
+3 10 8 12 
+3 12 8 9 
+3 13 14 15 
+3 15 14 16 
+3 17 15 16 
+3 18 19 14 
+3 14 19 16 
+3 19 20 16 
+3 15 17 21 
+3 15 21 13 
+3 14 13 18 
+3 21 22 13 
+3 13 22 18 
+3 21 23 22 
+3 21 24 23 
+3 23 25 22 
+3 22 25 18 
+3 18 25 20 
+3 18 20 19 
+3 23 26 25 
+3 25 26 20 
+3 23 24 26 
+3 26 24 27 
+3 26 27 20 
+3 20 27 16 
+3 24 21 27 
+3 27 21 17 
+3 27 17 16 
+3 28 29 30 
+3 31 32 29 
+3 29 32 30 
+3 32 33 30 
+3 30 33 28 
+3 28 33 34 
+3 28 34 35 
+3 35 34 36 
+3 28 35 29 
+3 35 36 29 
+3 29 36 31 
+3 36 37 31 
+3 31 37 32 
+3 37 38 32 
+3 32 38 33 
+3 36 34 37 
+3 37 34 38 
+3 38 34 33 
+3 39 40 41 
+3 42 43 40 
+3 40 43 41 
+3 43 44 41 
+3 41 44 39 
+3 39 44 45 
+3 39 45 46 
+3 46 45 47 
+3 39 46 40 
+3 46 47 40 
+3 40 47 42 
+3 47 48 42 
+3 42 48 43 
+3 48 49 43 
+3 43 49 44 
+3 47 45 48 
+3 48 45 49 
+3 49 45 44 
+3 50 51 52 
+3 50 52 53 
+3 51 54 55 
+3 51 55 52 
+3 54 56 57 
+3 54 57 55 
+3 56 58 59 
+3 56 59 57 
+3 58 60 61 
+3 58 61 59 
+3 60 50 53 
+3 60 53 61 
+3 53 52 62 
+3 53 62 63 
+3 52 55 64 
+3 52 64 62 
+3 55 57 65 
+3 55 65 64 
+3 57 59 66 
+3 57 66 65 
+3 59 61 67 
+3 59 67 66 
+3 61 53 63 
+3 61 63 67 
+3 63 62 68 
+3 63 68 69 
+3 62 64 70 
+3 62 70 68 
+3 64 65 71 
+3 64 71 70 
+3 65 66 72 
+3 65 72 71 
+3 66 67 73 
+3 66 73 72 
+3 67 63 69 
+3 67 69 73 
+3 69 68 74 
+3 69 74 75 
+3 68 70 76 
+3 68 76 74 
+3 70 71 77 
+3 70 77 76 
+3 71 72 78 
+3 71 78 77 
+3 72 73 79 
+3 72 79 78 
+3 73 69 75 
+3 73 75 79 
+3 75 74 80 
+3 75 80 81 
+3 74 76 82 
+3 74 82 80 
+3 76 77 83 
+3 76 83 82 
+3 77 78 84 
+3 77 84 83 
+3 78 79 85 
+3 78 85 84 
+3 79 75 81 
+3 79 81 85 
+3 81 80 86 
+3 81 86 87 
+3 80 82 88 
+3 80 88 86 
+3 82 83 89 
+3 82 89 88 
+3 83 84 90 
+3 83 90 89 
+3 84 85 91 
+3 84 91 90 
+3 85 81 87 
+3 85 87 91 
+3 87 86 92 
+3 87 92 93 
+3 86 88 94 
+3 86 94 92 
+3 88 89 95 
+3 88 95 94 
+3 89 90 96 
+3 89 96 95 
+3 90 91 97 
+3 90 97 96 
+3 91 87 93 
+3 91 93 97 
+3 93 92 98 
+3 93 98 99 
+3 92 94 100 
+3 92 100 98 
+3 94 95 101 
+3 94 101 100 
+3 95 96 102 
+3 95 102 101 
+3 96 97 103 
+3 96 103 102 
+3 97 93 99 
+3 97 99 103 
+3 99 98 104 
+3 99 104 105 
+3 98 100 106 
+3 98 106 104 
+3 100 101 107 
+3 100 107 106 
+3 101 102 108 
+3 101 108 107 
+3 102 103 109 
+3 102 109 108 
+3 103 99 105 
+3 103 105 109 
+3 105 104 110 
+3 105 110 111 
+3 104 106 112 
+3 104 112 110 
+3 106 107 113 
+3 106 113 112 
+3 107 108 114 
+3 107 114 113 
+3 108 109 115 
+3 108 115 114 
+3 109 105 111 
+3 109 111 115 
+3 54 51 50 
+3 56 54 50 
+3 58 56 50 
+3 60 58 50 
+3 112 113 110 
+3 113 114 110 
+3 114 115 110 
+3 115 111 110 
+3 116 117 118 
+3 119 116 118 
+3 120 121 117 
+3 116 120 117 
+3 122 123 121 
+3 120 122 121 
+3 124 125 123 
+3 122 124 123 
+3 126 127 125 
+3 124 126 125 
+3 119 118 127 
+3 126 119 127 
+3 128 116 119 
+3 129 128 119 
+3 130 120 116 
+3 128 130 116 
+3 131 122 120 
+3 130 131 120 
+3 132 124 122 
+3 131 132 122 
+3 133 126 124 
+3 132 133 124 
+3 129 119 126 
+3 133 129 126 
+3 134 128 129 
+3 135 134 129 
+3 136 130 128 
+3 134 136 128 
+3 137 131 130 
+3 136 137 130 
+3 138 132 131 
+3 137 138 131 
+3 139 133 132 
+3 138 139 132 
+3 135 129 133 
+3 139 135 133 
+3 140 134 135 
+3 141 140 135 
+3 142 136 134 
+3 140 142 134 
+3 143 137 136 
+3 142 143 136 
+3 144 138 137 
+3 143 144 137 
+3 145 139 138 
+3 144 145 138 
+3 141 135 139 

+ 165 - 0
test/models-nonbsd/PLY/ant-half.ply.license

@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.

BIN
test/models/BLEND/BlenderDefault_271.blend


Разлика између датотеке није приказан због своје велике величине
+ 7561 - 0
test/models/Collada/anims_with_full_rotations_between_keys.DAE


+ 95 - 0
test/models/OpenGEX/Example.ogex

@@ -0,0 +1,95 @@
+Metric (key = "distance") {float {1}}
+Metric (key = "angle") {float {1}}
+Metric (key = "time") {float {1}}
+Metric (key = "up") {string {"z"}}
+
+GeometryNode $node1
+{
+	Name {string {"Box001"}}
+	ObjectRef {ref {$geometry1}}
+	MaterialRef {ref {$material1}}
+
+	Transform
+	{
+		float[16]
+		{
+			{0x3F800000, 0x00000000, 0x00000000, 0x00000000,		// {1, 0, 0, 0
+			 0x00000000, 0x3F800000, 0x00000000, 0x00000000,		//  0, 1, 0, 0
+			 0x00000000, 0x00000000, 0x3F800000, 0x00000000,		//  0, 0, 1, 0
+			 0xBEF33B00, 0x411804DE, 0x00000000, 0x3F800000}		//  -0.47506, 9.50119, 0, 1}
+		}
+	}
+}
+
+GeometryNode $node2
+{
+	Name {string {"Box002"}}
+	ObjectRef {ref {$geometry1}}
+	MaterialRef {ref {$material1}}
+
+	Transform
+	{
+		float[16]
+		{
+			{0x3F800000, 0x00000000, 0x00000000, 0x00000000,		// {1, 0, 0, 0
+			 0x00000000, 0x3F800000, 0x00000000, 0x00000000,		//  0, 1, 0, 0
+			 0x00000000, 0x00000000, 0x3F800000, 0x00000000,		//  0, 0, 1, 0
+			 0x43041438, 0x411804DE, 0x00000000, 0x3F800000}		//  132.079, 9.50119, 0, 1}
+		}
+	}
+}
+
+GeometryObject $geometry1		// Box001, Box002
+{
+	Mesh (primitive = "triangles")
+	{
+		VertexArray (attrib = "position")
+		{
+			float[3]		// 24
+			{
+				{0xC2501375, 0xC24C468A, 0x00000000}, {0xC2501375, 0x424C468A, 0x00000000}, {0x42501375, 0x424C468A, 0x00000000}, {0x42501375, 0xC24C468A, 0x00000000}, {0xC2501375, 0xC24C468A, 0x42BA3928}, {0x42501375, 0xC24C468A, 0x42BA3928}, {0x42501375, 0x424C468A, 0x42BA3928}, {0xC2501375, 0x424C468A, 0x42BA3928},
+				{0xC2501375, 0xC24C468A, 0x00000000}, {0x42501375, 0xC24C468A, 0x00000000}, {0x42501375, 0xC24C468A, 0x42BA3928}, {0xC2501375, 0xC24C468A, 0x42BA3928}, {0x42501375, 0xC24C468A, 0x00000000}, {0x42501375, 0x424C468A, 0x00000000}, {0x42501375, 0x424C468A, 0x42BA3928}, {0x42501375, 0xC24C468A, 0x42BA3928},
+				{0x42501375, 0x424C468A, 0x00000000}, {0xC2501375, 0x424C468A, 0x00000000}, {0xC2501375, 0x424C468A, 0x42BA3928}, {0x42501375, 0x424C468A, 0x42BA3928}, {0xC2501375, 0x424C468A, 0x00000000}, {0xC2501375, 0xC24C468A, 0x00000000}, {0xC2501375, 0xC24C468A, 0x42BA3928}, {0xC2501375, 0x424C468A, 0x42BA3928}
+			}
+		}
+
+		VertexArray (attrib = "normal")
+		{
+			float[3]		// 24
+			{
+				{0x00000000, 0x00000000, 0xBF800000}, {0x00000000, 0x00000000, 0xBF800000}, {0x00000000, 0x00000000, 0xBF800000}, {0x00000000, 0x00000000, 0xBF800000}, {0x00000000, 0x00000000, 0x3F800000}, {0x00000000, 0x00000000, 0x3F800000}, {0x00000000, 0x00000000, 0x3F800000}, {0x00000000, 0x00000000, 0x3F800000},
+				{0x00000000, 0xBF800000, 0x00000000}, {0x00000000, 0xBF800000, 0x00000000}, {0x00000000, 0xBF800000, 0x00000000}, {0x80000000, 0xBF800000, 0x00000000}, {0x3F800000, 0x00000000, 0x00000000}, {0x3F800000, 0x00000000, 0x00000000}, {0x3F800000, 0x00000000, 0x00000000}, {0x3F800000, 0x00000000, 0x00000000},
+				{0x00000000, 0x3F800000, 0x00000000}, {0x00000000, 0x3F800000, 0x00000000}, {0x00000000, 0x3F800000, 0x00000000}, {0x80000000, 0x3F800000, 0x00000000}, {0xBF800000, 0x00000000, 0x00000000}, {0xBF800000, 0x00000000, 0x00000000}, {0xBF800000, 0x00000000, 0x00000000}, {0xBF800000, 0x00000000, 0x00000000}
+			}
+		}
+
+		VertexArray (attrib = "texcoord")
+		{
+			float[2]		// 24
+			{
+				{0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000}, {0x00000000, 0x00000000}, {0x00000000, 0x00000000}, {0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000},
+				{0x00000000, 0x00000000}, {0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000}, {0x00000000, 0x00000000}, {0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000},
+				{0x00000000, 0x00000000}, {0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000}, {0x00000000, 0x00000000}, {0x3F800000, 0x00000000}, {0x3F800000, 0x3F800000}, {0x00000000, 0x3F800000}
+			}
+		}
+
+		IndexArray
+		{
+			unsigned_int32[3]		// 12
+			{
+				{0, 1, 2}, {2, 3, 0}, {4, 5, 6}, {6, 7, 4}, {8, 9, 10}, {10, 11, 8}, {12, 13, 14}, {14, 15, 12}, {16, 17, 18}, {18, 19, 16}, {20, 21, 22}, {22, 23, 20}
+			}
+		}
+	}
+}
+
+Material $material1
+{
+	Name {string {"03 - Default"}}
+
+	Color (attrib = "diffuse") {float[3] {{0.588235, 0.588235, 0.588235}}}
+	Texture (attrib = "diffuse")
+	{
+		string {"texture/Concrete.tga"}
+	}
+}

+ 13 - 16
test/regression/run.py

@@ -167,11 +167,11 @@ def process_dir(d, outfile_results, zipin, result):
     print("Processing directory " + d)
     for f in sorted(os.listdir(d)):
         fullpath = os.path.join(d, f)
-        if os.path.isdir(fullpath) and not f == ".svn":
+        if os.path.isdir(fullpath) and not f[:1] == '.':
             process_dir(fullpath, outfile_results, zipin, result)
             continue
 
-        if f in settings.files_to_ignore:
+        if f in settings.files_to_ignore or os.path.splitext(f)[1] in settings.exclude_extensions:
             print("Ignoring " + f)
             continue
 
@@ -190,32 +190,26 @@ def process_dir(d, outfile_results, zipin, result):
                     "regression database? Use gen_db.zip to re-generate.")
                 continue
 
-            # Ignore extensions via settings.py configured list
-            # todo: Fix for multi dot extensions like .skeleton.xml
-            ext = os.path.splitext(fullpath)[1].lower()
-            if ext != "" and ext in settings.exclude_extensions:
-                continue
-
             print("-"*60 + "\n  " + os.path.realpath(fullpath) + " pp: " + pppreset) 
             
             outfile_actual = prepare_output_dir(fullpath, filehash, "ACTUAL")
             outfile_expect = prepare_output_dir(fullpath, filehash, "EXPECT")
             outfile_results.write("assimp dump    "+"-"*80+"\n")
             outfile_results.flush()
-
             command = [assimp_bin_path,
                 "dump",
                 fullpath, outfile_actual, "-b", "-s", "-l" ] +\
                 pppreset.split()
-
             r = subprocess.call(command, **shellparams)
-            print(r)
+            outfile_results.flush()
 
             if r and not failure:
                 result.fail(fullpath, outfile_expect, pppreset, IMPORT_FAILURE, r)
+                outfile_results.write("Failed to import\n")
                 continue
             elif failure and not r:
                 result.fail(fullpath, outfile_expect, pppreset, EXPECTED_FAILURE_NOT_MET)
+                outfile_results.write("Expected import to fail\n")
                 continue
             
             with open(outfile_expect, "wb") as s:
@@ -227,21 +221,24 @@ def process_dir(d, outfile_results, zipin, result):
             except IOError:
                 continue
                 
+            outfile_results.write("Expected data length: {0}\n".format(len(input_expected)))
+            outfile_results.write("Actual data length: {0}\n".format(len(input_actual)))
+            failed = False
             if len(input_expected) != len(input_actual):
                 result.fail(fullpath, outfile_expect, pppreset, DATABASE_LENGTH_MISMATCH,
                         len(input_expected), len(input_actual))
-                continue
+                # Still compare the dumps to see what the difference is
+                failed = True
 
             outfile_results.write("assimp cmpdump "+"-"*80+"\n")
             outfile_results.flush()
-
             command = [ assimp_bin_path, 'cmpdump', outfile_actual, outfile_expect ]
             if subprocess.call(command, **shellparams) != 0:
-                result.fail(fullpath, outfile_expect, pppreset, DATABASE_VALUE_MISMATCH)
+                if not failed:
+                    result.fail(fullpath, outfile_expect, pppreset, DATABASE_VALUE_MISMATCH)
                 continue 
             
-            result.ok(fullpath, pppreset, COMPARE_SUCCESS, 
-                len(input_expected))     
+            result.ok(fullpath, pppreset, COMPARE_SUCCESS, len(input_expected))     
 
 # -------------------------------------------------------------------------------
 def del_folder_with_contents(folder):

+ 1 - 1
test/regression/settings.py

@@ -62,7 +62,7 @@ files_to_ignore = ["pond.0.ply"]
 exclude_extensions = [
     ".lws", ".assbin", ".assxml", ".txt", ".md",
     ".jpeg", ".jpg", ".png", ".gif", ".tga", ".bmp",
-    ".skeleton", ".skeleton.xml"
+    ".skeleton", ".skeleton.xml", ".license"
 ]
 
 # -------------------------------------------------------------------------------

+ 1 - 1
tools/assimp_cmd/CMakeLists.txt

@@ -28,7 +28,7 @@ IF( WIN32 )
 		MAIN_DEPENDENCY assimp)
 ENDIF( WIN32 )
 
-TARGET_LINK_LIBRARIES( assimp_cmd assimp ${ZLIB_LIBRARIES})
+TARGET_LINK_LIBRARIES( assimp_cmd assimp ${ZLIB_LIBRARIES} )
 SET_TARGET_PROPERTIES( assimp_cmd PROPERTIES
 	OUTPUT_NAME assimp
 )

+ 23 - 7
tools/assimp_cmd/CompareDump.cpp

@@ -257,16 +257,32 @@ private:
 	/* read from both streams simult.*/
 	template <typename T> void read(T& filla,T& fille) {
 		if(1 != fread(&filla,sizeof(T),1,actual)) {
-			throw compare_fails_exception("Unexpected EOF reading ACTUAL");
+			EOFActual();
 		}
 		if(1 != fread(&fille,sizeof(T),1,expect)) {
-			throw compare_fails_exception("Unexpected EOF reading EXPECT");
+			EOFExpect();
 		}
 	}
 
-
 private:
 
+	void EOFActual() {
+		std::stringstream ss;
+		throw compare_fails_exception((ss
+			<< "Unexpected EOF reading ACTUAL.\nCurrent position in scene hierarchy is "
+			<< print_hierarchy(),ss.str().c_str()
+			));
+	}
+
+	void EOFExpect() {
+		std::stringstream ss;
+		throw compare_fails_exception((ss
+			<< "Unexpected EOF reading EXPECT.\nCurrent position in scene hierarchy is "
+			<< print_hierarchy(),ss.str().c_str()
+			));
+	}
+
+
 	FILE *const actual, *const expect;
 
 	typedef std::map<std::string,unsigned int> PerChunkCounter;
@@ -290,10 +306,10 @@ template <> void comparer_context :: read<aiString>(aiString& filla,aiString& fi
 	read(lena,lene);
 
 	if(lena && 1 != fread(&filla.data,lena,1,actual)) {
-		throw compare_fails_exception("Unexpected EOF reading ACTUAL");
+		EOFActual();
 	}
 	if(lene && 1 != fread(&fille.data,lene,1,expect)) {
-		throw compare_fails_exception("Unexpected EOF reading ACTUAL");
+		EOFExpect();
 	}
 
 	fille.data[fille.length=static_cast<unsigned int>(lene)] = '\0';
@@ -487,7 +503,7 @@ private:
 		res|=fread(&actual.second,4,1,ctx.get_actual())		<<3u;
 
 		if(res!=0xf) {
-			ctx.failure("I/OError reading chunk head, dumps are not well-defined","<ChunkHead>");
+			ctx.failure("IO Error reading chunk head, dumps are malformed","<ChunkHead>");
 		}
 
 		if (current.first != actual.first) {
@@ -504,7 +520,7 @@ private:
 		if (current.first != actual.first) {
 			std::stringstream ss;
 			ctx.failure((ss
-				<<"Chunk lenghts do not match. EXPECT: "
+				<<"Chunk lengths do not match. EXPECT: "
 				<<current.second
 				<<" ACTUAL: " 
 				<< actual.second,

+ 124 - 0
workspaces/Android-NDK/jni/Android.mk

@@ -0,0 +1,124 @@
+LOCAL_PATH := $(call my-dir)/../../../
+
+include $(CLEAR_VARS)
+LOCAL_MODULE    := assimp_static
+ASSIMP_SRC_DIR = code
+
+FILE_LIST := $(wildcard $(LOCAL_PATH)/$(ASSIMP_SRC_DIR)/*.cpp)
+FILE_LIST += $(wildcard $(LOCAL_PATH)/contrib/openddlparser/code/*.cpp)
+FILE_LIST += $(wildcard $(LOCAL_PATH)/contrib/unzip/*.c)
+FILE_LIST += $(wildcard $(LOCAL_PATH)/contrib/poly2tri/poly2tri/*/*.cc)
+
+LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%)
+
+LOCAL_SRC_FILES += contrib/clipper/clipper.cpp \
+	contrib/ConvertUTF/ConvertUTF.c \
+	contrib/irrXML/irrXML.cpp
+
+# enables -frtti and -fexceptions
+LOCAL_CPP_FEATURES := exceptions
+# identifier 'nullptr' will become a keyword in C++0x [-Wc++0x-compat]
+# but next breaks blender and other importer
+# LOCAL_CFLAGS += -std=c++11
+  
+# cant be disabled? rudamentary function?
+#       -DASSIMP_BUILD_NO_FLIPWINDING_PROCESS  \
+#
+DontBuildProcess = \
+        -DASSIMP_BUILD_NO_FLIPUVS_PROCESS  \
+        -DASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS \
+        -DASSIMP_BUILD_NO_CALCTANGENTS_PROCESS \
+        -DASSIMP_BUILD_NO_DEBONE_PROCESS \
+        -DASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS \
+        -DASSIMP_BUILD_NO_FINDINSTANCES_PROCESS \
+        -DASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS \
+        -DASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS \
+        -DASSIMP_BUILD_NO_GENFACENORMALS_PROCESS \
+        -DASSIMP_BUILD_NO_GENUVCOORDS_PROCESS \
+        -DASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS \
+        -DASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS \
+        -DASSIMP_BUILD_NO_JOINVERTICES_PROCESS \
+        -DASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS \
+        -DASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS \
+        -DASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS \
+        -DASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS \
+        -DASSIMP_BUILD_NO_REMOVEVC_PROCESS \
+        -DASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS \
+        -DASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS \
+        -DASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS \
+        -DASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS \
+        -DASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS \
+        -DASSIMP_BUILD_NO_TRIANGULATE_PROCESS \
+        -DASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+
+DontBuildImporters = \
+        -DASSIMP_BUILD_NO_X_IMPORTER \
+        -DASSIMP_BUILD_NO_3DS_IMPORTER \
+        -DASSIMP_BUILD_NO_MD3_IMPORTER \
+        -DASSIMP_BUILD_NO_MDL_IMPORTER \
+        -DASSIMP_BUILD_NO_MD2_IMPORTER \
+        -DASSIMP_BUILD_NO_PLY_IMPORTER \
+        -DASSIMP_BUILD_NO_ASE_IMPORTER \
+        -DASSIMP_BUILD_NO_HMP_IMPORTER \
+        -DASSIMP_BUILD_NO_SMD_IMPORTER \
+        -DASSIMP_BUILD_NO_MDC_IMPORTER \
+        -DASSIMP_BUILD_NO_MD5_IMPORTER \
+        -DASSIMP_BUILD_NO_STL_IMPORTER \
+        -DASSIMP_BUILD_NO_LWO_IMPORTER \
+        -DASSIMP_BUILD_NO_DXF_IMPORTER \
+        -DASSIMP_BUILD_NO_NFF_IMPORTER \
+        -DASSIMP_BUILD_NO_RAW_IMPORTER \
+        -DASSIMP_BUILD_NO_OFF_IMPORTER \
+        -DASSIMP_BUILD_NO_AC_IMPORTER \
+        -DASSIMP_BUILD_NO_BVH_IMPORTER \
+        -DASSIMP_BUILD_NO_IRRMESH_IMPORTER \
+        -DASSIMP_BUILD_NO_IRR_IMPORTER \
+        -DASSIMP_BUILD_NO_Q3D_IMPORTER \
+        -DASSIMP_BUILD_NO_B3D_IMPORTER \
+        -DASSIMP_BUILD_NO_COLLADA_IMPORTER \
+        -DASSIMP_BUILD_NO_TERRAGEN_IMPORTER \
+        -DASSIMP_BUILD_NO_CSM_IMPORTER \
+        -DASSIMP_BUILD_NO_3D_IMPORTER \
+        -DASSIMP_BUILD_NO_LWS_IMPORTER \
+        -DASSIMP_BUILD_NO_OGRE_IMPORTER \
+        -DASSIMP_BUILD_NO_MS3D_IMPORTER \
+        -DASSIMP_BUILD_NO_COB_IMPORTER \
+        -DASSIMP_BUILD_NO_Q3BSP_IMPORTER \
+        -DASSIMP_BUILD_NO_NDO_IMPORTER \
+        -DASSIMP_BUILD_NO_IFC_IMPORTER \
+        -DASSIMP_BUILD_NO_XGL_IMPORTER \
+        -DASSIMP_BUILD_NO_FBX_IMPORTER \
+        -DASSIMP_BUILD_NO_C4D_IMPORTER \
+	-DASSIMP_BUILD_NO_OPENGEX_IMPORTER \
+        -DASSIMP_BUILD_NO_ASSBIN_IMPORTER
+#        -DASSIMP_BUILD_NO_BLEND_IMPORTER \
+#         -DASSIMP_BUILD_NO_GEO_IMPORTER
+#         -DASSIMP_BUILD_NO_OBJ_IMPORTER \
+#
+DontBuildImporters := -DASSIMP_BUILD_NO_IFC_IMPORTER -DASSIMP_BUILD_NO_IRRMESH_IMPORTER  -DASSIMP_BUILD_NO_IRR_IMPORTER -DASSIMP_BUILD_NO_C4D_IMPORTER
+
+ASSIMP_FLAGS_3_0 = -DASSIMP_BUILD_DLL_EXPORT -DASSIMP_BUILD_NO_OWN_ZLIB -DASSIMP_BUILD_BOOST_WORKAROUND -Dassimp_EXPORTS -fPIC -fvisibility=hidden -Wall
+ASSIMP_FLAGS_3_1 = $(ASSIMP_FLAGS_3_0) # -DASSIMP_BUILD_BLENDER_DEBUG
+
+LOCAL_CFLAGS += $(ASSIMP_FLAGS_3_1) -DASSIMP_BUILD_NO_EXPORT -DOPENDDL_NO_USE_CPP11 $(DontBuildImporters)  # $(DontBuildProcess) 
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include $(LOCAL_PATH)/$(ASSIMP_SRC_DIR)/BoostWorkaround $(LOCAL_PATH)/contrib/openddlparser/include ./ 
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/$(ASSIMP_SRC_DIR)/BoostWorkaround
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE    := assimp
+
+LOCAL_CFLAGS += -UASSIMP_BUILD_DLL_EXPORT
+LOCAL_WHOLE_STATIC_LIBRARIES = assimp_static
+
+LOCAL_LDLIBS := -lz
+
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/$(ASSIMP_SRC_DIR)/BoostWorkaround
+include $(BUILD_SHARED_LIBRARY)
+
+-include $(LOCAL_PATH)/assimp_cmd.mk
+
+# let it on original place
+include $(LOCAL_PATH)/port/jassimp/jassimp-native/Android.mk

+ 8 - 0
workspaces/Android-NDK/jni/Application.mk

@@ -0,0 +1,8 @@
+ifeq ($(CC),clang)
+    NDK_TOOLCHAIN_VERSION := $(CC)
+    $(info "Use llvm Compiler")
+endif
+
+APP_ABI := armeabi-v7a
+
+APP_STL := stlport_static

Неке датотеке нису приказане због велике количине промена