vrshoot

diff libs/assimp/ACLoader.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/assimp/ACLoader.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,866 @@
     1.4 +
     1.5 +/*
     1.6 +---------------------------------------------------------------------------
     1.7 +Open Asset Import Library (assimp)
     1.8 +---------------------------------------------------------------------------
     1.9 +
    1.10 +Copyright (c) 2006-2012, assimp team
    1.11 +
    1.12 +All rights reserved.
    1.13 +
    1.14 +Redistribution and use of this software in source and binary forms, 
    1.15 +with or without modification, are permitted provided that the following 
    1.16 +conditions are met:
    1.17 +
    1.18 +* Redistributions of source code must retain the above
    1.19 +  copyright notice, this list of conditions and the
    1.20 +  following disclaimer.
    1.21 +
    1.22 +* Redistributions in binary form must reproduce the above
    1.23 +  copyright notice, this list of conditions and the
    1.24 +  following disclaimer in the documentation and/or other
    1.25 +  materials provided with the distribution.
    1.26 +
    1.27 +* Neither the name of the assimp team, nor the names of its
    1.28 +  contributors may be used to endorse or promote products
    1.29 +  derived from this software without specific prior
    1.30 +  written permission of the assimp team.
    1.31 +
    1.32 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    1.33 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    1.34 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.35 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    1.36 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.37 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    1.38 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.39 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    1.40 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    1.41 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    1.42 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.43 +---------------------------------------------------------------------------
    1.44 +*/
    1.45 +
    1.46 +/** @file Implementation of the AC3D importer class */
    1.47 +
    1.48 +#include "AssimpPCH.h"
    1.49 +
    1.50 +#ifndef ASSIMP_BUILD_NO_AC_IMPORTER
    1.51 +
    1.52 +// internal headers
    1.53 +#include "ACLoader.h"
    1.54 +#include "ParsingUtils.h"
    1.55 +#include "fast_atof.h"
    1.56 +#include "Subdivision.h"
    1.57 +
    1.58 +using namespace Assimp;
    1.59 +
    1.60 +static const aiImporterDesc desc = {
    1.61 +	"AC3D Importer",
    1.62 +	"",
    1.63 +	"",
    1.64 +	"",
    1.65 +	aiImporterFlags_SupportTextFlavour,
    1.66 +	0,
    1.67 +	0,
    1.68 +	0,
    1.69 +	0,
    1.70 +	"ac acc ac3d"
    1.71 +};
    1.72 +
    1.73 +// ------------------------------------------------------------------------------------------------
    1.74 +// skip to the next token
    1.75 +#define AI_AC_SKIP_TO_NEXT_TOKEN() \
    1.76 +	if (!SkipSpaces(&buffer)) \
    1.77 +	{ \
    1.78 +		DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
    1.79 +		continue; \
    1.80 +	} 
    1.81 +
    1.82 +// ------------------------------------------------------------------------------------------------
    1.83 +// read a string (may be enclosed in double quotation marks). buffer must point to "
    1.84 +#define AI_AC_GET_STRING(out) \
    1.85 +	++buffer; \
    1.86 +	const char* sz = buffer; \
    1.87 +	while ('\"' != *buffer) \
    1.88 +	{ \
    1.89 +		if (IsLineEnd( *buffer )) \
    1.90 +		{ \
    1.91 +			DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
    1.92 +			out = "ERROR"; \
    1.93 +			break; \
    1.94 +		} \
    1.95 +		++buffer; \
    1.96 +	} \
    1.97 +	if (IsLineEnd( *buffer ))continue; \
    1.98 +	out = std::string(sz,(unsigned int)(buffer-sz)); \
    1.99 +	++buffer;
   1.100 +
   1.101 +
   1.102 +// ------------------------------------------------------------------------------------------------
   1.103 +// read 1 to n floats prefixed with an optional predefined identifier 
   1.104 +#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
   1.105 +	AI_AC_SKIP_TO_NEXT_TOKEN(); \
   1.106 +	if (name_length) \
   1.107 +	{ \
   1.108 +		if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
   1.109 +		{ \
   1.110 +			DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
   1.111 +			continue; \
   1.112 +		} \
   1.113 +		buffer += name_length+1; \
   1.114 +	} \
   1.115 +	for (unsigned int i = 0; i < num;++i) \
   1.116 +	{ \
   1.117 +		AI_AC_SKIP_TO_NEXT_TOKEN(); \
   1.118 +		buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
   1.119 +	}
   1.120 +
   1.121 +
   1.122 +// ------------------------------------------------------------------------------------------------
   1.123 +// Constructor to be privately used by Importer
   1.124 +AC3DImporter::AC3DImporter()
   1.125 +{
   1.126 +	// nothing to be done here
   1.127 +}
   1.128 +
   1.129 +// ------------------------------------------------------------------------------------------------
   1.130 +// Destructor, private as well 
   1.131 +AC3DImporter::~AC3DImporter()
   1.132 +{
   1.133 +	// nothing to be done here
   1.134 +}
   1.135 +
   1.136 +// ------------------------------------------------------------------------------------------------
   1.137 +// Returns whether the class can handle the format of the given file. 
   1.138 +bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
   1.139 +{
   1.140 +	std::string extension = GetExtension(pFile);
   1.141 +
   1.142 +	// fixme: are acc and ac3d *really* used? Some sources say they are
   1.143 +	if(extension == "ac" || extension == "ac3d" || extension == "acc") {
   1.144 +		return true;
   1.145 +	}
   1.146 +	if (!extension.length() || checkSig) {
   1.147 +		uint32_t token = AI_MAKE_MAGIC("AC3D");
   1.148 +		return CheckMagicToken(pIOHandler,pFile,&token,1,0);
   1.149 +	}
   1.150 +	return false;
   1.151 +}
   1.152 +
   1.153 +// ------------------------------------------------------------------------------------------------
   1.154 +// Loader meta information
   1.155 +const aiImporterDesc* AC3DImporter::GetInfo () const
   1.156 +{
   1.157 +	return &desc;
   1.158 +}
   1.159 +
   1.160 +// ------------------------------------------------------------------------------------------------
   1.161 +// Get a pointer to the next line from the file
   1.162 +bool AC3DImporter::GetNextLine( )
   1.163 +{
   1.164 +	SkipLine(&buffer); 
   1.165 +	return SkipSpaces(&buffer);
   1.166 +}
   1.167 +
   1.168 +// ------------------------------------------------------------------------------------------------
   1.169 +// Parse an object section in an AC file
   1.170 +void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
   1.171 +{
   1.172 +	if (!TokenMatch(buffer,"OBJECT",6))
   1.173 +		return;
   1.174 +
   1.175 +	SkipSpaces(&buffer);
   1.176 +
   1.177 +	++mNumMeshes;
   1.178 +
   1.179 +	objects.push_back(Object());
   1.180 +	Object& obj = objects.back();
   1.181 +
   1.182 +	aiLight* light = NULL;
   1.183 +	if (!ASSIMP_strincmp(buffer,"light",5))
   1.184 +	{
   1.185 +		// This is a light source. Add it to the list
   1.186 +		mLights->push_back(light = new aiLight());
   1.187 +
   1.188 +		// Return a point light with no attenuation
   1.189 +		light->mType = aiLightSource_POINT;
   1.190 +		light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
   1.191 +		light->mAttenuationConstant = 1.f;
   1.192 +
   1.193 +		// Generate a default name for both the light source and the node
   1.194 +		// FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
   1.195 +		light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
   1.196 +		obj.name = std::string( light->mName.data );
   1.197 +
   1.198 +		DefaultLogger::get()->debug("AC3D: Light source encountered");
   1.199 +		obj.type = Object::Light;
   1.200 +	}
   1.201 +	else if (!ASSIMP_strincmp(buffer,"group",5))
   1.202 +	{
   1.203 +		obj.type = Object::Group;
   1.204 +	}
   1.205 +	else if (!ASSIMP_strincmp(buffer,"world",5))
   1.206 +	{
   1.207 +		obj.type = Object::World;
   1.208 +	}
   1.209 +	else obj.type = Object::Poly;
   1.210 +	while (GetNextLine())
   1.211 +	{
   1.212 +		if (TokenMatch(buffer,"kids",4))
   1.213 +		{
   1.214 +			SkipSpaces(&buffer);
   1.215 +			unsigned int num = strtoul10(buffer,&buffer);
   1.216 +			GetNextLine();
   1.217 +			if (num)
   1.218 +			{
   1.219 +				// load the children of this object recursively
   1.220 +				obj.children.reserve(num);
   1.221 +				for (unsigned int i = 0; i < num; ++i)
   1.222 +					LoadObjectSection(obj.children);
   1.223 +			}
   1.224 +			return;
   1.225 +		}
   1.226 +		else if (TokenMatch(buffer,"name",4))
   1.227 +		{
   1.228 +			SkipSpaces(&buffer);
   1.229 +			AI_AC_GET_STRING(obj.name);
   1.230 +
   1.231 +			// If this is a light source, we'll also need to store
   1.232 +			// the name of the node in it.
   1.233 +			if (light)
   1.234 +			{
   1.235 +				light->mName.Set(obj.name);
   1.236 +			}
   1.237 +		}
   1.238 +		else if (TokenMatch(buffer,"texture",7))
   1.239 +		{
   1.240 +			SkipSpaces(&buffer);
   1.241 +			AI_AC_GET_STRING(obj.texture);
   1.242 +		}
   1.243 +		else if (TokenMatch(buffer,"texrep",6))
   1.244 +		{
   1.245 +			SkipSpaces(&buffer);
   1.246 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
   1.247 +			if (!obj.texRepeat.x || !obj.texRepeat.y)
   1.248 +				obj.texRepeat = aiVector2D (1.f,1.f);
   1.249 +		}
   1.250 +		else if (TokenMatch(buffer,"texoff",6))
   1.251 +		{
   1.252 +			SkipSpaces(&buffer);
   1.253 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
   1.254 +		}
   1.255 +		else if (TokenMatch(buffer,"rot",3))
   1.256 +		{
   1.257 +			SkipSpaces(&buffer);
   1.258 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
   1.259 +		}
   1.260 +		else if (TokenMatch(buffer,"loc",3))
   1.261 +		{
   1.262 +			SkipSpaces(&buffer);
   1.263 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
   1.264 +		}
   1.265 +		else if (TokenMatch(buffer,"subdiv",6))
   1.266 +		{
   1.267 +			SkipSpaces(&buffer);
   1.268 +			obj.subDiv = strtoul10(buffer,&buffer);
   1.269 +		}
   1.270 +		else if (TokenMatch(buffer,"crease",6))
   1.271 +		{
   1.272 +			SkipSpaces(&buffer);
   1.273 +			obj.crease = fast_atof(buffer);
   1.274 +		}
   1.275 +		else if (TokenMatch(buffer,"numvert",7))
   1.276 +		{
   1.277 +			SkipSpaces(&buffer);
   1.278 +
   1.279 +			unsigned int t = strtoul10(buffer,&buffer);
   1.280 +			obj.vertices.reserve(t);
   1.281 +			for (unsigned int i = 0; i < t;++i)
   1.282 +			{
   1.283 +				if (!GetNextLine())
   1.284 +				{
   1.285 +					DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
   1.286 +					break;
   1.287 +				}
   1.288 +				else if (!IsNumeric(*buffer))
   1.289 +				{
   1.290 +					DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
   1.291 +					--buffer; // make sure the line is processed a second time
   1.292 +					break;
   1.293 +				}
   1.294 +				obj.vertices.push_back(aiVector3D());
   1.295 +				aiVector3D& v = obj.vertices.back();
   1.296 +				AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
   1.297 +			}
   1.298 +		}
   1.299 +		else if (TokenMatch(buffer,"numsurf",7))
   1.300 +		{
   1.301 +			SkipSpaces(&buffer);
   1.302 +			
   1.303 +			bool Q3DWorkAround = false;
   1.304 +
   1.305 +			const unsigned int t = strtoul10(buffer,&buffer);
   1.306 +			obj.surfaces.reserve(t);
   1.307 +			for (unsigned int i = 0; i < t;++i)
   1.308 +			{
   1.309 +				GetNextLine();
   1.310 +				if (!TokenMatch(buffer,"SURF",4))
   1.311 +				{
   1.312 +					// FIX: this can occur for some files - Quick 3D for 
   1.313 +					// example writes no surf chunks
   1.314 +					if (!Q3DWorkAround)
   1.315 +					{
   1.316 +						DefaultLogger::get()->warn("AC3D: SURF token was expected");
   1.317 +						DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
   1.318 +					}
   1.319 +					--buffer; // make sure the line is processed a second time
   1.320 +					// break; --- see fix notes above
   1.321 +
   1.322 +					Q3DWorkAround = true;
   1.323 +				}
   1.324 +				SkipSpaces(&buffer);
   1.325 +				obj.surfaces.push_back(Surface());
   1.326 +				Surface& surf = obj.surfaces.back();
   1.327 +				surf.flags = strtoul_cppstyle(buffer);
   1.328 +			
   1.329 +				while (1)
   1.330 +				{
   1.331 +					if(!GetNextLine())
   1.332 +					{
   1.333 +						DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
   1.334 +						break;
   1.335 +					}
   1.336 +					if (TokenMatch(buffer,"mat",3))
   1.337 +					{
   1.338 +						SkipSpaces(&buffer);
   1.339 +						surf.mat = strtoul10(buffer);
   1.340 +					}
   1.341 +					else if (TokenMatch(buffer,"refs",4))
   1.342 +					{
   1.343 +						// --- see fix notes above
   1.344 +						if (Q3DWorkAround)
   1.345 +						{
   1.346 +							if (!surf.entries.empty())
   1.347 +							{
   1.348 +								buffer -= 6;
   1.349 +								break;
   1.350 +							}
   1.351 +						}
   1.352 +
   1.353 +						SkipSpaces(&buffer);
   1.354 +						const unsigned int m = strtoul10(buffer);
   1.355 +						surf.entries.reserve(m);
   1.356 +
   1.357 +						obj.numRefs += m;
   1.358 +
   1.359 +						for (unsigned int k = 0; k < m; ++k)
   1.360 +						{
   1.361 +							if(!GetNextLine())
   1.362 +							{
   1.363 +								DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
   1.364 +								break;
   1.365 +							}
   1.366 +							surf.entries.push_back(Surface::SurfaceEntry());
   1.367 +							Surface::SurfaceEntry& entry = surf.entries.back();
   1.368 +
   1.369 +							entry.first = strtoul10(buffer,&buffer);
   1.370 +							SkipSpaces(&buffer);
   1.371 +							AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
   1.372 +						}
   1.373 +					}
   1.374 +					else 
   1.375 +					{
   1.376 +
   1.377 +						--buffer; // make sure the line is processed a second time
   1.378 +						break;
   1.379 +					}
   1.380 +				}
   1.381 +			}
   1.382 +		}
   1.383 +	}
   1.384 +	DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
   1.385 +}
   1.386 +
   1.387 +// ------------------------------------------------------------------------------------------------
   1.388 +// Convert a material from AC3DImporter::Material to aiMaterial
   1.389 +void AC3DImporter::ConvertMaterial(const Object& object,
   1.390 +	const Material& matSrc,
   1.391 +	aiMaterial& matDest)
   1.392 +{
   1.393 +	aiString s;
   1.394 +
   1.395 +	if (matSrc.name.length())
   1.396 +	{
   1.397 +		s.Set(matSrc.name);
   1.398 +		matDest.AddProperty(&s,AI_MATKEY_NAME);
   1.399 +	}
   1.400 +	if (object.texture.length())
   1.401 +	{
   1.402 +		s.Set(object.texture);
   1.403 +		matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
   1.404 +
   1.405 +		// UV transformation
   1.406 +		if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
   1.407 +			object.texOffset.x        || object.texOffset.y)
   1.408 +		{
   1.409 +			aiUVTransform transform;
   1.410 +			transform.mScaling = object.texRepeat;
   1.411 +			transform.mTranslation = object.texOffset;
   1.412 +			matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
   1.413 +		}
   1.414 +	}
   1.415 +
   1.416 +	matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
   1.417 +	matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
   1.418 +	matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
   1.419 +	matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
   1.420 +
   1.421 +	int n;
   1.422 +	if (matSrc.shin)
   1.423 +	{
   1.424 +		n = aiShadingMode_Phong;
   1.425 +		matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
   1.426 +	}
   1.427 +	else n = aiShadingMode_Gouraud;
   1.428 +	matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
   1.429 +
   1.430 +	float f = 1.f - matSrc.trans;
   1.431 +	matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
   1.432 +}
   1.433 +
   1.434 +// ------------------------------------------------------------------------------------------------
   1.435 +// Converts the loaded data to the internal verbose representation
   1.436 +aiNode* AC3DImporter::ConvertObjectSection(Object& object,
   1.437 +	std::vector<aiMesh*>& meshes,
   1.438 +	std::vector<aiMaterial*>& outMaterials,
   1.439 +	const std::vector<Material>& materials,
   1.440 +	aiNode* parent)
   1.441 +{
   1.442 +	aiNode* node = new aiNode();
   1.443 +	node->mParent = parent;
   1.444 +	if (object.vertices.size())
   1.445 +	{
   1.446 +		if (!object.surfaces.size() || !object.numRefs)
   1.447 +		{
   1.448 +			/* " An object with 7 vertices (no surfaces, no materials defined). 
   1.449 +			     This is a good way of getting point data into AC3D. 
   1.450 +			     The Vertex->create convex-surface/object can be used on these
   1.451 +			     vertices to 'wrap' a 3d shape around them "
   1.452 +				 (http://www.opencity.info/html/ac3dfileformat.html)
   1.453 +
   1.454 +				 therefore: if no surfaces are defined return point data only
   1.455 +			 */
   1.456 +
   1.457 +			DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
   1.458 +				"a point list is returned");
   1.459 +
   1.460 +			meshes.push_back(new aiMesh());
   1.461 +			aiMesh* mesh = meshes.back();
   1.462 +
   1.463 +			mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
   1.464 +			aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
   1.465 +			aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
   1.466 +
   1.467 +			for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
   1.468 +			{
   1.469 +				*verts = object.vertices[i];
   1.470 +				faces->mNumIndices = 1;
   1.471 +				faces->mIndices = new unsigned int[1];
   1.472 +				faces->mIndices[0] = i;
   1.473 +			}
   1.474 +
   1.475 +			// use the primary material in this case. this should be the
   1.476 +			// default material if all objects of the file contain points
   1.477 +			// and no faces.
   1.478 +			mesh->mMaterialIndex = 0;
   1.479 +			outMaterials.push_back(new aiMaterial());
   1.480 +			ConvertMaterial(object, materials[0], *outMaterials.back());
   1.481 +		}
   1.482 +		else
   1.483 +		{
   1.484 +			// need to generate one or more meshes for this object.
   1.485 +			// find out how many different materials we have
   1.486 +			typedef std::pair< unsigned int, unsigned int > IntPair;
   1.487 +			typedef std::vector< IntPair > MatTable;
   1.488 +			MatTable needMat(materials.size(),IntPair(0,0));
   1.489 +
   1.490 +			std::vector<Surface>::iterator it,end = object.surfaces.end();
   1.491 +			std::vector<Surface::SurfaceEntry>::iterator it2,end2;
   1.492 +
   1.493 +			for (it = object.surfaces.begin(); it != end; ++it)
   1.494 +			{
   1.495 +				register unsigned int idx = (*it).mat;
   1.496 +				if (idx >= needMat.size())
   1.497 +				{
   1.498 +					DefaultLogger::get()->error("AC3D: material index is out of range");
   1.499 +					idx = 0;
   1.500 +				}
   1.501 +				if ((*it).entries.empty())
   1.502 +				{
   1.503 +					DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
   1.504 +				}
   1.505 +
   1.506 +				// validate all vertex indices to make sure we won't crash here
   1.507 +				for (it2  = (*it).entries.begin(),
   1.508 +					 end2 = (*it).entries.end(); it2 != end2; ++it2)
   1.509 +				{
   1.510 +					if ((*it2).first >= object.vertices.size())
   1.511 +					{
   1.512 +						DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
   1.513 +						(*it2).first = 0;
   1.514 +					}
   1.515 +				}
   1.516 +
   1.517 +				if (!needMat[idx].first)++node->mNumMeshes;
   1.518 +
   1.519 +				switch ((*it).flags & 0xf)
   1.520 +				{
   1.521 +					// closed line
   1.522 +				case 0x1:
   1.523 +
   1.524 +					needMat[idx].first  += (unsigned int)(*it).entries.size();
   1.525 +					needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
   1.526 +					break;
   1.527 +
   1.528 +					// unclosed line
   1.529 +				case 0x2:
   1.530 +
   1.531 +					needMat[idx].first  += (unsigned int)(*it).entries.size()-1;
   1.532 +					needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
   1.533 +					break;
   1.534 +
   1.535 +					// 0 == polygon, else unknown
   1.536 +				default:
   1.537 +
   1.538 +					if ((*it).flags & 0xf)
   1.539 +					{
   1.540 +						DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
   1.541 +						(*it).flags &= ~(0xf);
   1.542 +					}
   1.543 +
   1.544 +					// the number of faces increments by one, the number
   1.545 +					// of vertices by surface.numref.
   1.546 +					needMat[idx].first++;
   1.547 +					needMat[idx].second += (unsigned int)(*it).entries.size();
   1.548 +				};
   1.549 +			}
   1.550 +			unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
   1.551 +			unsigned int mat = 0;
   1.552 +			const size_t oldm = meshes.size();
   1.553 +			for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
   1.554 +				cit != cend; ++cit, ++mat)
   1.555 +			{
   1.556 +				if (!(*cit).first)continue;
   1.557 +
   1.558 +				// allocate a new aiMesh object
   1.559 +				*pip++ = (unsigned int)meshes.size();
   1.560 +				aiMesh* mesh = new aiMesh();
   1.561 +				meshes.push_back(mesh);
   1.562 +
   1.563 +				mesh->mMaterialIndex = (unsigned int)outMaterials.size();
   1.564 +				outMaterials.push_back(new aiMaterial());
   1.565 +				ConvertMaterial(object, materials[mat], *outMaterials.back());
   1.566 +
   1.567 +				// allocate storage for vertices and normals
   1.568 +				mesh->mNumFaces = (*cit).first;
   1.569 +				aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
   1.570 +
   1.571 +				mesh->mNumVertices = (*cit).second;
   1.572 +				aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
   1.573 +				unsigned int cur = 0;
   1.574 +
   1.575 +				// allocate UV coordinates, but only if the texture name for the
   1.576 +				// surface is not empty
   1.577 +				aiVector3D* uv = NULL;
   1.578 +				if(object.texture.length())
   1.579 +				{
   1.580 +					uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
   1.581 +					mesh->mNumUVComponents[0] = 2;
   1.582 +				}
   1.583 +
   1.584 +				for (it = object.surfaces.begin(); it != end; ++it)
   1.585 +				{
   1.586 +					if (mat == (*it).mat)
   1.587 +					{
   1.588 +						const Surface& src = *it;
   1.589 +
   1.590 +						// closed polygon
   1.591 +						unsigned int type = (*it).flags & 0xf; 
   1.592 +						if (!type)
   1.593 +						{
   1.594 +							aiFace& face = *faces++;
   1.595 +							if((face.mNumIndices = (unsigned int)src.entries.size()))
   1.596 +							{
   1.597 +								face.mIndices = new unsigned int[face.mNumIndices];
   1.598 +								for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
   1.599 +								{
   1.600 +									const Surface::SurfaceEntry& entry = src.entries[i];
   1.601 +									face.mIndices[i] = cur++;
   1.602 +
   1.603 +									// copy vertex positions
   1.604 +									*vertices = object.vertices[entry.first] + object.translation;
   1.605 +
   1.606 +
   1.607 +									// copy texture coordinates 
   1.608 +									if (uv)
   1.609 +									{
   1.610 +										uv->x =  entry.second.x;
   1.611 +										uv->y =  entry.second.y;
   1.612 +										++uv;
   1.613 +									}
   1.614 +								}
   1.615 +							}
   1.616 +						}
   1.617 +						else
   1.618 +						{
   1.619 +							
   1.620 +							it2  = (*it).entries.begin();
   1.621 +
   1.622 +							// either a closed or an unclosed line
   1.623 +							register unsigned int tmp = (unsigned int)(*it).entries.size();
   1.624 +							if (0x2 == type)--tmp;
   1.625 +							for (unsigned int m = 0; m < tmp;++m)
   1.626 +							{
   1.627 +								aiFace& face = *faces++;
   1.628 +
   1.629 +								face.mNumIndices = 2;
   1.630 +								face.mIndices = new unsigned int[2];
   1.631 +								face.mIndices[0] = cur++;
   1.632 +								face.mIndices[1] = cur++;
   1.633 +
   1.634 +								// copy vertex positions
   1.635 +								*vertices++ = object.vertices[(*it2).first];
   1.636 +								
   1.637 +								// copy texture coordinates 
   1.638 +								if (uv)
   1.639 +								{
   1.640 +									uv->x =  (*it2).second.x;
   1.641 +									uv->y =  (*it2).second.y;
   1.642 +									++uv;
   1.643 +								}
   1.644 +
   1.645 +
   1.646 +								if (0x1 == type && tmp-1 == m)
   1.647 +								{
   1.648 +									// if this is a closed line repeat its beginning now
   1.649 +									it2  = (*it).entries.begin();
   1.650 +								}
   1.651 +								else ++it2;
   1.652 +
   1.653 +								// second point
   1.654 +								*vertices++ = object.vertices[(*it2).first];
   1.655 +
   1.656 +								if (uv)
   1.657 +								{
   1.658 +									uv->x =  (*it2).second.x;
   1.659 +									uv->y =  (*it2).second.y;
   1.660 +									++uv;
   1.661 +								}
   1.662 +							}
   1.663 +						}
   1.664 +					}
   1.665 +				}
   1.666 +			}
   1.667 +
   1.668 +			// Now apply catmull clark subdivision if necessary. We split meshes into
   1.669 +			// materials which is not done by AC3D during smoothing, so we need to
   1.670 +			// collect all meshes using the same material group.
   1.671 +			if (object.subDiv)	{
   1.672 +				if (configEvalSubdivision) {
   1.673 +					boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
   1.674 +					DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
   1.675 +
   1.676 +					std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
   1.677 +					div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
   1.678 +					std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
   1.679 +
   1.680 +					// previous meshes are deleted vy Subdivide().
   1.681 +				}
   1.682 +				else {
   1.683 +					DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
   1.684 +						+object.name);
   1.685 +				}
   1.686 +			}
   1.687 +		}
   1.688 +	}
   1.689 +
   1.690 +	if (object.name.length())
   1.691 +		node->mName.Set(object.name);
   1.692 +	else
   1.693 +	{
   1.694 +		// generate a name depending on the type of the node
   1.695 +		switch (object.type)
   1.696 +		{
   1.697 +		case Object::Group:
   1.698 +			node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
   1.699 +			break;
   1.700 +		case Object::Poly:
   1.701 +			node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
   1.702 +			break;
   1.703 +		case Object::Light:
   1.704 +			node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
   1.705 +			break;
   1.706 +
   1.707 +			// there shouldn't be more than one world, but we don't care
   1.708 +		case Object::World: 
   1.709 +			node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
   1.710 +			break;
   1.711 +		}
   1.712 +	}
   1.713 +
   1.714 +
   1.715 +	// setup the local transformation matrix of the object
   1.716 +	// compute the transformation offset to the parent node
   1.717 +	node->mTransformation = aiMatrix4x4 ( object.rotation );
   1.718 +
   1.719 +	if (object.type == Object::Group || !object.numRefs)
   1.720 +	{
   1.721 +		node->mTransformation.a4 = object.translation.x;
   1.722 +		node->mTransformation.b4 = object.translation.y;
   1.723 +		node->mTransformation.c4 = object.translation.z;
   1.724 +	}
   1.725 +
   1.726 +	// add children to the object
   1.727 +	if (object.children.size())
   1.728 +	{
   1.729 +		node->mNumChildren = (unsigned int)object.children.size();
   1.730 +		node->mChildren = new aiNode*[node->mNumChildren];
   1.731 +		for (unsigned int i = 0; i < node->mNumChildren;++i)
   1.732 +		{
   1.733 +			node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
   1.734 +		}
   1.735 +	}
   1.736 +
   1.737 +	return node;
   1.738 +}
   1.739 +
   1.740 +// ------------------------------------------------------------------------------------------------
   1.741 +void AC3DImporter::SetupProperties(const Importer* pImp)
   1.742 +{
   1.743 +	configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
   1.744 +	configEvalSubdivision =  pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
   1.745 +}
   1.746 +
   1.747 +// ------------------------------------------------------------------------------------------------
   1.748 +// Imports the given file into the given scene structure. 
   1.749 +void AC3DImporter::InternReadFile( const std::string& pFile, 
   1.750 +	aiScene* pScene, IOSystem* pIOHandler)
   1.751 +{
   1.752 +	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
   1.753 +
   1.754 +	// Check whether we can read from the file
   1.755 +	if( file.get() == NULL)
   1.756 +		throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
   1.757 +
   1.758 +	// allocate storage and copy the contents of the file to a memory buffer
   1.759 +	std::vector<char> mBuffer2;
   1.760 +	TextFileToBuffer(file.get(),mBuffer2);
   1.761 +
   1.762 +	buffer = &mBuffer2[0];
   1.763 +	mNumMeshes = 0;
   1.764 +
   1.765 +	lights = polys = worlds = groups = 0;
   1.766 +
   1.767 +	if (::strncmp(buffer,"AC3D",4)) {
   1.768 +		throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
   1.769 +	}
   1.770 +
   1.771 +	// print the file format version to the console
   1.772 +	unsigned int version = HexDigitToDecimal( buffer[4] );
   1.773 +	char msg[3];
   1.774 +	ASSIMP_itoa10(msg,3,version);
   1.775 +	DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
   1.776 +
   1.777 +	std::vector<Material> materials;
   1.778 +	materials.reserve(5);
   1.779 +
   1.780 +	std::vector<Object> rootObjects;
   1.781 +	rootObjects.reserve(5);
   1.782 +
   1.783 +	std::vector<aiLight*> lights;
   1.784 +	mLights = & lights;
   1.785 +
   1.786 +	while (GetNextLine())
   1.787 +	{
   1.788 +		if (TokenMatch(buffer,"MATERIAL",8))
   1.789 +		{
   1.790 +			materials.push_back(Material());
   1.791 +			Material& mat = materials.back();
   1.792 +
   1.793 +			// manually parse the material ... sscanf would use the buldin atof ...
   1.794 +			// Format: (name) rgb %f %f %f  amb %f %f %f  emis %f %f %f  spec %f %f %f  shi %d  trans %f
   1.795 +
   1.796 +			AI_AC_SKIP_TO_NEXT_TOKEN();
   1.797 +			if ('\"' == *buffer)
   1.798 +			{
   1.799 +				AI_AC_GET_STRING(mat.name);
   1.800 +				AI_AC_SKIP_TO_NEXT_TOKEN();
   1.801 +			}
   1.802 +
   1.803 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
   1.804 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
   1.805 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
   1.806 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
   1.807 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
   1.808 +			AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
   1.809 +		}
   1.810 +		LoadObjectSection(rootObjects);
   1.811 +	}
   1.812 +
   1.813 +	if (rootObjects.empty() || !mNumMeshes)
   1.814 +	{
   1.815 +		throw DeadlyImportError("AC3D: No meshes have been loaded");
   1.816 +	}
   1.817 +	if (materials.empty())
   1.818 +	{
   1.819 +		DefaultLogger::get()->warn("AC3D: No material has been found");
   1.820 +		materials.push_back(Material());
   1.821 +	}
   1.822 +
   1.823 +	mNumMeshes += (mNumMeshes>>2u) + 1;
   1.824 +	std::vector<aiMesh*> meshes;
   1.825 +	meshes.reserve(mNumMeshes);
   1.826 +
   1.827 +	std::vector<aiMaterial*> omaterials;
   1.828 +	materials.reserve(mNumMeshes);
   1.829 +
   1.830 +	// generate a dummy root if there are multiple objects on the top layer
   1.831 +	Object* root;
   1.832 +	if (1 == rootObjects.size())
   1.833 +		root = &rootObjects[0];
   1.834 +	else
   1.835 +	{
   1.836 +		root = new Object();
   1.837 +	}
   1.838 +
   1.839 +	// now convert the imported stuff to our output data structure
   1.840 +	pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
   1.841 +	if (1 != rootObjects.size())delete root;
   1.842 +
   1.843 +	if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
   1.844 +		pScene->mRootNode->mName.Set("<AC3DWorld>");
   1.845 +
   1.846 +	// copy meshes
   1.847 +	if (meshes.empty())
   1.848 +	{
   1.849 +		throw DeadlyImportError("An unknown error occured during converting");
   1.850 +	}
   1.851 +	pScene->mNumMeshes = (unsigned int)meshes.size();
   1.852 +	pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
   1.853 +	::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
   1.854 +
   1.855 +	// copy materials
   1.856 +	pScene->mNumMaterials = (unsigned int)omaterials.size();
   1.857 +	pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
   1.858 +	::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
   1.859 +
   1.860 +	// copy lights
   1.861 +	pScene->mNumLights = (unsigned int)lights.size();
   1.862 +	if (lights.size())
   1.863 +	{
   1.864 +		pScene->mLights = new aiLight*[lights.size()];
   1.865 +		::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
   1.866 +	}
   1.867 +}
   1.868 +
   1.869 +#endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER