Bladeren bron

+ add XGL/ZGL importer. Some features (includes, object refs, textures not supported yet).

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1210 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
aramis_acg 13 jaren geleden
bovenliggende
commit
397603bac0
5 gewijzigde bestanden met toevoegingen van 1158 en 0 verwijderingen
  1. 9 0
      code/CMakeLists.txt
  2. 6 0
      code/ImporterRegistry.cpp
  3. 932 0
      code/XGLLoader.cpp
  4. 199 0
      code/XGLLoader.h
  5. 12 0
      workspaces/vc9/assimp.vcproj

+ 9 - 0
code/CMakeLists.txt

@@ -390,6 +390,13 @@ SET(IFC_SRCS
 )
 SOURCE_GROUP( IFC FILES ${IFC_SRCS})
 
+SET( XGL_SRCS
+	XGLLoader.cpp
+	XGLLoader.h
+)
+SOURCE_GROUP( XGL FILES ${XGL_SRCS})
+
+
 SET( PostProcessing_SRCS
 	CalcTangentsProcess.cpp
 	CalcTangentsProcess.h
@@ -627,6 +634,7 @@ ADD_LIBRARY( assimp STATIC
 	${BLENDER_SRCS}
 	${NDO_SRCS}
 	${IFC_SRCS}
+	${XGL_SRCS}
 	
 	# Third-party libraries
 	${IrrXML_SRCS}
@@ -687,6 +695,7 @@ ADD_LIBRARY( assimp SHARED
 	${BLENDER_SRCS}
 	${NDO_SRCS}
 	${IFC_SRCS}
+	${XGL_SRCS}
 	
 	# Third-party libraries
 	${IrrXML_SRCS}

+ 6 - 0
code/ImporterRegistry.cpp

@@ -163,6 +163,9 @@ corresponding preprocessor flag to selectively disable formats.
 #ifndef ASSIMP_BUILD_NO_M3_IMPORTER
 #   include "M3Importer.h"
 #endif 
+#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
+#   include "XGLLoader.h"
+#endif 
 
 namespace Assimp {
 
@@ -285,6 +288,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 #if ( !defined ASSIMP_BUILD_NO_M3_IMPORTER )
 	out.push_back( new M3::M3Importer() );
 #endif
+#if ( !defined ASSIMP_BUILD_NO_XGL_IMPORTER )
+	out.push_back( new XGLImporter() );
+#endif
 }
 
 }

+ 932 - 0
code/XGLLoader.cpp

@@ -0,0 +1,932 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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.
+---------------------------------------------------------------------------
+*/
+
+/** @file Implementation of the XGL/ZGL importer class */
+
+#include "AssimpPCH.h"
+#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
+
+#include "XGLLoader.h"
+#include "ParsingUtils.h"
+#include "fast_atof.h"
+
+#include "StreamReader.h"
+#include "MemoryIOWrapper.h"
+
+using namespace Assimp;
+using namespace irr;
+using namespace irr::io;
+
+
+// zlib is needed for compressed XGL files 
+#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
+#	ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#		include <zlib.h>
+#	else
+#		include "../contrib/zlib/zlib.h"
+#	endif
+#endif
+
+
+// scopeguard for a malloc'ed buffer
+struct free_it
+{
+	free_it(void* free) : free(free) {}
+	~free_it() {
+		::free(this->free);
+	}
+
+	void* free;
+};
+
+template<> const std::string LogFunctions<XGLImporter>::log_prefix = "XGL: ";
+
+
+// ------------------------------------------------------------------------------------------------
+// Constructor to be privately used by Importer
+XGLImporter::XGLImporter()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor, private as well 
+XGLImporter::~XGLImporter()
+{}
+
+// ------------------------------------------------------------------------------------------------
+// Returns whether the class can handle the format of the given file. 
+bool XGLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+{
+	/* NOTE: A simple check for the file extension is not enough
+	 * here. XGL and ZGL are ok, but xml is too generic
+	 * and might be collada as well. So open the file and
+	 * look for typical signal tokens.
+	 */
+	const std::string extension = GetExtension(pFile);
+
+	if (extension == "xgl" || extension == "zgl") {
+		return true;
+	}
+	else if (extension == "xml" || checkSig) {
+		ai_assert(pIOHandler != NULL);
+
+		const char* tokens[] = {"<world>","<World>","<WORLD>"};
+		return SearchFileHeaderForToken(pIOHandler,pFile,tokens,3);
+	}
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a list of all file extensions which are handled by this class
+void XGLImporter::GetExtensionList(std::set<std::string>& extensions)
+{
+	extensions.insert("xgl");
+	extensions.insert("zgl");
+}
+
+// ------------------------------------------------------------------------------------------------
+// Imports the given file into the given scene structure. 
+void XGLImporter::InternReadFile( const std::string& pFile, 
+	aiScene* pScene, IOSystem* pIOHandler)
+{
+#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
+	Bytef* dest = NULL;
+	free_it free_it_really(dest);
+#endif
+
+	scene = pScene;
+	boost::shared_ptr<IOStream> stream( pIOHandler->Open( pFile, "rb"));
+
+	// check whether we can read from the file
+	if( stream.get() == NULL) {
+		throw DeadlyImportError( "Failed to open XGL/ZGL file " + pFile + "");
+	}
+
+	// see if its compressed, if so uncompress it
+	if (GetExtension(pFile) == "zgl") {
+#ifdef ASSIMP_BUILD_NO_COMPRESSED_XGL
+		ThrowException("Cannot read ZGL file since Assimp was built without compression support");
+#else
+		boost::scoped_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));	
+
+		// build a zlib stream
+		z_stream zstream;
+		zstream.opaque = Z_NULL;
+		zstream.zalloc = Z_NULL;
+		zstream.zfree  = Z_NULL;
+		zstream.data_type = Z_BINARY;
+
+		// raw decompression without a zlib or gzip header
+		inflateInit2(&zstream, -MAX_WBITS);
+
+		// skip two extra bytes, zgl files do carry a crc16 upfront (I think)
+		raw_reader->IncPtr(2);
+
+		zstream.next_in   = reinterpret_cast<Bytef*>( raw_reader->GetPtr() );
+		zstream.avail_in  = raw_reader->GetRemainingSize();
+		
+		size_t total = 0l;
+
+		// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
+	#define MYBLOCK 1024
+		Bytef block[MYBLOCK];
+		int ret;
+		do {
+			zstream.avail_out = MYBLOCK;
+			zstream.next_out = block;
+			ret = inflate(&zstream, Z_NO_FLUSH);
+
+			if (ret != Z_STREAM_END && ret != Z_OK) {
+				ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .XGL file");
+			}
+			const size_t have = MYBLOCK - zstream.avail_out;
+			total += have;
+			dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
+			memcpy(dest + total - have,block,have);
+		} 
+		while (ret != Z_STREAM_END);
+
+		// terminate zlib
+		inflateEnd(&zstream);
+
+		// replace the input stream with a memory stream
+		stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total)); 
+#endif
+	}
+
+	// construct the irrXML parser
+	CIrrXML_IOStreamReader st(stream.get());
+	boost::scoped_ptr<IrrXMLReader> read( createIrrXMLReader((IFileReadCallBack*) &st) );
+	reader = read.get();
+
+	// parse the XML file
+	TempScope scope;
+
+	while (ReadElement())	{	
+		if (!ASSIMP_stricmp(reader->getNodeName(),"world")) {
+			ReadWorld(scope);
+		}
+	}
+	
+
+	std::vector<aiMesh*>& meshes = scope.meshes_linear;
+	std::vector<aiMaterial*>& materials = scope.materials_linear;
+	if(!meshes.size() || !materials.size()) {
+		ThrowException("failed to extract data from XGL file, no meshes loaded");
+	}
+
+	// copy meshes
+	scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+	scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
+	std::copy(meshes.begin(),meshes.end(),scene->mMeshes);
+
+	// copy materials
+	scene->mNumMaterials = static_cast<unsigned int>(materials.size());
+	scene->mMaterials = new aiMaterial*[scene->mNumMaterials]();
+	std::copy(materials.begin(),materials.end(),scene->mMaterials);
+
+	if (scope.light) {
+		scene->mNumLights = 1;
+		scene->mLights = new aiLight*[1];
+		scene->mLights[0] = scope.light;
+
+		scope.light->mName = scene->mRootNode->mName;
+	}
+
+	scope.dismiss();
+}
+
+// ------------------------------------------------------------------------------------------------
+bool XGLImporter::ReadElement()
+{
+	while(reader->read()) {
+		if (reader->getNodeType() == EXN_ELEMENT) {
+			return true;
+		}
+	}
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool XGLImporter::ReadElementUpToClosing(const char* closetag)
+{
+	while(reader->read()) {
+		if (reader->getNodeType() == EXN_ELEMENT) {
+			return true;
+		}
+		else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(),closetag)) {
+			return false;
+		}
+	}
+	LogError("unexpected EOF, expected closing <" + std::string(closetag) + "> tag");
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+bool XGLImporter::SkipToText()
+{
+	while(reader->read()) {
+		if (reader->getNodeType() == EXN_TEXT) {
+			return true;
+		}
+		else if (reader->getNodeType() == EXN_ELEMENT || reader->getNodeType() == EXN_ELEMENT_END) {
+			ThrowException("expected text contents but found another element (or element end)");
+		}
+	}
+	return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+std::string XGLImporter::GetElementName()
+{
+	const char* s  = reader->getNodeName();
+	size_t len = strlen(s);
+
+	std::string ret;
+	ret.resize(len);
+
+	std::transform(s,s+len,ret.begin(),::tolower);
+	return ret;
+}
+
+// ------------------------------------------------------------------------------------------------
+void XGLImporter::ReadWorld(TempScope& scope)
+{
+	while (ReadElementUpToClosing("world"))	{	
+		const std::string& s = GetElementName();
+		// XXX right now we'd skip <lighting> if it comes after
+		// <object> or <mesh>
+		if (s == "lighting") {
+			ReadLighting(scope);
+		}
+		else if (s == "object" || s == "mesh" || s == "mat") {
+			break;
+		}
+	}
+
+	
+	aiNode* const nd = ReadObject(scope,true,"world");
+	if(!nd) {
+		ThrowException("failure reading <world>");
+	}
+	if(!nd->mName.length) {
+		nd->mName.Set("WORLD");
+	}
+
+	scene->mRootNode = nd;
+}
+
+// ------------------------------------------------------------------------------------------------
+void XGLImporter::ReadLighting(TempScope& scope)
+{
+	while (ReadElementUpToClosing("lighting"))	{
+		const std::string& s = GetElementName();
+		if (s == "directionallight") {
+			scope.light = ReadDirectionalLight();
+		}
+		else if (s == "ambient") {
+			LogWarn("ignoring <ambient> tag");
+		}
+		else if (s == "spheremap") {
+			LogWarn("ignoring <spheremap> tag");
+		}
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+aiLight* XGLImporter::ReadDirectionalLight()
+{
+	ScopeGuard<aiLight> l(new aiLight());
+	l->mType = aiLightSource_DIRECTIONAL;
+
+	while (ReadElementUpToClosing("directionallight"))	{	
+		const std::string& s = GetElementName();
+		if (s == "direction") {
+			l->mDirection = ReadVec3();
+		}
+		else if (s == "diffuse") {
+			l->mColorDiffuse = ReadCol3();
+		}
+		else if (s == "specular") {
+			l->mColorSpecular = ReadCol3();
+		}
+	}
+	return l.dismiss();
+}
+
+// ------------------------------------------------------------------------------------------------
+aiNode* XGLImporter::ReadObject(TempScope& scope, bool skipFirst, const char* closetag)
+{
+	ScopeGuard<aiNode> nd(new aiNode());
+	std::vector<aiNode*> children;
+	std::vector<unsigned int> meshes;
+
+	try {
+		while (skipFirst || ReadElementUpToClosing(closetag))	{
+			skipFirst = false;
+
+			const std::string& s = GetElementName();
+			if (s == "mesh") {
+				const size_t prev = scope.meshes_linear.size();
+				if(ReadMesh(scope)) {
+					const size_t newc = scope.meshes_linear.size();
+					for(size_t i = 0; i < newc-prev; ++i) {
+						meshes.push_back(static_cast<unsigned int>(i+prev));
+					}
+				}
+			}
+			else if (s == "mat") {
+				ReadMaterial(scope);
+			}
+			else if (s == "object") {
+				children.push_back(ReadObject(scope));
+			}
+			else if (s == "objectref") {
+				// XXX
+			}
+			else if (s == "meshref") {
+				const int id = ReadIndexFromText();
+
+				std::multimap<unsigned int, aiMesh*>::iterator it = scope.meshes.find(id), end = scope.meshes.end();
+				if (it == end) {
+					ThrowException("<meshref> index out of range");
+				}
+
+				for(; it != end && (*it).first == id; ++it) {
+					// ok, this is n^2 and should get optimized one day
+					aiMesh* const m = (*it).second;
+
+					unsigned int i = 0, mcount = static_cast<unsigned int>(scope.meshes_linear.size());
+					for(; i < mcount; ++i) {
+						if (scope.meshes_linear[i] == m) {
+							meshes.push_back(i);
+							break;
+						}
+					}
+
+					ai_assert(i < mcount);
+				}
+			}
+			else if (s == "transform") {
+				nd->mTransformation = ReadTrafo();
+			}
+		}
+
+	} catch(...) {
+		BOOST_FOREACH(aiNode* ch, children) {
+			delete ch;
+		}
+		throw;
+	}
+
+	// link meshes to node
+	nd->mNumMeshes = static_cast<unsigned int>(meshes.size());
+	if (nd->mNumMeshes) {
+		nd->mMeshes = new unsigned int[nd->mNumMeshes]();
+		for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
+			nd->mMeshes[i] = meshes[i];
+		}
+	}
+
+	// link children to parent
+	nd->mNumChildren = static_cast<unsigned int>(children.size());
+	if (nd->mNumChildren) {
+		nd->mChildren = new aiNode*[nd->mNumChildren]();
+		for(unsigned int i = 0; i < nd->mNumChildren; ++i) {
+			nd->mChildren[i] = children[i];
+			children[i]->mParent = nd;
+		}
+	}
+
+	return nd.dismiss();
+}
+
+// ------------------------------------------------------------------------------------------------
+aiMatrix4x4 XGLImporter::ReadTrafo()
+{
+	aiVector3D forward, up, right, position;
+	float scale = 1.0f;
+
+	while (ReadElementUpToClosing("transform"))	{	
+		const std::string& s = GetElementName();
+		if (s == "forward") {
+			forward = ReadVec3();
+		}
+		else if (s == "up") {
+			up = ReadVec3();
+		}
+		else if (s == "position") {
+			position = ReadVec3();
+		}
+		if (s == "scale") {
+			scale = ReadFloat();
+			if(scale < 0.f) {
+				// this is wrong, but we can leave the value and pass it to the caller
+				LogError("found negative scaling in <transform>, ignoring");
+			}
+		}
+	}
+
+	aiMatrix4x4 m;
+	if(forward.SquareLength() < 1e-4 || up.SquareLength() < 1e-4) {
+		LogError("A direction vector in <transform> is zero, ignoring trafo");
+		return m;
+	}
+
+	forward.Normalize();
+	up.Normalize();
+
+	right = forward ^ up;
+	if (fabs(up * forward) > 1e-4) {
+		// this is definitely wrong - a degenerate coordinate space ruins everything
+		// so subtitute identity transform.
+		LogError("<forward> and <up> vectors in <transform> are skewing, ignoring trafo");
+		return m;
+	}
+
+	right *= scale;
+	up *= scale;
+	forward *= scale;
+
+	m.a1 = right.x;
+	m.b1 = right.y;
+	m.c1 = right.z;
+
+	m.a2 = up.x;
+	m.b2 = up.y;
+	m.c2 = up.z;
+
+	m.a3 = forward.x;
+	m.b3 = forward.y;
+	m.c3 = forward.z;
+
+	m.a4 = position.x;
+	m.b4 = position.y;
+	m.c4 = position.z;
+
+	return m;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiMesh* XGLImporter::ToOutputMesh(const TempMaterialMesh& m)
+{
+	ScopeGuard<aiMesh> mesh(new aiMesh());
+
+	mesh->mNumVertices = static_cast<unsigned int>(m.positions.size());
+	mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+	std::copy(m.positions.begin(),m.positions.end(),mesh->mVertices);
+
+	if(m.normals.size()) {
+		mesh->mNormals = new aiVector3D[mesh->mNumVertices];
+		std::copy(m.normals.begin(),m.normals.end(),mesh->mNormals);
+	}
+
+	if(m.uvs.size()) {
+		mesh->mNumUVComponents[0] = 2;
+		mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
+
+		for(unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+			mesh->mTextureCoords[0][i] = aiVector3D(m.uvs[i].x,m.uvs[i].y,0.f);
+		}
+	}
+
+	mesh->mNumFaces =  static_cast<unsigned int>(m.vcounts.size());
+	mesh->mFaces = new aiFace[m.vcounts.size()];
+
+	unsigned int idx = 0;
+	for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
+		aiFace& f = mesh->mFaces[i];
+		f.mNumIndices = m.vcounts[i];
+		f.mIndices = new unsigned int[f.mNumIndices];
+		for(unsigned int c = 0; c < f.mNumIndices; ++c) {
+			f.mIndices[c] = idx++;
+		}
+	}
+
+	ai_assert(idx == mesh->mNumVertices);
+
+	mesh->mPrimitiveTypes = m.pflags;
+	mesh->mMaterialIndex = m.matid;
+	return mesh.dismiss();
+}
+
+// ------------------------------------------------------------------------------------------------
+bool XGLImporter::ReadMesh(TempScope& scope)
+{
+	TempMesh t;
+
+	std::map<unsigned int, TempMaterialMesh> bymat;
+	const unsigned int mesh_id = ReadIDAttr();
+
+	while (ReadElementUpToClosing("mesh"))	{	
+		const std::string& s = GetElementName();
+
+		if (s == "mat") {
+			ReadMaterial(scope);
+		}
+		else if (s == "p") {
+			if (!reader->getAttributeValue("ID")) {
+				LogWarn("no ID attribute on <p>, ignoring");
+			}
+			else {
+				int id = reader->getAttributeValueAsInt("ID");
+				t.points[id] = ReadVec3();
+			}
+		}
+		else if (s == "n") {
+			if (!reader->getAttributeValue("ID")) {
+				LogWarn("no ID attribute on <n>, ignoring");
+			}
+			else {
+				int id = reader->getAttributeValueAsInt("ID");
+				t.normals[id] = ReadVec3();
+			}
+		}
+		else if (s == "tc") {
+			if (!reader->getAttributeValue("ID")) {
+				LogWarn("no ID attribute on <tc>, ignoring");
+			}
+			else {
+				int id = reader->getAttributeValueAsInt("ID");
+				t.uvs[id] = ReadVec2();
+			}
+		}
+		else if (s == "f" || s == "l" || s == "p") {
+			const unsigned int vcount = s == "f" ? 3 : (s == "l" ? 2 : 1);
+
+			unsigned int mid = ~0u;
+			TempFace tf[3];
+			bool has[3] = {0};
+
+			while (ReadElementUpToClosing(s.c_str()))	{
+				const std::string& s = GetElementName();
+				if (s == "fv1" || s == "lv1" || s == "pv1") {
+					ReadFaceVertex(t,tf[0]);
+					has[0] = true;
+				}
+				else if (s == "fv2" || s == "lv2") {
+					ReadFaceVertex(t,tf[1]);
+					has[1] = true;
+				}
+				else if (s == "fv3") {
+					ReadFaceVertex(t,tf[2]);
+					has[2] = true;
+				}
+				else if (s == "mat") {
+					if (mid != ~0u) {
+						LogWarn("only one material tag allowed per <f>");
+					}
+					mid = ResolveMaterialRef(scope);
+				}
+				else if (s == "matref") {
+					if (mid != ~0u) {
+						LogWarn("only one material tag allowed per <f>");
+					}
+					mid = ResolveMaterialRef(scope);
+				}
+			}
+
+			if (mid == ~0u) {
+				ThrowException("missing material index");
+			}
+
+			bool nor = false;
+			bool uv = false;
+			for(unsigned int i = 0; i < vcount; ++i) {
+				if (!has[i]) {
+					ThrowException("missing face vertex data");
+				}
+
+				nor = nor || tf[i].has_normal;
+				uv = uv || tf[i].has_uv;
+			}			
+
+			if (mid >= (1<<30)) {
+				LogWarn("material indices exhausted, this may cause errors in the output");
+			}
+			unsigned int meshId = mid | ((nor?1:0)<<31) | ((uv?1:0)<<30);
+
+			TempMaterialMesh& mesh = bymat[meshId];
+			mesh.matid = mid;
+
+			for(unsigned int i = 0; i < vcount; ++i) {
+				mesh.positions.push_back(tf[i].pos);
+				if(nor) {
+					mesh.normals.push_back(tf[i].normal);
+				}
+				if(uv) {
+					mesh.uvs.push_back(tf[i].uv);
+				}
+				
+				mesh.pflags |= 1 << (vcount-1);
+			}
+
+			mesh.vcounts.push_back(vcount);
+		}		
+	}
+
+	// finally extract output meshes and add them to the scope 
+	typedef std::pair<unsigned int, TempMaterialMesh> pairt;
+	BOOST_FOREACH(const pairt& p, bymat) {
+		aiMesh* const m  = ToOutputMesh(p.second);
+		scope.meshes_linear.push_back(m);
+
+		// if this is a definition, keep it on the stack
+		if(mesh_id != ~0u) {
+			scope.meshes.insert(std::pair<unsigned int, aiMesh*>(mesh_id,m));
+		}
+	}
+
+	// no id == not a reference, insert this mesh right *here*
+	return mesh_id == ~0u;
+}
+
+// ----------------------------------------------------------------------------------------------
+unsigned int XGLImporter::ResolveMaterialRef(TempScope& scope)
+{
+	const std::string& s = GetElementName();
+	if (s == "mat") {
+		ReadMaterial(scope);
+		return scope.materials_linear.size()-1;
+	}
+
+	const int id = ReadIndexFromText();
+
+	std::map<unsigned int, aiMaterial*>::iterator it = scope.materials.find(id), end = scope.materials.end();
+	if (it == end) {
+		ThrowException("<matref> index out of range");
+	}
+	
+	// ok, this is n^2 and should get optimized one day
+	aiMaterial* const m = (*it).second;
+
+	unsigned int i = 0, mcount = static_cast<unsigned int>(scope.materials_linear.size());
+	for(; i < mcount; ++i) {
+		if (scope.materials_linear[i] == m) {
+			return i;
+		}
+	}
+
+	ai_assert(false);
+	return 0;
+}
+
+// ------------------------------------------------------------------------------------------------
+void XGLImporter::ReadMaterial(TempScope& scope)
+{
+	const unsigned int mat_id = ReadIDAttr();
+
+	ScopeGuard<aiMaterial> mat(new aiMaterial());
+	while (ReadElementUpToClosing("mat"))  {
+		const std::string& s = GetElementName();
+		if (s == "amb") {
+			const aiColor3D c = ReadCol3();
+			mat->AddProperty(&c,1,AI_MATKEY_COLOR_AMBIENT);
+		}
+		else if (s == "diff") {
+			const aiColor3D c = ReadCol3();
+			mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
+		}
+		else if (s == "spec") {
+			const aiColor3D c = ReadCol3();
+			mat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
+		}
+		else if (s == "emiss") {
+			const aiColor3D c = ReadCol3();
+			mat->AddProperty(&c,1,AI_MATKEY_COLOR_EMISSIVE);
+		}
+		else if (s == "alpha") {
+			const float f = ReadFloat();
+			mat->AddProperty(&f,1,AI_MATKEY_OPACITY);
+		}
+		else if (s == "shine") {
+			const float f = ReadFloat();
+			mat->AddProperty(&f,1,AI_MATKEY_SHININESS);
+		}
+	}
+
+	scope.materials[mat_id] = mat;
+	scope.materials_linear.push_back(mat.dismiss());
+}
+
+
+// ----------------------------------------------------------------------------------------------
+void XGLImporter::ReadFaceVertex(const TempMesh& t, TempFace& out)
+{
+	const std::string& end = GetElementName();
+
+	bool havep = false;
+	while (ReadElementUpToClosing(end.c_str()))  {
+		const std::string& s = GetElementName();
+		if (s == "pref") {
+			const unsigned int id = ReadIndexFromText();
+			std::map<unsigned int, aiVector3D>::const_iterator it = t.points.find(id);
+			if (it == t.points.end()) {
+				ThrowException("point index out of range");
+			}
+
+			out.pos = (*it).second;
+			havep = true;
+		}
+		else if (s == "nref") {
+			const unsigned int id = ReadIndexFromText();
+			std::map<unsigned int, aiVector3D>::const_iterator it = t.normals.find(id);
+			if (it == t.normals.end()) {
+				ThrowException("normal index out of range");
+			}
+
+			out.normal = (*it).second;
+			out.has_normal = true;
+		}
+		else if (s == "tcref") {
+			const unsigned int id = ReadIndexFromText();
+			std::map<unsigned int, aiVector2D>::const_iterator it = t.uvs.find(id);
+			if (it == t.uvs.end()) {
+				ThrowException("uv index out of range");
+			}
+
+			out.uv = (*it).second;
+			out.has_uv = true;
+		}
+		else if (s == "p") {
+			out.pos = ReadVec3();
+		}
+		else if (s == "n") {
+			out.normal = ReadVec3();
+		}
+		else if (s == "tc") {
+			out.uv = ReadVec2();
+		}
+	}
+
+	if (!havep) {
+		ThrowException("missing <pref> in <fvN> element");
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int XGLImporter::ReadIDAttr()
+{
+	for(int i = 0, e = reader->getAttributeCount(); i < e; ++i) {
+	
+		if(!ASSIMP_stricmp(reader->getAttributeName(i),"id")) {
+			return reader->getAttributeValueAsInt(i);
+		}
+	}	
+	return ~0u;
+}
+
+// ------------------------------------------------------------------------------------------------
+float XGLImporter::ReadFloat()
+{
+	if(!SkipToText()) {
+		LogError("unexpected EOF reading float element contents");
+		return 0.f;
+	}
+	const char* s = reader->getNodeData(), *se;
+
+	if(!SkipSpaces(&s)) {
+		LogError("unexpected EOL, failed to parse float");
+		return 0.f;
+	}
+
+	float t;
+	se = fast_atoreal_move(s,t);
+
+	if (se == s) {
+		LogError("failed to read float text");
+		return 0.f;
+	}
+
+	return t;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int XGLImporter::ReadIndexFromText()
+{
+	if(!SkipToText()) {
+		LogError("unexpected EOF reading index element contents");
+		return ~0u;
+	}
+	const char* s = reader->getNodeData(), *se;
+	if(!SkipSpaces(&s)) {
+		LogError("unexpected EOL, failed to parse index element");
+		return ~0u;
+	}
+
+	const unsigned int t = strtoul10(s,&se);
+
+	if (se == s) {
+		LogError("failed to read index");
+		return ~0u;
+	}
+
+	return t;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiVector2D XGLImporter::ReadVec2()
+{
+	aiVector2D vec;
+
+	if(!SkipToText()) {
+		LogError("unexpected EOF reading vec2 contents");
+		return vec;
+	}
+	const char* s = reader->getNodeData();
+
+	for(int i = 0; i < 2; ++i) {
+		if(!SkipSpaces(&s)) {
+			LogError("unexpected EOL, failed to parse vec2");
+			return vec;
+		}
+		vec[i] = fast_atof(&s);
+
+		SkipSpaces(&s);
+		if (i != 1 && *s != ',') {
+			LogError("expected comma, failed to parse vec2");
+			return vec;
+		}
+		++s;
+	}
+
+	return vec;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiVector3D XGLImporter::ReadVec3()
+{
+	aiVector3D vec;
+
+	if(!SkipToText()) {
+		LogError("unexpected EOF reading vec3 contents");
+		return vec;
+	}
+	const char* s = reader->getNodeData();
+
+	for(int i = 0; i < 3; ++i) {
+		if(!SkipSpaces(&s)) {
+			LogError("unexpected EOL, failed to parse vec3");
+			return vec;
+		}
+		vec[i] = fast_atof(&s);
+
+		SkipSpaces(&s);
+		if (i != 2 && *s != ',') {
+			LogError("expected comma, failed to parse vec3");
+			return vec;
+		}
+		++s;
+	}
+
+	return vec;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiColor3D XGLImporter::ReadCol3()
+{
+	const aiVector3D& v = ReadVec3();
+	if (v.x < 0.f || v.x > 1.0f || v.y < 0.f || v.y > 1.0f || v.z < 0.f || v.z > 1.0f) {
+		LogWarn("color values out of range, ignoring");
+	}
+	return aiColor3D(v.x,v.y,v.z);
+}
+
+#endif 

+ 199 - 0
code/XGLLoader.h

@@ -0,0 +1,199 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, 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.
+
+----------------------------------------------------------------------
+*/
+
+/** @file XGLLoader.h
+ *  @brief Declaration of the .xgl/.zgl
+ */
+#ifndef AI_XGLLOADER_H_INCLUDED
+#define AI_XGLLOADER_H_INCLUDED
+
+#include "BaseImporter.h"
+#include "irrXMLWrapper.h"
+#include "LogAux.h"
+
+namespace Assimp	{
+
+// ---------------------------------------------------------------------------
+/** XGL/ZGL importer.
+ *
+ * Spec: http://vizstream.aveva.com/release/vsplatform/XGLSpec.htm
+ */
+class XGLImporter : public BaseImporter, public LogFunctions<XGLImporter>
+{
+public:
+
+	XGLImporter();
+	~XGLImporter();
+
+
+public:
+
+	// -------------------------------------------------------------------
+	/** Returns whether the class can handle the format of the given file. 
+	 *  See BaseImporter::CanRead() for details.	*/
+	bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
+		bool checkSig) const;
+
+protected:
+
+	// -------------------------------------------------------------------
+	/** Called by Importer::GetExtensionList() for each loaded importer.
+	 * See BaseImporter::GetExtensionList() for details  */
+	void GetExtensionList(std::set<std::string>& extensions);
+
+	// -------------------------------------------------------------------
+	/** Imports the given file into the given scene structure. 
+	 * See BaseImporter::InternReadFile() for details */
+	void InternReadFile( const std::string& pFile, aiScene* pScene, 
+		IOSystem* pIOHandler);
+
+private:
+
+	struct TempScope
+	{
+		TempScope()
+			: light()
+		{}
+
+		~TempScope()
+		{
+			BOOST_FOREACH(aiMesh* m, meshes_linear) {
+				delete m;
+			}
+
+			BOOST_FOREACH(aiMaterial* m, materials_linear) {
+				delete m;
+			}
+
+			delete light;
+		}
+
+		void dismiss() {
+			light = NULL;
+			meshes_linear.clear();
+			materials_linear.clear();
+			meshes.clear();
+			materials.clear();
+		}
+
+		std::multimap<unsigned int, aiMesh*> meshes;
+		std::map<unsigned int, aiMaterial*> materials;
+
+		std::vector<aiMesh*> meshes_linear;
+		std::vector<aiMaterial*> materials_linear;
+
+		aiLight* light;
+	};
+
+	struct TempMesh
+	{
+		std::map<unsigned int, aiVector3D> points;
+		std::map<unsigned int, aiVector3D> normals;
+		std::map<unsigned int, aiVector2D> uvs;
+	};
+
+	struct TempMaterialMesh
+	{
+		TempMaterialMesh()
+			: pflags()
+			, matid()
+		{}
+
+		std::vector<aiVector3D> positions, normals;
+		std::vector<aiVector2D> uvs;
+
+		std::vector<unsigned int> vcounts;
+		unsigned int pflags;
+		unsigned int matid;
+	};
+
+	struct TempFace
+	{
+		TempFace()
+			: has_uv()
+			, has_normal()
+		{}
+
+		aiVector3D pos;
+		aiVector3D normal;
+		aiVector2D uv;
+		bool has_uv;
+		bool has_normal;
+	};
+
+private:
+
+	void Cleanup();
+
+	std::string GetElementName();
+	bool ReadElement();
+	bool ReadElementUpToClosing(const char* closetag);
+	bool SkipToText();
+	unsigned int ReadIDAttr();
+
+	void ReadWorld(TempScope& scope);
+	void ReadLighting(TempScope& scope);
+	aiLight* ReadDirectionalLight();
+	aiNode* ReadObject(TempScope& scope,bool skipFirst = false,const char* closetag = "object");
+	bool ReadMesh(TempScope& scope);
+	void ReadMaterial(TempScope& scope);
+	aiVector2D ReadVec2();
+	aiVector3D ReadVec3();
+	aiColor3D ReadCol3();
+	aiMatrix4x4 ReadTrafo();
+	unsigned int ReadIndexFromText();
+	float ReadFloat();
+
+	aiMesh* ToOutputMesh(const TempMaterialMesh& m);
+	void ReadFaceVertex(const TempMesh& t, TempFace& out);
+	unsigned int ResolveMaterialRef(TempScope& scope);
+
+private:
+
+
+private:
+
+	irr::io::IrrXMLReader* reader;
+	aiScene* scene;
+};
+
+} // end of namespace Assimp
+
+#endif // AI_IRRMESHIMPORTER_H_INC

+ 12 - 0
workspaces/vc9/assimp.vcproj

@@ -2036,6 +2036,18 @@
 						>
 					</File>
 				</Filter>
+				<Filter
+					Name="xgl"
+					>
+					<File
+						RelativePath="..\..\code\XGLLoader.cpp"
+						>
+					</File>
+					<File
+						RelativePath="..\..\code\XGLLoader.h"
+						>
+					</File>
+				</Filter>
 			</Filter>
 			<Filter
 				Name="postprocessing"